0x01 菱形繼承ios
假設有類B和類C,它們都繼承了相同的類A。另外還有類D,類D經過多重繼承機制繼承了類B和類C。函數
若是直接繼承會引起訪問不明確(二義性),以及數據冗餘。若是直接指定訪問對象,可解決二義性,而要解決數據冗餘,則要引入虛函數。spa
由於圖表的形狀相似於菱形(或者鑽石),所以這個問題被形象地稱爲菱形問題(鑽石繼承問題)。對象
示例代碼:blog
#include <Windows.h> #include <iostream> using namespace std; class Life { public: Life() :LifeMeaning(5) { } public: int LifeMeaning; }; class Bird :public Life { public: Bird() :BirdMeaning(0x50) { } public: int BirdMeaning; }; class Human :public Life { public: Human() :HumanMeaning(0x100) { } public: int HumanMeaning; }; class Angel :public Bird, public Human { public: Angel() :AngelMeaning(0x30) { } public: int AngelMeaning; }; int main() { Angel Angel; return 0; }
內存窗口觀察Angel對象的基地址,能夠看到有兩個05(Life中的成員變量LifeMeaning的值05),這是由於子類對象會包父類的成員變量。對於Bird和Human來講,都會去包含Life類中LifeMeaning的值05。對於天使Angel來講,會同時包含Bird和Human的全部成員。故而LifeMeaning的這個變量在子類Angel中出現了兩次,這是菱形繼承問題。繼承
對於二義性,能夠經過做用域符指定訪問對象來消除(Angel.Bird::LifeMeaning),而數據冗餘的問題,則要經過虛繼承。內存
0x02 虛繼承作用域
實例代碼:io
#include <Windows.h> #include <iostream> using namespace std; class Life { public: Life() :LifeMeaning(0x5) { } public: int LifeMeaning; }; class LifePropagate1 :virtual public Life { public: LifePropagate1() :LifePropagate1Meaning(0x50) { } public: int LifePropagate1Meaning; }; class LifePropagate2 :virtual public Life { public: LifePropagate2() :m_B(0x60) { } public: int m_B; }; class NewLife :public LifePropagate1, public LifePropagate2 { public: NewLife() :NewLifeMeaning(0x100) { } public: int NewLifeMeaning; }; int main() { NewLife NewLifeObject; return 0; }
內存窗口觀察NewLifeObject對象的基地址:class
LifePropagate1與LifePropagate2 共用一個虛基類。最終虛基類的數據只有一份,數據冗餘和二義性問題再也不。
那麼,虛繼承又是怎麼解決這些煩人的問題的呢?
能夠看到在B和C中再也不保存Life中的內容,保存了一份偏移地址,而後將最原始父類的數據保存在一個公共位置處這樣保證了數據冗餘性的下降同時,也消除了二義性。