
함수 오버로딩(Function Overloading)
C언어에서는 동일한 이름의 함수가 존재하면 컴파일 오류가 발생한다.
int main(void)
{
MyFunc(20); // MyFunc(int a) 호출
MyFunc(30, 40); // MyFunc(int b, int c) 호출
return 0;
}
함수 호출 시 전달되는 인자를 통해서 이름이 같아도 함수의 구분이 가능하기 때문에, 매개변수 선언 형태가 다르다면 동일한 이름의 함수 정의를 허용한다. 이를 함수 오버로딩이라고 한다.
C++에서는 함수를 찾을 때 함수의 이름과 매개변수 정보를 동시에 활용한다. 따라서 MyFunc(30, 40)의 경우, 두 개의 int형 매개변수를 받는 MyFunc이라는 함수를 찾아간다.
반면 C언어는 함수의 이름만을 이용하여 함수를 찾는다. 따라서 MyFunc(30, 40)의 경우, MyFunc라는 이름의 함수를 찾아간다. 결과적으로 C언어에서는 함수의 오버로딩이 불가능하고, 문법적으로 허용하지 않는다.
오버로딩은 자료형 또는 개수가 달라야 한다. 다음은 오버로딩의 예이다.
매개변수의 자료형이 다른 경우
int MyFunc(double a) { }
int MyFunc(int b) { }
매개변수의 개수가 다른 경우
int MyFunc(int a) { }
int MyFunc(int a, int b) { }
매개변수의 순서가 다른 경우
int MyFunc(int a, double b) { }
int MyFunc(double a, int b) { }
다음은 오버로딩이 아니다. 반환형(맨 앞의 int, void...)은 함수 호출과는 관계가 없으며, 매개변수의 이름 또한 마찬가지이다.
int MyFunc(int a) { }
void MyFunc(int b) { }
int MyFunc(int a, int b) { }
int MyFunc(int c, int d) { }
함수 오버로딩의 예제이다. 서로 다른 두 매개변수의 순서를 바꾼 함수를 추가하였다.
#include <iostream>
void MyFunc(void)
{
std::cout << "MyFunc(void) called" << std::endl;
}
void MyFunc(char c)
{
std::cout << "MyFunc(char c) called" << std::endl;
}
void MyFunc(int a, double b)
{
std::cout << "MyFunc(int a, double b) called" << std::endl;
}
void MyFunc(double a, int b)
{
std::cout << "MyFunc(double a, int b) called" << std::endl;
}
int main(void)
{
MyFunc();
MyFunc('A');
MyFunc(1, 1.1);
MyFunc(1.1, 1);
return 0;
}
매개변수의 디폴트 값(Default Value)
C++의 함수에서는 기본적으로 설정되어 있는 '디폴트 값'을 설정할 수 있다. 함수 호출 시 인자를 전달하지 않으면 해당 디폴트 값을 받은 것으로 간주하여 호출된다. 다음의 예제를 보자.
int MyFuncOne(int num = 7) { }
int MyFuncTwo(int num1 = 5, int num2 = 7) { }
만약 매개변수를 주지 않고, MyFuncOne();의 형태로 함수를 호출한다면, MyFuncOne(7);과 같이 매개변수 7이 전달된 것으로 간주한다는 것이다.
#include <iostream>
int Adder(int num1 = 1, int num2 = 2)
{
return num1 + num2;
}
int main(void)
{
std::cout << Adder() << std::endl;
std::cout << Adder(5) << std::endl;
std::cout << Adder(3, 5) << std::endl;
return 0;
}
Adder(5)의 경우, num1로 5를 넘기고 num2에는 아무런 값을 넘기지 않았기 때문에 디폴트 값인 2가 들어가게 된다. 따라서 함수 Adder는 7을 반환한다.
함수의 원형을 별도로 선언해야 하는 경우, 디폴트 값은 함수의 선언 부분에만 적어야 한다.
#include <iostream>
int Adder(int num1 = 1, int num2 = 2);
int main(void)
{
std::cout << Adder() << std::endl;
std::cout << Adder(5) << std::endl;
std::cout << Adder(3, 5) << std::endl;
return 0;
}
int Adder(int num1, int num2)
{
return num1 + num2;
}
부분적 디폴트 값 설정
상단에서도 다뤘지만, 디폴트 값을 전부 지정할 수 있다.
int MyFunc(int num1 = 3, int num2 = 4, int num3 = 5) { }
또한, 일부분만 디폴트 값을 지정할 수도 있다.
int MyFunc(int num1, int num2 = 4, int num3 = 5) { }
이 경우, 다음처럼 함수 호출이 가능해진다.
MyFunc(10); // MyFunc(10, 4, 5);
MyFunc(10, 20); // MyFunc(10, 20, 5);
그러나 오른쪽 매개변수의 디폴트 값을 비우는 형태로는 지정할 수 없다는 점에 유의한다.
int MyFunc(int num1 = 3, int num2 = 4, int num3) { }
반드시 오른쪽 매개변수의 디폴트 값부터 채우는 형태로 정의해야 한다. 함수에 전달되는 인자가 왼쪽에서부터 오른쪽으로 채워지기 때문이다.
MyFunc(1)을 호출한 경우, num1 자리에 1이 들어가고 나머지 자리는 디폴트 값이 채워진다. MyFunc(2, 3)을 호출한 경우, num1과 num2에 각각 2와 3이 들어가고 num3 자리에 디폴트 값이 채워진다. 이처럼 num1과 num2가 num3보다 우선적으로 채워지기 때문에, num3만 넣고 나머지 둘을 디폴트 값으로 채울 방법은 존재하지 않는다.