算是对多重继承里,类型转换所做一个笔记。先看如下代码:
class A
{
public:
A() { m_data = 'A';}
~A() {}
char m_data;
};
class B
{
public:
B() { m_data = 'B';}
~B() {}
char m_data;
};
class C : public A, public B
{
public:
C() { m_data = 'C';}
~C() {}
char m_data;
};
class D : public C
{
public:
D() { m_data = 'D';}
~D() {}
void test()
{
DWORD value = (DWORD)this;
A* address1 = (A*)(value);// 编译通过,类型转换错误(仅在在虚拟继承的情况下),正确的写法:A* address1 = (A*)((D*)value);
B* address2 = (B*)(value);// 编译通过,类型转换错误,正确的写法:B* address2 = (B*)((D*)value);
C* address3 = (C*)(value);
D* address4 = (D*)(value);
printf("%c %c %c %c", address1->m_data, address2->m_data, address3->m_data, address4->m_data);
}
char m_data;
};
void main()
{
D d;
d.test();
}
代码运行后,结果为A A C D,显然B这个类没有正确转换。
A和B都是D的父类,为什么A* address1 = (A*)value这句转换正确,而B* address2 = (B*)(value)出错呢?这就是多重继承的不可判断性。
正因为这种特性的存在,我们在实际使用中,应该尽量避免多重继承,选择单一继承这种模式。JAVA就是如此,最初设计时就只能单一继承,而多重继承则演变为纯虚接口(interface),这样就规避了此类问题。但可惜,在C++里,WTL和QT都大量使用这种模型,想在实际项目中完全避免,也很困难。
要解决,有几种方法。
1. 把B* address2 = (B*)(value)这行,改写为B* address2 = (B*)((D*)value); 这样就能直观的传达给编译器,B正确的偏移量。
最终输出A B C D,正是我们想要的结果。
2. 显示使用static_cast,当编译器不能确定转换类型时,会提示编译错误信息。
例如:
B* address2 = static_cast<B*>(value); // 编译失败。
B* adddres2 = static_cast<B*>((D*)value); // 编译成功,并且结果正确。
3. 使用RTTI解决。
--------------------------------------------------
看似问题解决了,可如果一旦改写为
虚拟继承(class C : virtual public A, virtual public B)这种形式,A运行时还是会出错,必须写成A* address1 = (A*)((D*)value);。如程序里用到了多重继承,一定要小心+谨慎。
posted on 2011-01-12 15:53
foxriver 阅读(6293)
评论(10) 编辑 收藏 引用