c++ 상속, 가상함수
글쓴이: j03y14 / 작성시간: 일, 2016/11/06 - 12:54오전
class CWall { public: virtual bool hasIntersected() { cout << "CWall hasIntersected" << endl; return false; } }; class VirticalCWall :public CWall { public: int c=1; virtual bool hasIntersected() { cout << "VirticalCWall hasIntersected" << endl; return false; } }; class HorizonalCWall :public CWall { public: int d = 1; virtual bool hasIntersected() { cout << "HorizonalCWall hasIntersected" << endl; return false; } }; int main() { <span> CWall g_legowall[2]; g_legowall[0] = VirticalCWall(); g_legowall[1] = HorizonalCWall() ;</span> <span>/*CWall* g_legowall[2]; g_legowall[0] = new VirticalCWall(); g_legowall[1] = new HorizonalCWall(); */</span> for (int i = 0;i<2 ;i++) { <span> g_legowall[i].hasIntersected();</span> <span>//g_legowall[i]->hasIntersected();</span> } return 0; }
왜 주석처리한 방법으로 객체를 생성해야만 상속받은 객체의 가상함수가 출력되고,
주석처리하지 않은 방법으로 겍체를 생성하면 부모 객체의 가상함수가 출력이 될까요?
주석처리하지 않은 방법으로 객체를 만들고 이용해서 자식 객체의 가상함수를 출력하는 방법이 없나요?
Forums:
?!!
자바 같은 언어 쓰다가 오셨나요??
C++에서 base class의 포인터나 참조자를 정의했다면 그것은 derived class의 객체를 가리킬 수 있습니다.
그러나 애초에 base class의 객체를 직접 정의했다면 그것은 곧 죽어도 base class의 객체입니다.
다시 말해, 다형성(Polymorphism) 기능을 제대로 쓰고 싶다면 주석처리된 코드처럼 포인터를 사용하거나, 아니면 참조자를 쓰셔야 된다는 얘기입니다.
주석처리 안 된 코드가 무사히 컴파일되는 것을 보고 착각하실 수 있는데, 저 코드는 질문자님이 의도하신 대로 절대 동작하지 않습니다.
C++는
g_legowall[0] = VirticalCWall();
를 이렇게 해석합니다.1.
VirticalCWall
타입의 temporary를 생성하고2. 그 temporary를
CWall
타입의 객체g_legowall[0]
에 복사 배정합니다.2-1. 말인즉슨
g_legowall[0]
에 대해 복사 배정 연산자CWall &CWall::operator=(const CWall &)
이 호출된다는 겁니다. 이 연산자를 정의한 적이 없다고 하셔도 마찬가집니다. 컴파일러가 자동으로 만들어줍니다.2-2. 여기서 복사 원본이 되는 것은 앞서 언급한 temporary인데, 이는 사실
VirticalCWall
타입이지만 상속 관계에 의해OWall
이기도 하므로 자동으로 업캐스팅이 수행되어 문제 없이 복사 배정이 일어납니다.결국 갓 만들어진
VirticalCWall
타입 temporary의OWall
부분만이g_legowall[0]
에 복사된다는 얘깁니다.대입 이후에도
g_legowall[0]
는 여전히OWall
객체이므로, 가상 함수를 호출해도 당연히OWall
의 것이 호출됩니다.감히 말씀드리건대, 이런 식으로 암시적으로 업캐스팅이 일어나서 객체의 일부만이 복사되는 상황은 일단 경계대상입니다. 무슨 일이 일어나는지 정확히 이해한 상황에서 일부러 그런 게 아니라면 말이죠. 말인즉슨, 실수로 이런 짓을 하기가 C++에서는 너무 쉽다는 얘깁니다.
DISCLAIMER: C++11 혹은 그 이후의 C++를 사용중이라면 복사 배정이 아니라 이동 배정이 됩니다. 어쨌든 논지는 안 달라져요.
댓글 달기