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