C++ 추상 클래스와 포인터 캐스팅, 다중상속 ㅅㅂㄹㅁ

프로그래밍 2007.06.13 22:41
상황설명

A라는 부모 클래스를 만들고, 이 A라는 클래스의 포인터인 A* pA 를 인자로 하는 foo(A* pA)를 정의해서 사용중이었다. 이 함수의 인자로는 A를 상속한 B나 C클래스를 예상할 수 있으며, 이 B와 C클래스는 I라는 순수 가상함수를 상속한 다중상속 객체들이었다. I는 순수가상함수인 Vfoo()를 가지고 있었다. C는 생성자에서 A의 함수(가상함수가 아니다)를 호출한다.

사용자 삽입 이미지

이런 상속관계 (수정)


vector<I*> vt;

...

C* pC = new C;
I* pI = (I*)pC; // C* -> I*
vt.push_back(pI);

...

A* pA = (A*)vt[0]; // C* -> I* -> A*
foo(pA);

...

foo(A* p_pA)
{
    I* pI = (I*)p_pA; // C* -> I* -> A* -> I*
    pI->Vfoo(); // 여기서 문제발생
}

문제발생

문제는 C형 인스턴스를 가리키는 A형 포인터 pA_dir_C를 foo(A* pA)의 인자로 넘겨주면서 일어났다. foo(A* pA)함수 내부에서는 인자로 받은 pA를 (I*)pA 로 형변환하여 Vfoo()를 호출하는 루틴이 들어있었는데, 여기서 에러가 발생한 것이다. (6025 pure virtual function call)

Watch를 통하여 살펴보니 vftable의 문제였는지, Vfoo()가 아닌 엉뚱한 함수가 불려오더라. (다른 추상 클래스 I2에서 오버라이딩 된 가상함수였다.) 포인터 형변환에서 가상함수 테이블에 변화가 오는 것일까?

해결책

결국 C* -> I* -> A* -> I* 와 같은 여러 번의 형변환을 거치지 않고 C* -> I* 상태에서 pI->Vfoo() 식으로 형변환 단계를 줄여서 사용하였다. 정확히 말하면 문제를 해결한 것이 아니라 회피한 것이나 마찬가지다. 하지만 적당한 레퍼런스도 없고, 도와줄만한 사람도 없고 해서. 코드 길이는 좀 길어질지 몰라도 저런 식으로 함수를 통하는 단계를 줄여버렸다.

감상

쩐의 전쟁이 너무 재밌다.


Trackbacks 1 : Comments 11