C++, 다중상속, dynamic_cast
글쓴이: wafe / 작성시간: 금, 2004/04/30 - 12:47오후
클래스 A가 있습니다. 그리고 인터페이스 흉내를 내려고 클래스 B를 만들어서 가상함수만 넣었습니다. 그리고 C는 A와 B를 상속 받아서 가상 함수를 구현했습니다.
class A {
public:
void MethodA1();
};
class B {
public:
virtual void MethodB1() = 0;
};
class C : public A, B {
void MethodB1() { // blahblah }
};
그 외에도 같은 형식으로 A,B를 상속받아 B의 가상 함수를 구현한 클래스들이 많습니다. D, E, F, ...
그리고 함수가 하나 있는데 이 함수가 A형 포인터를 받는데, 실제로는 항상 C, D, E, F 등등 상속된 클래스만 받습니다. 그런데 이 함수에서 내부에서 B의 포인터로 바꿀 일이 있습니다. B*형을 받는 다른 함수를 호출해야 하거든요. 대충 이런 식이지요.
func1(A* pA) {
// 조건 1
if(...) {
B* pB = dynamic_cast<B*>(pa);
func2(pB);
}
else {
// 딴짓
}
}
이 코드에서 dynamic_cast 가 실패하는 것이 정상인가요? 반환값이 NULL이 나와서 pB를 쓸 수가 없네요. 그리고 이 경우에 C 스타일 캐스팅을 사용하면 문제가 발생하지는 않을까요?
Forums:


Re: C++, 다중상속, dynamic_cast
A 와 B 타입은 아무 관계가 없습니다.
해서 상호간 캐스팅도 불가능합니다.
그래서 dynamic_cast 가 NULL 을 리턴할 것입니다.
C 스타일 캐스팅을 써서도 안됩니다.
A 포인터를 B 포인터로 바꾸기 위해서는
A 포인터를 C 와 같이 A 와 B 간의 관계를 가지고 있는 포인터로 바꾼 다음
C 포인터를 B 포인터로 바꾸는것이 바른 방법입니다.
참고로 가상테이블을 가진 클래스들의 다중상속시
실제 인스턴스는 동일하다 해도,
참조하는 타입에 따라 값이 달라집니다. (아래 예제 참고)
아래 예에서는 reinterpret_cast 를 사용하였지만,
만약 p1 포인터를 p2 로 변환시 C style cast 를 사용한다면
결과는 reinterpret_cast 로 변환한것과 같을 것입니다.
#include <stdio.h> class Parent_1 { public: virtual void DoSomething() = 0; }; class Parent_2 { }; class Child : public Parent_1, public Parent_2 { public: void DoSomething() { printf( "child\n" ); } }; int main() { Child *child = new Child; Parent_1 *p1 = static_cast< Parent_1* >( child ); Parent_2 *p2 = static_cast< Parent_2* >( child ); printf( "Child : 0x%08X\n", child ); printf( "P1 : 0x%08X\n", p1 ); printf( "P2 : 0x%08X\n", p2 ); p1 = child; p2 = child; printf( "\n\n" ); printf( "Child : 0x%08X\n", child ); printf( "P1 : 0x%08X\n", p1 ); printf( "P2 : 0x%08X\n", p2 ); p1 = reinterpret_cast< Parent_1* >( child ); p2 = reinterpret_cast< Parent_2* >( child ); // <- 이거 참조하면 뻑남 printf( "\n\n" ); printf( "Child : 0x%08X\n", child ); printf( "P1 : 0x%08X\n", p1 ); printf( "P2 : 0x%08X\n", p2 ); } .. 결과는 아래와 같습니다. Child : 0x00372ED0 P1 : 0x00372ED0 P2 : 0x00372ED4 Child : 0x00372ED0 P1 : 0x00372ED0 P2 : 0x00372ED4 Child : 0x00372ED0 P1 : 0x00372ED0 P2 : 0x00372ED0클래스 A와 B는 서로 관계가 없으므로 직접 dynamic_cast를 하
클래스 A와 B는 서로 관계가 없으므로 직접 dynamic_cast를 하면
항상 0이 나옵니다. 그러나 A*가 가리키는 개체가 C라는 것을 알고
있다면 안전하게 B*로 바꿀 수 있습니다.
A* pa = new C; if (C* pc = dynamic_cast<C*>(pa)) { B* pb = pc; pb->MethodB1(); // pc->MethodB1()과 동일 }댓글 달기