雖然C++中有頭文件機(jī)制使得代碼重用十分高效,但是,文件層面的相互包含(include)仍舊顯得太過(guò)笨重。
同時(shí),面向?qū)ο蟮木幊虒哟卧絹?lái)越清晰,在萬(wàn)物皆可實(shí)例化的時(shí)代里,繼承的出現(xiàn)就成為必然。
1.繼承的定義
在C++語(yǔ)言中,一個(gè)派生類(lèi)可以從一個(gè)基類(lèi)派生,也可以從多個(gè)基類(lèi)派生。從一個(gè)基類(lèi)派生的繼承稱(chēng)為單繼承;從多個(gè)基類(lèi)派生的繼承稱(chēng)為多繼承。
這樣,采用編程內(nèi)部的自動(dòng)化重用機(jī)制,是程序的編寫(xiě)和重用,以及對(duì)象的描述,更為簡(jiǎn)潔高效。
也有利于,操作和數(shù)據(jù)的保護(hù),也有利于源代碼的保護(hù)。
繼承時(shí),子類(lèi)擁有父類(lèi)的所有成員,但是會(huì)受到一定的訪問(wèn)限制。
同時(shí),子類(lèi)也可以擁有自己的數(shù)據(jù)成員,和,修改通過(guò)繼承得來(lái)的成員(函數(shù),數(shù)據(jù))。這就暗示著,子類(lèi)的成員一定多于父類(lèi)。
語(yǔ)法:
單繼承的定義格式如下:
class<派生類(lèi)名>:<繼承方式><基類(lèi)名>
{
<派生類(lèi)新定義成員>
};
多繼承的定義格式如下:
class<派生類(lèi)名>:<繼承方式1><基類(lèi)名1>,<繼承方式2><基類(lèi)名2>,…
{
<派生類(lèi)新定義成員>
};
2.繼承的訪問(wèn)控制
繼承方式:
public 公有化繼承 : 子類(lèi)將父類(lèi)的公有成員 和 保護(hù)成員 作為自己的公有成員
protected 保護(hù)繼承 : 子類(lèi)將父類(lèi)的公有成員 和 保護(hù)成員 作為自己的保護(hù)成員
private 私有化繼承 : 子類(lèi)將父類(lèi)的公有成員 和 保護(hù)成員 作為自己的私有成員
子類(lèi)對(duì)父類(lèi)的訪問(wèn):
// jPG
一般來(lái)說(shuō),保護(hù)數(shù)據(jù)成員可以被子類(lèi)訪問(wèn)而不可被外界訪問(wèn)。事實(shí)上,任何成熟的類(lèi)設(shè)計(jì),都不應(yīng)使用保護(hù)成員,而僅僅有 public 和 private。
基類(lèi)的私有成員即使對(duì)自己的子類(lèi)也保密。就像保險(xiǎn)柜里父母年輕時(shí)代的情書(shū)。
3.繼承的各種對(duì)象成員初始化和構(gòu)造順序(僅考慮對(duì)象)
1. 任何虛擬基類(lèi)的構(gòu)造函數(shù)按照他們被繼承的順序構(gòu)造
2. 任何非虛擬基類(lèi)的構(gòu)造函數(shù)按他們被繼承的順序構(gòu)造
3. 任何成員對(duì)象的構(gòu)造函數(shù)按照他們聲明的順序構(gòu)造
4. 類(lèi)自己的構(gòu)造函數(shù)
4.繼承的構(gòu)造函數(shù)和析構(gòu)函數(shù)
繼承不僅僅繼承父類(lèi)的成員屬性,也繼承父類(lèi)的成員函數(shù),可以說(shuō),子類(lèi)繼承了父類(lèi)的一切。其構(gòu)造函數(shù)也不例外。
當(dāng)子類(lèi) 新定義了構(gòu)造函數(shù),初始化時(shí)就調(diào)用子類(lèi)的相應(yīng)的構(gòu)造函數(shù)。
若子類(lèi) 沒(méi)有定義自己的構(gòu)造函數(shù),初始化時(shí)就調(diào)用父類(lèi)的相應(yīng)的構(gòu)造函數(shù)。
若父類(lèi)也沒(méi)有,就調(diào)用父類(lèi)的父類(lèi)的相應(yīng)的構(gòu)造函數(shù)。
即:子類(lèi)沒(méi)有的,就向父類(lèi)找。
子類(lèi)的構(gòu)造函數(shù)在調(diào)用時(shí),在還沒(méi)有執(zhí)行構(gòu)造函數(shù)體之前,立即調(diào)用基類(lèi)的構(gòu)造函數(shù)。如果基類(lèi)的構(gòu)造函數(shù)在初始化列表中,就按照初始化列表的調(diào)用形式來(lái);否則,就調(diào)用相應(yīng)基類(lèi)的構(gòu)造函數(shù)。
基類(lèi)上面如果還有基類(lèi),則會(huì)優(yōu)先調(diào)用上面的基類(lèi)的構(gòu)造函數(shù)。
做完類(lèi) 的構(gòu)造,接下來(lái)給自身的對(duì)象本體分配空間,進(jìn)而調(diào)用對(duì)象中對(duì)象成員的構(gòu)造函數(shù),一邊調(diào)用一邊分配空間。有多個(gè)對(duì)象成員,則按聲明順序調(diào)用。
每個(gè)構(gòu)造函數(shù)的調(diào)用,總是先分配對(duì)象本體的空間,給出該空間的this指針。就先一層層蓋樓一樣,先蓋好下面的基類(lèi),再蓋好當(dāng)前層的房間(成員),這是一個(gè)不斷遞歸的過(guò)程。
對(duì)象的析構(gòu)順序,和對(duì)象構(gòu)造順序嚴(yán)格相反。
5.多繼承
有時(shí)候,我們僅僅通過(guò)一個(gè)類(lèi)的繼承還遠(yuǎn)遠(yuǎn)滿足不了描述實(shí)體的功能,就像沙發(fā)床一樣,既具有床類(lèi)的特性,又具有沙發(fā)類(lèi)的特性,而我們又不值得新設(shè)計(jì)一個(gè)類(lèi)來(lái)描述ta,我們可以使用多繼承的方法來(lái)描述ta。
多繼承的格式如下:
class<派生類(lèi)名>:<繼承方式1><基類(lèi)名1>,<繼承方式2><基類(lèi)名2>,…
{
<派生類(lèi)新定義成員>
};
這樣子類(lèi)就有了多個(gè)父類(lèi)所具有的一切屬性。
但是,問(wèn)題來(lái)了:
當(dāng)兩個(gè)父類(lèi)的函數(shù)或成員屬性重名時(shí),該怎么辦?
有兩個(gè)方法:
第一個(gè)方法是:使用這樣的格式:father_class_name::function_or_argument
用父類(lèi)的名字來(lái)區(qū)分;
第二個(gè)方法是:虛擬繼承
6.虛擬繼承
事實(shí)上,可以在兩個(gè)父類(lèi)上面增加一個(gè)(祖)父類(lèi),來(lái)統(tǒng)一兩個(gè)功能相似或者一樣的成員:
床類(lèi) 和 沙發(fā)類(lèi) 同屬于 家具類(lèi),家具類(lèi) 有重量這一屬性,就不必在床和沙發(fā)類(lèi)中定義重量。
但是,這樣沙發(fā)床類(lèi)在繼承父類(lèi)時(shí),兩個(gè)父類(lèi)會(huì)分別有一個(gè)相同的父類(lèi),所得到的重量屬性仍舊是兩個(gè)。

這時(shí)就要用到——虛擬繼承。
其功能大致上是,將兩個(gè)父類(lèi)說(shuō)明繼承自同一個(gè)父類(lèi),擁有共有的屬性。

其用法如下:
class father1:virtual public grandfather
{
...
}
class father2:virtual public grandfather
{
...
}
class son:public father1,public father2
{
...
}
這樣就解決了問(wèn)題。
但是,一個(gè)成熟的類(lèi)設(shè)計(jì),作為經(jīng)驗(yàn)之談,應(yīng)避免多繼承