C++類的繼承與派生

轉(zhuǎn)自大神博客凡程子

一施逾、基本概念

  1. 類的繼承,是新的類從已有類那里得到已有的特性呈野〉桶或從已有類產(chǎn)生新類的過程就是類的派生,原有的類稱為基類或父類被冒,產(chǎn)生的新類稱為派生類或子類军掂。
  2. 派生類的聲明:
    class 派生類名 : 繼承方式 基類名1,繼承方式 基類名2昨悼,...蝗锥,繼承方式 基類名n
    {
    派生類成員聲明;
    }
  3. 一個(gè)派生類可以同時(shí)有多個(gè)基類率触,這種情況稱為多重繼承终议,派生類只有一個(gè)基類,稱為單繼承葱蝗,直接派生穴张,間接派生。
  4. 繼承方式規(guī)定了如何訪問基類繼承的成員两曼。繼承方式有public皂甘,private,protected悼凑。如果不顯示給出繼承方式偿枕,默認(rèn)為private繼承。繼承方式指定了派生類成員以及類外對(duì)象對(duì)于從基類繼承來的成員的訪問權(quán)限户辫。
  5. 派生類繼承基類中除構(gòu)造和析構(gòu)函數(shù)以外的所有成員益老。
  6. 派生類生成:
    • 吸收基類成員(除構(gòu)造析構(gòu)函數(shù)以外的所有成員)
    • 改造基類成員(根據(jù)繼承方式調(diào)整基類成員的訪問,函數(shù)在子類中的覆蓋寸莫,以及虛函數(shù)在子類中的覆蓋)
    • 添加新的成員
  7. public繼承(基類的private不是我的private)
    當(dāng)類的繼承方式為公有繼承時(shí)捺萌,基類的公有和保護(hù)成員的訪問屬性在派生類中不變,而基類的私有成員不可訪問膘茎。即基類的公有成員和保護(hù)成員被繼承到派生類中仍作為派生類的公有成員和保護(hù)成員桃纯。派生類的其他成員可以直接訪問它們。無論派生類的成員還是派生類的對(duì)象都無法訪問基類的私有成員披坏。
  8. private繼承
    當(dāng)類的繼承方式為私有繼承時(shí)态坦,基類中的公有成員和保護(hù)成員都以私有成員身份出現(xiàn)在派生類中,而基類的私有成員在派生類中不可訪問棒拂∩√荩基類的公有成員和保護(hù)成員被繼承后作為派生類的私有成員玫氢,派生類的其他成員可以直接訪問它們,但是在類外部通過派生類的對(duì)象無法訪問谜诫。無論是派生類的成員還是通過派生類的對(duì)象漾峡,都無法訪問從基類繼承的私有成員。通過多次私有繼承后喻旷,對(duì)于基類的成員都會(huì)成為不可訪問生逸。因此私有繼承比較少用。
  9. 保護(hù)繼承
    保護(hù)繼承中且预,基類的公有成員和私有成員都以保護(hù)成員的身份出現(xiàn)在派生類中槽袄,而基類的私有成員不可訪問。派生類的其他成員可以直接訪問從基類繼承來的公有和保護(hù)成員锋谐,但是類外部通過派生類的對(duì)象無法訪問它們遍尺,無論派生類的成員還是派生類的對(duì)象,都無法訪問基類的私有成員涮拗。

二狮鸭、派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)

1.派生類中由基類繼承而來的成員的初始化工作還是由基類的構(gòu)造函數(shù)完成,然后派生類中新增的成員在派生類的構(gòu)造函數(shù)中初始化

  1. 派生類構(gòu)造函數(shù)的語法
    派生類名::派生類名(參數(shù)總表):基類名1(參數(shù)表1)多搀,基類名(參數(shù)名2)....基類名n(參數(shù)名n)歧蕉,內(nèi)嵌子對(duì)象1(參數(shù)表1),內(nèi)嵌子對(duì)象2(參數(shù)表2)....內(nèi)嵌子對(duì)象n(參數(shù)表n)
    {
    派生類新增成員的初始化語句康铭;
    }
    注意:構(gòu)造函數(shù)的初始化順序并不以上面的順序進(jìn)行惯退,而是根據(jù)聲明的順序初始化
  2. 如果基類中沒有不帶參數(shù)的構(gòu)造函數(shù)(且參數(shù)沒有默認(rèn)初值),也可以說从藤,只有帶參數(shù)的構(gòu)造函數(shù)催跪,那么在派生類的構(gòu)造函數(shù)初始化列表里中必須調(diào)用基類構(gòu)造函數(shù),以初始化基類成員
  3. 派生類構(gòu)造函數(shù)執(zhí)行的次序:
    • 調(diào)用基類構(gòu)造函數(shù)夷野,調(diào)用順序按照它們被繼承時(shí)聲明的順序(從左到右)
    • 調(diào)用內(nèi)嵌成員對(duì)象的構(gòu)造函數(shù)懊蒸,調(diào)用順序按照它們?cè)陬愔新暶鞯捻樞?/li>
    • 派生類的構(gòu)造函數(shù)體中的內(nèi)容
      例子:
#include <iostream>
#include <time.h>
using namespace std;

class B1
{
public:
    B1(int i)
    {
        cout<<"constructing B1 "<<i<<endl;
    }
};

class B2
{
public:
    B2(int j)
    {
        cout<<"constructing B2 "<<j<<endl;
    }
};

class B3
{
public:
    B3()
    {
        cout<<"constructing B3"<<endl;
    }
};

class C: public B2, public B1, public B3
{
public:
    C(int a, int b, int c, int d):B1(a), memberB2(d), memberB1(c),B2(b)
    {

    }
private:
    B1 memberB1;
    B2 memberB2;
    B3 memberB3;
};

int main() 
{ 
    C obj(1,2,3,4);

    return 0; 
}

輸出結(jié)果為:
constructing B2 2
constructing B1 1
constructing B3
constructing B1 3
constructing B2 4
constructing B3

  1. 析構(gòu)函數(shù)
    派生類的析構(gòu)函數(shù)的功能是在該對(duì)象消亡之前進(jìn)行一些必要的清理工作,析構(gòu)函數(shù)沒有類型悯搔,也沒有參數(shù)骑丸。析構(gòu)函數(shù)的執(zhí)行順序與構(gòu)造函數(shù)相反。
#include <iostream>
#include <time.h>
using namespace std;

class B1
{
public:
    B1(int i)
    {
        cout<<"constructing B1 "<<i<<endl;
    }
    ~B1()
    {
        cout<<"destructing B1"<<endl;
    }
};

class B2
{
public:
    B2(int j)
    {
        cout<<"constructing B2 "<<j<<endl;
    }
    ~B2()
    {
        cout<<"destructing B2"<<endl;
    }
};

class B3
{
public:
    B3()
    {
        cout<<"constructing B3"<<endl;
    }
    ~B3()
    {
        cout<<"destructing B3"<<endl;
    }
};

class C: public B2, public B1, public B3
{
public:
    C(int a, int b, int c, int d):B1(a), memberB2(d), memberB1(c),B2(b)
    {

    }
private:
    B1 memberB1;
    B2 memberB2;
    B3 memberB3;
};

int main() 
{ 
    C obj(1,2,3,4);

    return 0; 
}

輸出結(jié)果為:
constructing B2 2
constructing B1 1
constructing B3
constructing B1 3
constructing B2 4
constructing B3
destructing B3
destructing B2
destructing B1
destructing B3
destructing B1
destructing B2

三妒貌、派生類成員的標(biāo)識(shí)和訪問

  1. 派生類成員屬性劃分為四種:不可訪問的成員通危,私有成員,保護(hù)成員灌曙,公有成員
  2. 作用域分辨
    形式為:基類名::成員名菊碟;基類名::成員名(參數(shù)表)
    如果某派生類的多個(gè)基類擁有同名的成員,同時(shí)派生類又新增這樣的同名成員在刺,在這種情況下逆害,派生類成員將隱藏所有基類的同名成員头镊,這就需要上面的調(diào)用方式才能調(diào)用基類的同名成員。
    例子:多繼承同名
#include <iostream>
#include <time.h>
using namespace std;

class B1
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B1 "<<nV<<endl;
    }
};

class B2
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B2 "<<nV<<endl;
    }
};

class D1: public B1, public B2
{
public:
    int nV;
    void fun()
    {
        cout<<"member of D1 "<<nV<<endl;
    }
};

int main() 
{ 
    D1 d1;
    d1.nV = 1;
    d1.fun();
    d1.B1::nV = 2;
    d1.B1::fun();
    d1.B2::nV = 3;
    d1.B2::fun();

    return 0; 
}

輸出結(jié)果為:
member of D1 1
member of B1 2
member of B2 3
以上通過作用域分辨符魄幕,解決了訪問基類中被屏蔽的同名成員相艇。

  1. 如果某個(gè)派生類的部分或全部直接基類是從另一個(gè)共同的基類派生而來,在這些直接基類中梅垄,從上一級(jí)基類繼承來的成員就擁有相同的名稱,因此派生類中也就會(huì)產(chǎn)生同名現(xiàn)象输玷,對(duì)這種類型的同名成員也要使用作用域分辨符來唯一標(biāo)識(shí)队丝,而且必須用直接基類進(jìn)行限定。
#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B0 "<<nV<<endl;
    }
};

class B1:public B0
{
public:
    int nV1;
};

class B2:public B0
{
public:
    int nV2;
};

class D1:public B1, public B2    //B1 B2是直接基類
{
public:
    int nVd;
    void fund()
    {
        cout<<"member of D1"<<endl;
    }
};

int main() 
{ 
    D1 d1;
    d1.B1::nV = 2;
    d1.B1::fun();
    d1.B2::nV = 3;
    d1.B2::fun();

    return 0; 
}

輸出結(jié)果為:
member of B0 2
member of B0 3
在這種情況下欲鹏,派生類對(duì)象在內(nèi)存中就同時(shí)擁有成員nV及fun的兩份拷貝机久。但是很多情況下,我們只需要這樣一個(gè)這樣的數(shù)據(jù)拷貝赔嚎,同一成員的多份拷貝增加了內(nèi)存的開銷膘盖。可以通過虛函數(shù)來解決這個(gè)問題尤误。

  1. 虛基類(針對(duì)多重繼承
    為了解決前面提到的多重拷貝的問題侠畔,可以將共同基類設(shè)置為虛基類,這時(shí)從不同的路徑繼承過來的同名數(shù)據(jù)成員在內(nèi)存中就只有一個(gè)拷貝损晤,同一個(gè)函數(shù)也只有一個(gè)映射软棺。
    虛基類的聲明是在派生類的聲明過程,其語法形式為:
    class 派生類名::virtual 繼承方式 基類名尤勋;
    例子:
#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B0 "<<nV<<endl;
    }
};

class B1:virtual public B0
{
public:
    int nV1;
};

class B2:virtual public B0
{
public:
    int nV2;
};

class D1:public B1, public B2
{
public:
    int nVd;
    void fund()
    {
        cout<<"member of D1"<<endl;
    }
};

int main() 
{ 
    D1 d1;
    d1.nV = 2;
    d1.fun();

    return 0; 
}

輸出結(jié)果為:
member of B0 2

  1. 虛函數(shù)及其派生類的構(gòu)造函數(shù)
    一般而言喘落,派生類只對(duì)其直接基類的構(gòu)造函數(shù)傳遞參數(shù),但是在虛基類中最冰,不管是直接或間接虛基類的所有派生類瘦棋,都必須在構(gòu)造函數(shù)的成員初始化列表中列出對(duì)虛基類的初始化。
#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    B0(int n)
    {
        nV = n;
    }
    int nV;
    void fun()
    {
        cout<<"member of B0 "<<nV<<endl;
    }
};

class B1:virtual public B0
{
public:
    B1(int a):B0(a)   
    {
    }
    int nV1;
};

class B2:virtual public B0
{
public:
    B2(int a):B0(a)
    {
    }
    int nV2;
};

class D1:public B1, public B2
{
public:
    D1(int a):B0(a), B1(a), B2(a)
    {
    }
    int nVd;
    void fund()
    {
        cout<<"member of D1"<<endl;
    }
};

int main() 
{ 
    D1 d1(1);
    d1.nV = 2;
    d1.fun();

    return 0; 
}

以上例子看上去B0的構(gòu)造函數(shù)好像被調(diào)用了三次暖哨,但是實(shí)際上只有D1類中的D1(int a):B0(a), B1(a), B2(a)
才是真正的調(diào)用了B0構(gòu)造函數(shù)赌朋。

四、賦值兼容規(guī)則

  1. 賦值兼容規(guī)則是指在需要基類對(duì)象的任何地方都可以使用公有派生類的對(duì)象來替代篇裁。
  2. 賦值兼容規(guī)則所指的替代包括:
    • 派生類的對(duì)象可以賦值給基類對(duì)象
    • 派生類的對(duì)象可以初始化基類的引用
    • 派生類對(duì)象的地址可以賦給指向基類的指針
    • 在替代之后箕慧,派生類對(duì)象就可以作為基類的對(duì)象使用,但只能使用從基類繼承的成員茴恰。

例子:

#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    void display()
    {
        cout<<"B0::display()"<<endl;
    }
};

class B1:public B0
{
public:
    void display()
    {
        cout<<"B1::display()"<<endl;
    }
};

class B2:public B0
{
public:
    void display()
    {
        cout<<"B2::display()"<<endl;
    }
};

void fun(B0 *ptr)
{
    ptr->display();
}

int main() 
{ 
    B0 b0;
    B1 b1;
    B2 b2;
    fun(&b0);
    b0 = b1;
    fun(&b0);
    b0 = b2;
    fun(&b0);

    return 0; 
}

輸出結(jié)果為:
B0::display()
B0::display()
B0::display()

通過這種賦值兼容后颠焦,每次調(diào)用的同名函數(shù)都是基類的同名函數(shù),如果想調(diào)用派生類的往枣,則需要使用虛函數(shù)伐庭。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末粉渠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子圾另,更是在濱河造成了極大的恐慌霸株,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件集乔,死亡現(xiàn)場(chǎng)離奇詭異去件,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扰路,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門尤溜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人汗唱,你說我怎么就攤上這事宫莱。” “怎么了哩罪?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵授霸,是天一觀的道長。 經(jīng)常有香客問我际插,道長碘耳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任框弛,我火速辦了婚禮藏畅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘功咒。我一直安慰自己愉阎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布力奋。 她就那樣靜靜地躺著榜旦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪景殷。 梳的紋絲不亂的頭發(fā)上溅呢,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音猿挚,去河邊找鬼咐旧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绩蜻,可吹牛的內(nèi)容都是我干的铣墨。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼办绝,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼伊约!你這毒婦竟也來了姚淆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤屡律,失蹤者是張志新(化名)和其女友劉穎腌逢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體超埋,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搏讶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了霍殴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片媒惕。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖繁成,靈堂內(nèi)的尸體忽然破棺而出吓笙,到底是詐尸還是另有隱情淑玫,我是刑警寧澤巾腕,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站絮蒿,受9級(jí)特大地震影響尊搬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜土涝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一佛寿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧但壮,春花似錦冀泻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至溯祸,卻和暖如春肢专,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背焦辅。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國打工博杖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筷登。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓剃根,卻偏偏與公主長得像,于是被迫代替她去往敵國和親前方。 傳聞我的和親對(duì)象是個(gè)殘疾皇子跟继,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容