2015. 2. 1.

[C++]함수 오버로딩(Function Overloading)과 매크로 함수(Macro Function), 템플릿 함수(Template Function)

C에서의 함수 오버로딩?

 C에서는 함수 오버로딩이 불가능하다. 왜냐하면 C에서는 함수를 함수의 이름, 즉 함수 포인터로 구분하기 때문이다. 하지만 C++에서는 C에서와는 달리 함수의 이름과 전달되는 인자를 통해 함수를 구분한다. 그래서 함수 오버로딩이 가능하다. 아래의 코드를 보자.


 위 코드는 함수 오버로딩의 예시를 보여주는 코드이다. MyFunc() 함수는 매개변수에 따라 둘로 구분할 수 있다. 그리고 둘로 구분된 함수를 int 하나, int 둘의 경우 각각 호출을 한다. 그래서 MyFunc(20)의 경우 매개변수가 하나인 MyFunc()이 호출되고, MyFunc(30, 40)의 경우 매개변수가 둘인 MyFunc()이 호출된다. 이렇게 함수 구분이 가능한 이유는 C++은 함수의 이름(결국 함수 포인터)과 함께 함수의 매개변수를 통해 호출할 함수를 구분하기 때문이다. 앞에서 설명한 것처럼 C에서 함수 오버로딩을 실행하면 어떻게 되겠는가? MyFunc(20)을 보는 순간 컴파일러는 '어쩌지? MyFunc() 함수가 2개인데 무얼 호출해야 할지 모르겠네.'라고 고민에 빠질 것이다.
 위의 코드는 return 자료형으로 함수 오버로딩 시도하고 있다. 이 경우 return value type만으로는 오버로딩된 함수를 구별할 수 없다는 에러 메세지를 확일할 수 있다.


오버로딩 함수 디폴트 값 설정
 아무런 매개변수가 전달되지 않으면 default value를 적용해서 오버로딩 함수를 호출한다. 매개변수가 전달되면 매개변수를 적용하여 오버로딩 함수를 호출한다.

 오버로딩 함수의 디폴트 값은 오른쪽 변수부터 정한다. 왜 오른쪽 변수부터 정하겠는가? 매개변수가 전달되면 왼쪽부터 채우기 때문이다.


매개변수를 제곱하는 Square() 함수를 만들자. 
먼저 int 자료형에 대한 Square() 함수를 만들었다. float 자료형에 대한 Square() 함수도 필요하다. 함수 오버로딩을 이용해서 만들어 보자.  float 자료형에 대한 Square() 함수를 만들었다. 그런데 return value type이 바뀌었다. 이는 잘못된 오버로딩 방법이다. 그래서 return value type을 int로 수정하자.
 의도한 대로 함수가 오버로딩되었다. 하지만 이 경우 float 자료형이 int 자료형으로 묵시적인 형 변환이 이루어져서 정확한 결과를 얻을 수 없다. 그러면 int 자료형을 위한 함수, float 자료형을 위한 함수를 완전히 별개의 함수로 만들 수 밖에 없는가?


매크로 함수(Macro Function)
 매크로 함수는 일반 함수와는 다르게 전처리 단계에서 코드가 직접 삽입된다. 코드에 SQUARE(7)과 같이 SQUARE() 함수를 사용한 부분은 전처리기에 의해 ((7) * (7))로 변경되어야 한다. 컴파일러가 처리하기 전에 이미 변경된다.

 방금 우리가 한 고민을 다시 떠올려 보자. int, float, double 등의 자료형에 맞는 Square() 함수를 함수 오버로딩으로 구현하고자 했다. 하지만 이는 return value를 변경할 수 없는 문제에 막히고 말았다. 매크로 함수를 보니 이 문제를 해결할 수 있을 것 같다는 생각이 든다. 그렇다면 매크로 함수는 단점이 없는가?


매크로 함수의 단점

 매크로 함수는 복잡한 함수를 만들기에 적합하지 않다. 만약 함수 내부에 if문이 있고, for문이 있다고 생각해보라. 이를 매크로 함수로 바꿀 수 있겠는가? 어려운 일이다. 할 수 있다고 해도 안하는 것이 좋을 것이다.

 그리고 매크로 함수는 일반 함수처럼 디버깅하기 힘들다는 단점이 있다. 전처리 단계에서 삽입된 매크로 함수는 디버거를 활용한 디버깅을 할 수 없다.

 마지막 문제점은 괄호에 관한 점이다. 먼저 코드를 보자.
 ret 값은 얼마인가? 4인가? 그렇다면 매크로 함수의 마지막 단점에 걸려들었다. 4라고 생각한 이유는 (1+1) * (1+1)은 2*2가 되므로 4라고 생각했을 것이다. 하지만 매크로 함수는 정의한 그대로 적용된다. (1 + 1 * 1 + 1)로 적용된다. 결국 3이 된다. 이런 문제를 예방하기 위해서 매크로 함수의 변수는 ()로 감싸야 한다.


 이런 단점들때문에 매크로 함수는 제한적으로 사용할 수 밖에 없다.

 그렇다면 완전한 해결책은 없나?


템플릿 함수!

 템플릿은 자료형에 종속적이지 않는 자료를 선언할 때 사용된다. 매크로 함수에서 X와 같이 자료형에 제한받지 않는 자료형을 template을 사용하면 선언할 수 있다. 이런 template를 활용하여 자료형에 종속적이지 않는 방식으로 프로그래밍하는 방법인 generic programming이라고 한다.

 먼저 템플릿을 적용한 함수를 살펴보자.
 typename T가 template으로 선언되었다. 이제 T는 어떤 자료형이든 상관없이 담을 수 있다. return 값도 T에 의해 알아서 적용된다. return value 앞에 inline이라는 명령어가 선언되어 있다. 이는 템플릿 함수를 매크로 함수처럼 프로그램 코드 내부로 적용하라는 키워드이다. 이는 매크로 함수와는 다르게 전처리 단계가 아니라 컴파일 단계에서 이뤄진다. 그리고 inline으로 선언하였더라고 컴파일러에 의해 거부될 수가 있다. 컴파일러가 판단하기에 inline 선언에 의해 최적화가 이뤄지면 프로그램 코드 내부에 치환하지만, 반대의 경우에는 inline하지 않을 수도 있다. 판단은 컴파일러님이 하신다.

 여튼 template을 통해 매크로 함수의 단점을 해결한 일반 함수를 만들 수 있다.

댓글 없음:

댓글 쓰기