본문 바로가기
번역/Bjarne Stroustrup's C++ Style and Technique FAQ

Why doesn't overloading work for derived classes?

by 겜게준 2019. 12. 9.

파생 클래스에서 오버로딩이 안 되는 이유가 무엇인가요?

(많은 비슷한 질문들에서) 이 질문은 보통 몇몇 사람들이 잘못 예측하는 다음의 예제 때문에 나오게 되는데,

#include
using namespace std;

class B {
public:
int f(int i) { cout << "f(int): "; return i+1; }
// ...
};

class D : public B {
public:
double f(double d) { cout << "f(double): "; return d+1.3; }
// ...
};

int main()
{
D* pd = new D;

cout << pd->f(2) << '\n';
cout << pd->f(2.3) << '\n';
}

이 예제는 아래의 결과 대신
f(int): 3
f(double): 3.6

다음의 결과가 나옵니다.
f(double): 3.3
f(double): 3.6

정확히 말하자면, D와 B 사이에 Overload resolution(컴파일러에서 함수 호출을 컴파일할 때, 이름 or 템플릿 인수로 함수를 찾던 도중에 후보 함수가 둘 이상일 때 실제 호출될 함수를 선택하기 위한 작업)이 없습니다. 컴파일러는 D의 스코프를 검사하고, double f(double) 함수를 찾은 다음 호출을 하는데, 이때 B의 스코프는 신경쓰지 않습니다. C++은 스코프 사이에 오버로딩을 지원하지 않는데, 파생 클래스도 일반적인 규칙에서 예외는 아닙니다. (자세한 사항은 D&E 나 TC++PL3를 참고하시길 바랍니다).

그런데도 기본 클래스와 파생클래스의 f() 함수의 오버로드 셋을 만들고 싶으면 어떻게 해야 하나요?

그건 using 선언으로 쉽게 할 수 있습니다.

class D : public B {
public:
using B::f; // make every f from B available
double f(double d) { cout << "f(double): "; return d+1.3; }
// ...
};

이렇게 수정하면 출력은 다음과 같이 될 것인데
f(int): 3
f(double): 3.6

이는, B의 f()와 D의 f()에 overload resolution을 적용해 호출하기 가장 적절한 f()를 선택한 것입니다. 

댓글