내 세상

[C++] 함수 본문

Language/C/C++

[C++] 함수

sga8 2020. 1. 2. 19:44
728x90
반응형

함수 호출 시 디폴트 파라미터 사용 주의 사항

#include <iostream>

// 디폴트 파라미터 : 인자를 전달하지 않으면 디폴트 값 사용

// 주의 사항 2가지
//   1. 함수를 선언과 구현으로 분리시에 디폴트 값은
//	  	선언 에만 표기해야 한다.
//   2. 마지막 인자 부터 차례대로만 지정해야 한다.

void goo(int a = 0, int b = 0, int c = 0) {} // ok
void goo(int a, int b = 0, int c = 0) {}     // ok
void goo(int a = 0, int b    , int c = 0) {} // error
void goo(int a = 0, int b = 0, int c) {}     // error,  default는 오른쪽 끝부터 진행할 수 있음.

goo(1); // 이렇게 위에서 3번째 goo를 호출 했을 때 어느 값에 대입하는 것인지 알수 없기 때문에 에러임.


void foo(int a, int b = 0, int c = 0); // 함수에 대한 선언만.
int main()
{
	foo(1, 2, 3);
	foo(1, 2); // 1,2,0
	foo(1); // 1, 0, 0

}

void foo(int a, int b = 0, int c = 0) { // error. default 값을 바꾸려고 시도 한다고 판단하기 때문에;
										// 다르게, 위에 b=0, c=0이 없으면 컴파일 에러가 난다. 
										// 호출 할때는 위에 부분을 호출하기 때문에.

}

// void foo(int a, int b /* = 0*/, int c /* = 0 */); 과 같은 형태로 사용하기도 함,

 

inline 함수 장/단점

  - inline 함수를 사용하면 소스의 해당 부분을 기계어 코드로 치환하는 것을 의미한다.

// 인라인 함수
// 장점 : 빨라진다
// 단점 : 코드가 커질수도 있다(여러줄 함수를 여러번 치환할 경우)
//		  디버깅이 어려워진다.
       int Add1(int a, int b) { return a + b; }
inline int Add2(int a, int b) { return a + b; }

int main()
{

	int n1 = Add1(1, 2); // Add1으로 이동했다가 다시 돌아오는 것
			   // Push 2, Push 1, call Add1
	int n2 = Add2(1, 2); // Add2로 점프하는 것이 아니라, Add2의 기계어 코드로 해당 소스를 치환하는 것을 의미함.

	
}

 

함수 오버로딩, 매크로의 문제점

#include <iostream>

// 인자의 개수나 타입이 다르면 "동일한 이름의 함수를 2개이상" 만들 수 있다
/*
int square(int a) {
	return a * a;
}
double square(double a) {
	return a * a;
}

int main()
{
	int n = square(3);
	double d = square(3.4);
}
*/


// 매크로를 사용하면 타입에 독립적인 sqaure를 만들수 있지만!!
// 버그가 너무 많다. ++n 등의 표기법이 있으면 항상 버그
#define square(x) (x)*(x)

int main()
{
	int n = 3;
	int s = square(++n); // (++n)*(++n);
	        // 4가 리턴 되나, 4로 바뀐 n이 리턴 되나?
			// ++의 return value는 값이 아닌 주소이다.
            // 그렇기 때문에, ++ 연산 2번을 거친 후 n의 주소를 리턴해줌.
            // (n')*(n') = (5)*(5) = 25			

	std::cout << s << std::endl;
} 

 

함수 template

#include <cstdio>

// 함수의 인자와 반환 타입만 다르고 구현부가 동일한 경우
// "함수"를 만들지 말고 "함수를 만드는 틀"을 만들자.

// "square"는  함수가 아닌 "함수를 만드는 틀(template)" 입니다
template<typename T>
T square(T n) {
	return n * n;
}

int main()
{
	square<int>(3);  // 이 코드를 보고 컴파일러가 
					// int square(int) 함수 생성
	square<double>(3.4); // double square(double) 함수 생성

	// 타입을 명시적으로 전달하지 않으면
	// 컴파일러가 인자를 보고 추론해줍니다.
	square(3); // 3을 보고 square<int>(3) 으로 변경
	square(3.4); // 3.4를 보고 square<double>(3.4) 으로 변경

	printf("%p\n", &square); // error. square는 함수가 아니라
							// 함수를 찍어내는 틀입니다.
							// 컴파일 시간에 컴파일러가 사용할 뿐..
							// 메모리에 놓이는 것이 아닙니다.

	printf("%p\n", &square<int>);

	// int n = std::min(1, 10); // 함수 템플릿입니다 !!


	// 템플릿 단점 : Code Bloat(코드 폭발)
	// 너무 많은 함수(클래스)가 생성되어서 코드 메모리가 증가되는 현상
	int n1 = 10;
	short s1 = 10;
	square(n1); // int 버전
	square(s1); // short 버전
}

 

C++11에서의 suffix return type, lambda expression

// C++11에서 나온 새로운 모양 : 후위 반환 타입(suffix return type)
auto square(int a) -> int
{
	return a * a;
}

int main()
{
	square(3);
}


/////////////////////////////////////////////////////////////////////////////

int Add(int a, int b) { return a + b; }

void foo(int(*f)(int, int))
{
	f(1, 2);
}

int main()
{
	foo(Add);

	// 람다 표현식 (lambda expression)
	// 함수 이름이 필요한 자리에 함수 구현 자체를 사용하는 것
	// [] : lambda introducer
	//		람다표현식이 시작됨을 알리는 기호
	foo([](int a, int b) { return a + b; });

	Add(1, 2);

	int n = [](int a, int b) {return a + b; }(1, 2);

	//pthread_create(0, 0, [](void*p) {스레드로 수행할일; }, 스레드인자);
}

 

 

C와 C++ 함수 문법

  - C++98 : inline 함수, 디폴트 파라미터, 함수 오버로딩, 함수 템플릿

  - C++11 : 후위 반환 타입, 함수 삭제, 람다 표현식

728x90
반응형