算是對多重繼承里,類型轉(zhuǎn)換所做一個筆記。先看如下代碼:
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);// 編譯通過,類型轉(zhuǎn)換錯誤(僅在在虛擬繼承的情況下),正確的寫法:A* address1 = (A*)((D*)value);
B* address2 = (B*)(value);// 編譯通過,類型轉(zhuǎn)換錯誤,正確的寫法: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();
}
代碼運行后,結(jié)果為A A C D,顯然B這個類沒有正確轉(zhuǎn)換。
A和B都是D的父類,為什么A* address1 = (A*)value這句轉(zhuǎn)換正確,而B* address2 = (B*)(value)出錯呢?這就是多重繼承的不可判斷性。
正因為這種特性的存在,我們在實際使用中,應(yīng)該盡量避免多重繼承,選擇單一繼承這種模式。JAVA就是如此,最初設(shè)計時就只能單一繼承,而多重繼承則演變?yōu)榧兲摻涌?interface),這樣就規(guī)避了此類問題。但可惜,在C++里,WTL和QT都大量使用這種模型,想在實際項目中完全避免,也很困難。
要解決,有幾種方法。
1. 把B* address2 = (B*)(value)這行,改寫為B* address2 = (B*)((D*)value); 這樣就能直觀的傳達(dá)給編譯器,B正確的偏移量。
最終輸出A B C D,正是我們想要的結(jié)果。
2. 顯示使用static_cast,當(dāng)編譯器不能確定轉(zhuǎn)換類型時,會提示編譯錯誤信息。
例如:
B* address2 = static_cast<B*>(value); // 編譯失敗。
B* adddres2 = static_cast<B*>((D*)value); // 編譯成功,并且結(jié)果正確。
3. 使用RTTI解決。
--------------------------------------------------
看似問題解決了,可如果一旦改寫為
虛擬繼承(class C : virtual public A, virtual public B)這種形式,A運行時還是會出錯,必須寫成A* address1 = (A*)((D*)value);。如程序里用到了多重繼承,一定要小心+謹(jǐn)慎。
posted on 2011-01-12 15:53
foxriver 閱讀(6371)
評論(10) 編輯 收藏 引用