在C++中,什麼叫做鑽石問題(也可以叫菱形繼承問題),怎麼避免它? 下面的圖表可以用來解釋鑽石問題。 假設我們有類B和類C,它們都繼承了相同的類A。另外我們還有類D,類D通過多重繼承機制繼承了類B和類C。因為上述圖表的形狀類似於鑽石(或者菱形),因此這個問題被形象地稱為鑽石問題(菱形繼承問題)。現在,我們將上面的圖表翻譯成具體的代碼: [cpp] /* Animal類對應於圖表的類A */ class Animal { /* ... */ }; // 基類 { int weight; public: int getWeight() { return weight;}; }; class Tiger : public Animal { /* ... */ }; class Lion : public Animal { /* ... */ } class Liger : public Tiger, public Lion { /* ... */ }; 在上面的代碼中,我們給出了一個具體的鑽石問題例子。Animal類對應於最頂層類(圖表中的A),Tiger和Lion分別對應於圖表的B和C,Liger類(獅虎獸,即老虎和獅子的雜交種)對應於D。 現在,問題是如果我們有這種繼承結構會出現什麼樣的問題。 看看下面的代碼後再來回答問題吧。 [cpp] int main( ) { Liger lg ; /*編譯錯誤,下面的代碼不會被任何C++編譯器通過 */ int weight = lg.getWeight(); } 在我們的繼承結構中,我們可以看出Tiger和Lion類都繼承自Animal基類。所以問題是:因為Liger多重繼承了Tiger和Lion類,因此Liger類會有兩份Animal類的成員(數據和方法),Liger對象"lg"會包含Animal基類的兩個子對象。 所以,你會問Liger對象有兩個Animal基類的子對象會出現什麼問題?再看看上面的代碼-調用"lg.getWeight()"將會導致一個編譯錯誤。這是因為編譯器並不知道是調用Tiger類的getWeight()還是調用Lion類的getWeight()。所以,調用getWeight方法是不明確的,因此不能通過編譯。 鑽石問題的解決方案: 我們給出了鑽石問題的解釋,但是現在我們要給出一個鑽石問題的解決方案。如果Lion類和Tiger類在分別繼承Animal類時都用virtual來標注,對於每一個Liger對象,C++會保證只有一個Animal類的子對象會被創建。看看下面的代碼: [cpp] class Tiger : virtual public Animal { /* ... */ }; class Lion : virtual public Animal { /* ... */ } 你可以看出唯一的變化就是我們在類Tiger和類Lion的聲明中增加了"virtual"關鍵字。現在類Liger對象將會只有一個Animal子對象,下面的代碼編譯正常: [cpp] int main( ) { Liger lg ; /*既然我們已經在Tiger和Lion類的定義中聲明了"virtual"關鍵字,於是下面的代碼編譯OK */ int weight = lg.getWeight(); } 因為Java不支持多繼承,所以不會出現菱形繼承問題。但是Java可以通過接口間接實現多重繼承。 [java] Class Mule implements Horse,Donkey { /* Horse和Donkey是接口*/ }