C++之菱形繼承
阿新 • • 發佈:2019-01-07
當我們談C++時,我們談些什麼?
封裝,繼承,多型。這是C++語言的三大特性,而每次在談到繼承時我們不可避免的要談到一個很重要的問題——菱形繼承。
a.菱形繼承是什麼
如上圖,菱形繼承即多個類繼承了同一個公共基類,而這些派生類又同時被一個類繼承。這麼做會引發什麼問題呢,讓我們來看一段程式碼吧!
#include<iostream> using namespace std; class Base { protected: int _base; public: void fun() { cout << "Base::fun" << endl; } }; class A:public Base { protected: int _a; }; class B : public Base { protected: int _b; }; class D :public A, public B { private: int _d; }; int main() { D d; d.fun();//編譯器報錯:呼叫不明確 getchar(); }
我們可以看見D的物件模型裡面儲存了兩份Base,當我們想要呼叫我們從Base裡繼承的fun時就會出現呼叫不明確問題,並且會造成資料冗餘的問題,明明可以只要一份就好,而我們卻儲存了兩份。
那麼我們可以怎樣解決呢?
第一種解決方法,使用域限定我們所需訪問的函式
int main()
{
D d;
d.A::fun();
d.B::fun();
getchar();
}
這樣的做法是沒有問題的,但是,這樣做非常的不方便,並且當程式十分大的時候會造成我們思維混亂
於是,C++給了我們一個別的解決方案——虛繼承
b.虛繼承
虛繼承是什麼?
如上圖,虛繼承即讓A和B在繼承Base時加上virtural關鍵字,這裡需要記住不是D使用虛繼承
那麼,虛繼承又是怎麼解決這些煩人的問題的呢?
我們可看見在A和B中不再儲存Base中的內容,儲存了一份偏移地址,然後將Base的資料儲存在一個公共位置處這樣保證了資料冗餘性的降低同時,我們也能直接的使用d.fun()來呼叫Base裡的fun函式。
#include<iostream> using namespace std; class Base { protected: int _base; public: void fun() { cout << "Base::fun" << endl; } }; class A:virtual public Base { protected: int _a; }; class B :virtual public Base { protected: int _b; }; class D :public A, public B { private: int _d; }; int main() { D d; d.fun(); getchar(); }