網(wǎng)站管理員登錄哪有學電腦培訓班
目錄
概念:
定義:
定義格式
繼承關系和訪問限定符
基類和派生類對象賦值轉(zhuǎn)換:
繼承中的作用域:
派生類的默認成員函數(shù)
繼承與友元:
繼承與靜態(tài)成員:
復雜的菱形繼承及菱形虛擬繼承:
虛擬繼承使用格式
虛擬繼承的原理解釋
繼承和組合
概念:
繼承機制是面向?qū)ο蟪绦蛟O計使代碼可以復用的最重要的手段,它允許程序員在保持原有類特性的基礎上進行擴展,增加功能,這樣產(chǎn)生的新類稱為 派生類。
繼承是類設計層次的復用,之前接觸的復用都是簡單的函數(shù)復用。
定義:
定義格式
下圖中:Person是父類,也稱作基類。Student是子類,也稱作派生類
繼承關系和訪問限定符
繼承方式和基類的訪問限定符共同決定了派生類成員的訪問權限
繼承基類成員訪問方式的變化
可以看出派生類成員訪問權限是取 基類成員訪問權限和派生類繼承方式中較小的那個權限
基類和派生類對象賦值轉(zhuǎn)換:
- 派生類對象 可以賦值給 基類的對象/基類的指針/基類的引用,這種被稱作切片或切割,派生類比基類多出的那部分將會被切除,和基類相同部分進行賦值
- 基類對象不能賦值的派生類
- 基類的指針或者引用可以通過強制類型轉(zhuǎn)換賦值給派生類的指針或者引用。但是必須是基類的指針是指向派生類對象時才是安全的。這里基類如果是多態(tài)類型,可以使用RTTI(Run-Time Type Information)的dynamic_cast 來進行識別后進行安全轉(zhuǎn)換。
繼承中的作用域:
- 在繼承體系中 基類 和 派生類 都有 獨立的作用域
- 子類和父類中有同名成員時,子類成員將屏蔽父類會同名成員的直接訪問,這種情況叫隱藏(原理就是編譯器先在子類中尋找,再去父類尋找,如果子類中找到了就自然不會再去父類尋找了,所以可以使用作用域限定符直接指定父類的類域 去訪問父類的同名成員)
- 如果是成員函數(shù)的隱藏,只需要函數(shù)名相同就構成隱藏
派生類的默認成員函數(shù)
首先,派生類一般是基類的拓展,我們可以將派生類分為 基類和拓展部分,對于基類部分的操作基本是沿用它自己的,拓展部分則是我們類似一個新類去定義
- 派生類的構造函數(shù)會自動調(diào)用(由編譯器操作)基類的構造函數(shù)初始化基類的那一部分成員。如果基類沒有默認的構造函數(shù),則必須在派生類構造函數(shù)的初始化列表階段顯示調(diào)用。
- 派生類的拷貝構造函數(shù)必須調(diào)用基類的拷貝構造完成基類的拷貝初始化。
- 派生類的operator=必須要調(diào)用基類的operator=完成基類的復制。
- 派生類的析構函數(shù)會在被調(diào)用完成后自動調(diào)用基類的析構函數(shù)清理基類成員。因為這樣才能保證派生類對象先清理派生類成員再清理基類成員的順序。
- 派生類對象初始化先調(diào)用基類構造再調(diào)派生類構造。
- 派生類對象析構清理先調(diào)用派生類析構再調(diào)基類的析構。
繼承與友元:
友元關系不能被繼承,也就是說基類友元不能訪問子類私有和保護成員
繼承與靜態(tài)成員:
基類定義了static 靜態(tài)成員,則同一個繼承體系中只有一個此成員。也就是說一個 static 靜態(tài)成員被同一個繼承體系共用,不論有多少個子類。
復雜的菱形繼承及菱形虛擬繼承:
單繼承:一個子類只有一個直接父類時稱這個繼承關系為單繼承
多繼承:一個子類有兩個或以上直接父類時稱這個繼承關系為多繼承
菱形繼承:菱形繼承是多繼承的一種特殊情況。
菱形繼承的問題:從下面的對象成員模型構造,可以看出菱形繼承有數(shù)據(jù)冗余和二義性的問題。在Assistant的對象中Person成員會有兩份。
虛擬繼承可以解決菱形繼承的二義性和數(shù)據(jù)冗余的問題,原理下面會詳細說明。如上面的繼承關系,在Student和Teacher的繼承Person時使用虛擬繼承,即可解決問題。需要注意的是,虛擬繼承不要隨便在其他地方去使用。
虛擬繼承使用格式
在繼承方式前加上 virtual 關鍵字即可
class A
{public:
int _a;
};// class B : public A
class B : virtual public A //這里繼承方式前面加上
{
public:
int _b;
};
虛擬繼承的原理解釋
上面 Person關系菱形虛擬繼承的原理圖:
由圖可以看出,兩個派生類對于同一個基類的虛擬繼承,是在兩派生類當中存下一個基類的偏移量指針,這個指針指向一張表,表叫做虛基表,指針叫做虛基表指針。通過這個表與存下的指針,就能找到基類的位置,所以就不會出現(xiàn)二義性和數(shù)據(jù)冗余的問題了。
相當于將子類 虛擬繼承的成員/函數(shù) 換成對應的地址,通過這個地址找到最初的父類,這樣繼承的就完全是同一個東西了,不會重復也不會出現(xiàn)歧義
繼承和組合
- public繼承是一種 is-a 的關系。也就是說每個派生類對象都是一個基類對象。
- 組合是一種 has-a 的關系。比如 B 組合了 A,則每個 B 對象中都有一個 A 對象
- 優(yōu)先使用對象組合,而不是類繼承
- 繼承這種通過生成派生類的復用通常被稱為白箱復用,因為在繼承方式中,基類的內(nèi)部細節(jié)對子類是可見的,這一定程度破壞了基類的封裝,基類的改變可能對派生類有很大影響(派生類的有些功能實現(xiàn)可能就是用基類的細節(jié)來定義的)。這樣派生類和基類間的依賴關系很強,耦合度高。
- 組合則相反,被稱為黑箱復用,被組合的對象內(nèi)部細節(jié)是不可見的,其必須具有良好定義的接口,我們只需要了解其功能和接口使用即可。這樣的話就被封裝得很好,組合類間沒有很強的依賴關系,耦合度低。
- 實際盡量多用組合,組合耦合度低,代碼維護性好。但還是要根據(jù)實際情況,若更適合繼承(is-a 的關系),就用繼承。