類繼承
能夠從已有的類派生出新的類但壮,而派生類繼承了原有類(稱為基類)的特征咸包,包括方法。
1.可以在已有類的基礎(chǔ)上添加功能棒假。
2.可以給類添加數(shù)據(jù)溯职。
3.可以修改類方法的行為。
派生類需要自己的構(gòu)造函數(shù)帽哑。
派生類可以根據(jù)需要添加額外的數(shù)據(jù)成員和成員函數(shù)谜酒。
構(gòu)造函數(shù)必須給新成員(如果有的話)和繼承的成員提供數(shù)據(jù)。
(繼承類型
當一個類派生自基類妻枕,該基類可以被繼承為 public僻族、protected 或 private 幾種類型。繼承類型是通過上面講解的訪問修飾符 access-specifier 來指定的屡谐。
我們幾乎不使用 protected 或 private 繼承述么,通常使用 public 繼承。當使用不同類型的繼承時愕掏,遵循以下幾個規(guī)則:
公有繼承(public):當一個類派生自公有基類時度秘,基類的公有成員也是派生類的公有成員,基類的保護成員也是派生類的保護成員饵撑,基類的私有成員不能直接被派生類訪問剑梳,但是可以通過調(diào)用基類的公有和保護成員來訪問唆貌。
保護繼承(protected): 當一個類派生自保護基類時,基類的公有和保護成員將成為派生類的保護成員垢乙。
私有繼承(private):當一個類派生自私有基類時锨咙,基類的公有和保護成員將成為派生類的私有成員。
)
無論什么方式繼承追逮,派生類都不能直接訪問基類的私有成員酪刀,而必須通過基類方法進行訪問。
有關(guān)派生類構(gòu)造函數(shù)的要點如下:
1.首先創(chuàng)建基類對象羊壹。
2.派生類構(gòu)造函數(shù)應(yīng)通過成員初始化列表將基類信息傳遞給基類構(gòu)造函數(shù)蓖宦。
3.派生類構(gòu)造函數(shù)應(yīng)初始化派生類新增的數(shù)據(jù)成員。
創(chuàng)建派生類對象時油猫,程序首先調(diào)用基類構(gòu)造函數(shù)稠茂,然后再調(diào)用派生類構(gòu)造函數(shù)∏檠基類構(gòu)造函數(shù)負責(zé)初始化繼承的數(shù)據(jù)成員睬关;派生類構(gòu)造函數(shù)主要用于初始化新增的數(shù)據(jù)成員。派生類的構(gòu)造函數(shù)總是調(diào)用一個基類的構(gòu)造函數(shù)毡证〉绲可以使用初始化列表語法指明要使用的基類構(gòu)造函數(shù),否則將使用默認的基類構(gòu)造函數(shù)料睛。
派生類對象過期時丐箩,程序?qū)⑹紫日{(diào)用派生類析構(gòu)函數(shù),然后在調(diào)用基類析構(gòu)函數(shù)恤煞。
成員初始化列表
派生類構(gòu)造函數(shù)可以使用初始化列表機制將值傳遞給基類構(gòu)造函數(shù)
derived ::derived(type x,type y):base(x,y){
}
其中derived是派生類 base是基類名 x y基類是構(gòu)造函數(shù)變量 屎勘。
同理 基類構(gòu)造函數(shù)也可以這樣做。
基類指針可以在不進行顯式類型轉(zhuǎn)換的情況下指向派生類對象居扒;
基類引用可以在不進行顯式類型轉(zhuǎn)換的情況下指向派生類對象概漱。
然而,基類指針或引用只能用于調(diào)用基類方法喜喂,不能調(diào)用派生類的方法瓤摧。基類聲明的虛函數(shù)除外。
通常,C++要求引用和指針類型與賦給的類型匹配玉吁,但這一規(guī)則對繼承來說是例外照弥。
然而,這種例外只是單向的进副,不可以將基類對象和地址賦給派生類引用和指針产喉。因為派生類指針或引用為基類調(diào)用派生類函數(shù)是沒有意義的。
繼承 is-a關(guān)系
公有繼承是最常用的方式,他建立一種is-a關(guān)系曾沈,即派生類對象也是一個基類對象,可以對基類對象進行的任何操作鸥昏,也可以對派生類對象執(zhí)行塞俱。
多態(tài)公有繼承
有兩種機制可用于實現(xiàn)多態(tài)公有繼承:
1.在派生類中重新定義基類的方法。
2.使用虛方法吏垮。
如果父類子類存在函數(shù)名相同程序?qū)⑹褂脤ο箢愋蛠泶_定使用哪個版本障涯。
如果方法是通過引用或指針而不是對象調(diào)用的,它將確定使哪一種方法膳汪。如果沒有使用關(guān)鍵字virtual唯蝶,程序?qū)⒏鶕?jù)引用類型或指針類型選擇方法;如果使用了virtual遗嗽,程序?qū)⒏鶕?jù)引用或指針指向的對象的類型來選擇方法粘我。
如果要在派生類中重新定義基類的方法,通常應(yīng)將積累方法聲明為虛的痹换。這樣征字,程序?qū)⒏鶕?jù)對象類型而不是引用或指針的類型來選擇方法。為基類聲明一個虛析構(gòu)函數(shù)也是一種慣例娇豫。
虛析構(gòu)函數(shù)可以確保正確的析構(gòu)函數(shù)被調(diào)用(由對象類型來選擇方法而不是指針或引用決定)匙姜。
靜態(tài)聯(lián)編和動態(tài)聯(lián)編
在編譯過程中進行聯(lián)編稱為靜態(tài)聯(lián)編,又稱早期聯(lián)編冯痢。然而氮昧,虛函數(shù)使這項工作變得更困難,使用拿一個函數(shù)是不能在編譯時確定的浦楣,因為編譯器不知道用戶將選擇那種對象袖肥。所以編譯器必須生成能夠在程序運行時選擇正確的虛方法的代碼,這被稱為動態(tài)聯(lián)編椒振,又稱晚期編程昭伸。
將派生類引用或指針轉(zhuǎn)化為基類引用或指針被稱為向上強制轉(zhuǎn)換,這使公有繼承不需要進行顯式類型轉(zhuǎn)換澎迎。
相反的過程——將基類指針或引用轉(zhuǎn)換為派生類指針或引用——成為向下強制轉(zhuǎn)換庐杨。
如果不是顯式類型轉(zhuǎn)換,則向下強制轉(zhuǎn)換是不允許的夹供。原因是is-a關(guān)系通常是不可逆的灵份。
隱式向上強制轉(zhuǎn)換是基類指針或引用可以指向基類對象或派生類對象,因此需要動態(tài)聯(lián)編哮洽。C++使用虛成員函數(shù)來滿足這種需求填渠。
靜態(tài)聯(lián)編的好處 1.效率更高 2.指出不需要重新定義該函數(shù)。這表明,金獎那些語氣將被重新定義的方發(fā)生嗎為虛的氛什。
如果要在派生類中重新定義基類的方法莺葫,則將它設(shè)置為虛方法;否則枪眉,設(shè)置為非虛方法捺檬。
通常編譯器處理虛函數(shù)的方法是:給每個對象添加一個隱藏成員。隱藏成員中保存了一個指向函數(shù)地址數(shù)組的指針贸铜。這個數(shù)組稱為虛函數(shù)表堡纬。虛函數(shù)表中儲存了為類對象進行聲明的虛函數(shù)地址。
使用虛函數(shù)使蒿秦,在內(nèi)存和執(zhí)行速度方面有一定的成本 包括:
1.每個對象都將增大烤镐,增大量為儲存地址的空間;
2.對于每個類棍鳖,編譯器都創(chuàng)建一個虛函數(shù)地址表(數(shù)組)炮叶;
3.對于每個函數(shù)調(diào)用,都需要執(zhí)行意向額外的操作鹊杖,即到表中查找地址悴灵。
1.構(gòu)造函數(shù)不能是虛函數(shù)。創(chuàng)建派生類對象時骂蓖,將調(diào)用派生類的構(gòu)造函數(shù)积瞒,而不是基類的構(gòu)造函數(shù)。
2.析構(gòu)函數(shù)應(yīng)是虛函數(shù)登下,除非類不用做基類茫孔。
否則 當創(chuàng)建基類指針并指向動態(tài)分配的派生類的內(nèi)存時,當釋放這個指針時被芳,將會釋放基類所占的內(nèi)存而不是派生類的缰贝。
所以,通常應(yīng)????給基類提供一個虛析構(gòu)函數(shù)畔濒,即使他并不需要析構(gòu)函數(shù)剩晴。
3.友元不能是虛函數(shù),因為友元不是類成員侵状,而只有成員才能是虛函數(shù)赞弥。可以換種方式使用友元調(diào)用虛成員函數(shù)解決趣兄。
4.重新定義將隱藏方法绽左。
派生類和基類如果出現(xiàn)相同的函數(shù)名,對于派生類的對象來講派生類的函數(shù)將會覆蓋基類的函數(shù)艇潭。
第一 如果重新定義繼承的方法拼窥,應(yīng)確保與原來的原型完全相同戏蔑,但如果返回類型是基類引用或指針,則可以修改為指向派生類的引用或指針(例外)鲁纠。這種特性被稱為返回類型協(xié)變总棵,因為允許返回類型隨類類型的變化而變化。第二房交,如果基類聲明被重載了彻舰,則應(yīng)在派生類中重新定義所有的基類版本。
private和protected之間的區(qū)別只有在基類派生的類中才會表現(xiàn)出來候味。(派生類的成員可以直接訪問基類的保護成員但不能直接訪問基類的私有成員)因此,對于外部世界來說
保護成員的行為與私有成員相似隔心;但對于派生類來說白群,保護成員的行為與公有成員相似。最好對類數(shù)據(jù)成員采用私有訪問控制硬霍,不要使用保護訪問控制帜慢;同時通過基類方法使派生類能夠訪問基類數(shù)據(jù)。
抽象基類
當類聲明中包含純虛函數(shù)時唯卖,則不能創(chuàng)建該類的對象粱玲。這里的理念是,包含純虛函數(shù)的類只用作基類拜轨。
由含有純虛函數(shù)的基類派生出來的類叫做具體類抽减,這表示可以創(chuàng)建這些類型的對象。
在設(shè)計ABC之前橄碾,首先應(yīng)開發(fā)一個模型——指出編程問題所需的類以及他們之間的相互關(guān)系卵沉。一種學(xué)院派思想認為,如果要設(shè)計類繼承層次法牲,則只能將那些不會被用作基類的類設(shè)計為具體的類史汗。這種方法的設(shè)計更清晰,復(fù)雜程度更低拒垃。
ABC要求具體派生類覆蓋其純虛函數(shù)——破事派生類遵循ABC設(shè)置的接口規(guī)則停撞。
繼承和動態(tài)內(nèi)存分配
第一種情況:派生類不使用new
基類聲明中包含了構(gòu)造函數(shù)使用new時需要的特殊方法:析構(gòu)函數(shù)、復(fù)制構(gòu)造函數(shù)悼瓮、重載賦值運算符戈毒。那么派生類就不需要再次定義上述這些。
派生類的析構(gòu)函數(shù)總是要進行一些操作:執(zhí)行自身的代碼后調(diào)用基類析構(gòu)函數(shù)谤牡。
在復(fù)制類成員或繼承的類組件時副硅,則是使用該類的復(fù)制構(gòu)造函數(shù)完成的。
類的默認賦值運算符將自動使用基類的復(fù)制運算符來對基類組件進行賦值翅萤。
第二種情況:派生類使用new
這種情況下恐疲,必須為派生類定義顯式析構(gòu)函數(shù)腊满、賦值構(gòu)造函數(shù)和賦值運算符。
派生類析構(gòu)函數(shù)自動調(diào)用基類的析構(gòu)函數(shù)培己,故其自身的職責(zé)是對派生類構(gòu)造函數(shù)執(zhí)行工作的進行清理碳蛋。
類設(shè)計回顧...
(完)