C++ 가상함수 오버라이드가 안되는데 이유를 모르겠습니다.
글쓴이: phyljh / 작성시간: 목, 2020/10/22 - 5:57오후
C++ 가상함수 오버라이드 공부를 하려고 아래와 같은 코드를 짜봤는데요.
예상결과로 기대한것은 Derived foo 가 출력되는 것인데
Base foo 가 출력됩니다.
무엇이 잘못된것일까요?
#include <iostream> using namespace std; template<typename T> class Base { public: virtual void foo(const T a) { cout << "Base foo" << endl; } }; class Derived : public Base<int*> { public: virtual void foo(const int* a) { cout << "Derived foo" << endl; } }; int main() { int* t = nullptr; Base<int*> * p = new Derived(); p->foo(t); return 0; }
Forums:
요즘 kldp에 재미있는 C++ 질문들이 많이
요즘 kldp에 재미있는 C++ 질문들이 많이 올라오는군요.
1. 네. override 안 됩니다.
Base<int*>::foo
는int * const a
와 같이 매개변수를 받는 반면,Derived::foo
는const int *a
와 같이 매개변수를 받고 있거든요.그 둘의 차이를 모르시겠거든, C++이 C로부터 물려받은 toxic한 선언 문법을 좀 공부하셔야 됩니다.
위 4개 선언에 대해서 (1)
p
의 값을 바꿀 수 있는 경우와 (2)*p
의 값을 바꿀 수 있는 경우를 각각 구분해보세요. 연습문제입니다.요점은, 포인터에 const를 붙일 땐 (1) 포인터 자신이 상수인 경우와 (2) 포인터가 가리키는 대상이 상수인 경우를 구분해야 한다는 겁니다.
아무튼, 결국
Derive:foo
가Base<int*>::foo
를 제대로 override하려면 아래와 같이 짜야 한다는 뜻이죠.(그건 그렇고, C++11의
nullptr
는 썼으면서 C++11의override
는 안 쓰신 거 실화입니까?!)컴파일 잘 되고, 실행 예상대로 "Derived foo" 잘 찍혀 나올 겁니다.
2. 혼동의 원인 중 하나는, 템플릿 매개변수는 단순한 문자열 치환이 아니라는 겁니다.
예컨대
virtual void foo(const T a)
에서T
를 그대로int*
로 치환해서virtual void foo(const int* a)
가 되는 게 아니라고요.typename T
에 대해서 당신이const T a
라고 썼으면,T
가 무엇이었건 간에const
는a
를 상수로 만듭니다.그래서
T
가 포인터인int*
로 치환될 경우, 해당 매개변수 타입은a
가 상수가 되는int * const a
가 되는 것이죠.생각해보면 아주 합리적입니다. 바로 이런 기능 때문에 전처리기 매크로 같은 것 대신 템플릿을 쓰는 거죠.
감사합니다.
혼동의 원인을 정확히 지적해 주셔서 감사합니다.
foo 함수의 인자를 const int* 로 하려고 했었는데 그렇다면 아래처럼 짰어야 되는거였군요.
+1
좋은 답변으로 많이 배워갑니다.
저는 이렇게 생각했습니다.
댓글 달기