在C++中,什么叫做菱形繼承問題(也可以叫鑽石問題),怎么避免它?
假設我們有類B和類C,它們都繼承了相同的類A。另外我們還有類D,類D通過多重繼承機制繼承了類B和類C。因為上述圖表的形狀類似於鑽石(或者菱形),因此這個問題被形象地稱為鑽石問題(菱形繼承問題)。現在,我們將上面的圖表翻譯成具體的代碼:
#include<iostream> class Animal{ private: int weight; public: virtual int getWeight() { return this->weight; } }; class Tiger : public Animal{}; class Lion : public Animal{}; class Liger : public Tiger, public Lion{}; int main() { Liger lg; lg.getWeight(); }
在我們的繼承結構中,我們可以看出Tiger和Lion類都繼承自Animal基類。所以問題是:因為Liger多重繼承了Tiger和Lion類,因此Liger類會有兩份Animal類的成員(數據和方法),Liger對象"lg"會包含Animal基類的兩個子對象。
所以,你會問Liger對象有兩個Animal基類的子對象會出現什么問題?再看看上面的代碼-調用"lg.getWeight()"將會導致一個編譯錯誤。這是因為編譯器並不知道是調用Tiger類的getWeight()還是調用Lion類的getWeight()。所以,調用getWeight方法是不明確的,因此不能通過編譯。
解決方法一:
使用虛繼承,C++會保證對於每個Liger對象,只有一個Animal類的子對象會被創建。
#include<iostream> class Animal{ private: int weight; public: virtual int getWeight() { return this->weight; } }; class Tiger : virtual public Animal{}; class Lion : virtual public Animal{}; class Liger : public Tiger, public Lion{}; int main() { Liger lg; lg.getWeight(); }
解決方法二:
指定域
#include<iostream> class Animal{ private: int weight; public: virtual int getWeight() { return this->weight; } }; class Tiger : public Animal{}; class Lion : public Animal{}; class Liger : public Tiger, public Lion{}; int main() { Liger lg; lg.Lion::getWeight(); }
當存在多繼承時,雖然我們盡可能地保證不同類中地成員變量和成員函數命名不沖突,但是想菱形繼承仍有可能發生。
所以我們應該盡可能少地使用多繼承,只有在比較簡單或者實在有必要時才使用,能用單一繼承解決的問題就不要使用多繼承。也正是這個原因,C++之后的很多面向對象的語言,例如Java、C#、PHP等,都不支持多繼承。
參考鏈接: