當咱們談C++時,咱們談些什麼?ios
封裝,繼承,多態。這是C++語言的三大特性,而每次在談到繼承時咱們不可避免的要談到一個很重要的問題——菱形繼承。ide
a.菱形繼承是什麼
函數
如上圖,菱形繼承即多個類繼承了同一個公共基類,而這些派生類又同時被一個類繼承。這麼作會引起什麼問題呢,讓咱們來看一段代碼吧!spa
#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時就會出現調用不明確問題,而且會形成數據冗餘的問題,明明能夠只要一份就好,而咱們卻保存了兩份。對象
那麼咱們能夠怎樣解決呢?blog
第一種解決方法,使用域限定咱們所需訪問的函數繼承
int main() { D d; d.A::fun(); d.B::fun(); getchar(); }
這樣的作法是沒有問題的,可是,這樣作很是的不方便,而且當程序十分大的時候會形成咱們思惟混亂get
因而,C++給了咱們一個別的解決方案——虛繼承編譯器
b.虛繼承it
虛繼承是什麼?
如上圖,虛繼承即讓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(); }
*虛繼承和虛函數是徹底不一樣的兩個概念,但願你們不要隨意搞混,想要了解虛函數的同窗能夠看看博主的另外一篇博文《C++的繼承&多態》http://zimomo.blog.51cto.com/10799874/1752936