天天看點

C++ Primer 學習筆記_95_用于大型程式的工具 --多重繼承與虛繼承用于大型程式的工具

引言:

大多數應用程式使用單個基類的公用繼承,但是,在某些情況下,單繼承是不夠用的,因為可能無法為問題域模組化,或者會對模型帶來不必要的複雜性。

在這些情況下,多重繼承可以更直接地為應用程式模組化。多重繼承是從多于一個直接基類派生類的能力,多重繼承的派生類繼承其所有父類的屬性。

一、多重繼承

1、定義多個類

為了支援多重繼承,擴充派生清單:

以支援由逗号分隔的基類清單:

派生類為每個基類(顯式或隐式地)指定了通路級别——public、protected 或 private。像單繼承一樣,隻有在定義之後,類才可以用作多重繼承的基類。對于類可以繼承的基類的數目,沒有語言強加的限制,但在一個給定派生清單中,一個基類隻能出現一次。

2、多重繼承的派生類從每個基類中繼承狀态

在多重繼承下,派生類的對象包含每個基類的基類子對象:

對象ying_yang包含一個 Bear類子對象(Bear類子對象本身包含一個ZooAnimal基類子對象)、一個Endangered類子對象以及Panda類中聲明的非static資料成員(如果有的話)。

C++ Primer 學習筆記_95_用于大型程式的工具 --多重繼承與虛繼承用于大型程式的工具

3、派生類構造函數初始化所有基類

構造派生類型的對象包含構造和初始化它的所有基類子對象。像繼承單個基類的情況一樣,派生類的構造函數可以在構造函數初始化式中給零個或多個基類傳遞值:

4、構造次序

構造函數初始化式隻能控制用于初始化基類的值,不能控制基類的構造次序。基類構造函數按照基類構造函數在類派生清單中的出現次序調用。對Panda而言,基類初始化的次序是:

1)ZooAnimal,從Panda的直接基類Bear沿層次向上的最終基類。

2)Bear,第一個直接基類。

3)Endangered,第二個直接基類,它本身沒有基類。

4)Panda,初始化Panda本身的成員,然後運作它的構造函數的函數體。

【注解】

構造函數調用次序既不受構造函數初始化清單中出現的基類的影響,也不受基類在構造函數初始化清單中出現的次序的影響。

例如,在Panda類的預設構造函數中,隐式調用Bear類的預設構造函數,它不出現在構造函數初始化清單中,但仍在顯式列出的Endangered類構造函數之前調用Bear類的預設構造函數。

5、析構的次序

總是按構造函數運作的逆序調用析構函數。如:

二、轉換與多個基類

在單個基類情況下,派生類的指針或引用可以自動轉換為基類的指針或引用,對于多重繼承也是如此,派生類的指針或引用可以轉換為其任意基類的指針或引用。

在多重繼承的情況下,遇到二義性轉換的可能性更大。編譯器不會試圖根據派生類轉換來差別基類間的轉換,轉換到每個基類都一樣好:

1、多重繼承下的虛函數

假定我們的類定義了下表列出的虛成員:

<col>

ZooAnimal/Endangered類中的虛函數

函數

定義自己版本的類

print

ZooAnimal::ZooAnimal

Bear::Bear

Endangered::Endangered

Panda::Panda

highlight

toes

cuddle

析構函數

2、基于指針類型或引用類型的查找

像單繼承一樣,用基類的指針或引用隻能通路基類中定義(或繼承)的成員,不能通路派生類中引入的成員。

當一個類繼承于多個基類的時候,那些基類之間沒有隐含的關系,不允許使用一個基類的指針通路其他基類的成員。

在通過Endangered指針或引用通路Panda對象時,不能通路Panda接口的Panda特定的部分和Bear部分:

3、确定使用哪個虛析構函數

假定所有根基類都将它們的析構函數适當定義為虛函數,那麼,無論通過哪種指針類型删除對象,虛析構函數的處理都是一緻的:

假定這些指針每個都向Panda對象,則每種情況下發生完全相同的析構函數調用次序。析構函數調用的次序是構造函數次序的逆序:通過虛機制調用Panda析構函數。随着Panda析構函數的執行,依次調用Endangered、Bear和ZooAnimal的析構函數。

三、多重繼承派生類的複制控制

多重繼承的派生類的逐個成員初始化、指派和析構,表現得與單繼承下的一樣,使用基類自己的複制構造函數、指派操作符或析構函數隐式構造、指派或撤銷每個基類。

假定Panda類使用預設複制控制成員。ling_ling的初始化

使用預設複制構造函數調用Bear複制構造函數,Bear複制構造函數依次在執行 Bear複制構造函數之前運作ZooAnimal複制構造函數。一旦構造了ling_ling的 Bear部分,就運作Endangered複制構造函數來建立對象的那個部分。最後,運作Panda複制構造函數。

合成的指派操作符的行為類似于複制構造函數。

合成的析構函數撤銷Panda對象的每個成員,并且按構造次序的逆序為基類部分調用析構函數。

【小心地雷】

像單繼承的情況一樣,如果具有多個基類的類定義了自己的析構函數,該析構函數隻負責清除派生類。如果派生類定義了自己的複制構造函數或指派操作符,則類負責複制(指派)所有的基類子部分。隻有派生類使用複制構造函數或指派操作符的合成版本,才自動複制或指派基類部分。

繼續閱讀