C++_代碼重用4-多重繼承
繼承使用時要註意,默認是私有派生。所以要公有派生時必須記得加關鍵字Public。
MI(Multi Inheritance)會帶來哪些問題?以及如何解決它們?
兩個主要問題:
從兩個不同的基類繼承同名方法;
從兩個或更多相關基類那裏繼承同一個類的多個實例;
虛方法
Worker公有派生出Singer和Waiter;
然後Singer和Waiter公有派生出SingingWaiter(即多重繼承);
這樣會導致一個問題,就是SingingWaiter中有兩個Worker組件。通常可以將派生類對象的地址賦值給基類指針。但是在這樣的情況下這麽做的話,將出現二義性。所以必須使用類型轉換來指定對象。但這又增加了指針引用的復雜度。
C++在引入多重繼承的同時,也引入新技術——虛基類,來解決該問題。
虛基類也用關鍵字virtual,虛基類與虛函數之間並不存在明顯的聯系。這麽做是為了給程序員減少壓力,類似於關鍵字的重載。
class Singer: virtual public Worker{…};
class Waiter: public virtual Worker{…};
(virtual和public的次序無關緊要)
那麽為什麽不使虛行為成為MI的默認準則呢?
在一些情況下,可能需要基類的多個拷貝;
將基類作為虛的要求程序完成額外的計算,為不需要的程序付出代價是不應當的;
新的構造函數規則
使用虛基類時,必須對構造函數采用新的方法;
對於非虛基類,唯一可以出現在初始化列表中的構造函數是即時基類構造函數。
A派生B,B派生C;--->C類的構造函數只能調用B類的構造函數,B類的構造函數只能調用A類構造函數。
但對於虛基類而言,這種信息自動傳遞方式不可用。這是因為對於多重繼承而言,信息傳遞將通過兩條不同的途徑。為避免這種沖突,當基類是虛的,將禁止信息通過中間類自動傳遞給基類。
這就要求顯式地調用所需的基類構造函數:
SingingWaiter(參數列表):Worker(wk),Waiter(wk,p),Singer(wk,v) { }
上述格式對虛基類來說是合法的,對非虛基類來說是非法的。
哪個方法
對於多重繼承,如果每個祖先都有一個Show函數,那麽會導致函數調用的二義性。
對於單繼承,如果沒有重新定義show,將調用最近祖先中的show定義。
有幾種解決方法:
1使用作用域解析運算符來澄清編程者的意圖;
2或是在多重繼承的類中重新定義show方法,並指出要使用哪個show;
這種遞增的方法對於單繼承來說是有效的;
但是對於多重繼承來說,還是有問題:
SingingWaiter::Show
{Singer::Show();Waiter::Show();} //這將顯示姓名和ID兩次。
該如何解決呢?->使用模塊化方法,而不是遞增的方法;即提供一個只顯示worker組件的方法,提供一個只顯示waiter組件及singer組件的方法。
將所有數據組件都設置為保護的方法,而不是私有的,可以更嚴格地控制對數據的訪問;
如果數據組件的方法是保護的,則只能在繼承層次結構中的類中使用它,在其他地方則不能使用。
MI小結
MI會增加編程的復雜度。然而,這種復雜度主要是由於派生類通過多條途徑繼承同一個基類引起的。
當派生類使用關鍵字virtual來指示派生時,基類就稱為了虛基類。其構造函數的規則有所變化,不會自動進行信息不換傳遞,需要顯式地調用基類構造函數。
通過優先規則解決名稱二義性。如果一個類從兩個不同的類那裏繼承了兩個同名的成員,則需要在派生類中使用類限定符來區分它們。否則,編譯器將指出二義性。
有間接虛基類的派生類包含直接調用間接基類構造函數的構造函數,這對於間接非虛基類來說是非法的。
C++_代碼重用4-多重繼承