C++學(xué)習(xí)(6)多態(tài)

1.虛函數(shù)和多態(tài)

  • 在類的定義中,前面有virtual關(guān)鍵字的成員函數(shù)就是虛函數(shù)败徊。
  • virtual關(guān)鍵字只用在類定義里的函數(shù)說明中尿这,寫函數(shù)體時不用。

  • 多態(tài)的表現(xiàn)形式一
    ?派生類的指針可以賦給基類指針蝙斜。
    ?通過基類指針調(diào)用基類和派生類中的同名虛函數(shù)時:
    (1)若該指針指向一個基類的對象,那么被調(diào)用是
    基類的虛函數(shù)澎胡;
    (2)若該指針指向一個派生類的對象孕荠,那么被調(diào)用
    的是派生類的虛函數(shù)绢片。
    這種機(jī)制就叫做“多態(tài)”。
class CBase {
public:
    virtual void SomeVirtualFunction() { }
};
class CDerived :public CBase {
public:
    virtual void SomeVirtualFunction() { }
};
int main() {
    CDerived ODerived;
    CBase * p = &ODerived;
    p->SomeVirtualFunction(); //調(diào)用哪個虛函數(shù)取決于p指向哪種類型的對象
    return 0;
}

  • 多態(tài)的表現(xiàn)形式二
    ?派生類的對象可以賦給基類引用
    ?通過基類引用調(diào)用基類和派生類中的同名虛函數(shù)時:
    (1)若該引用引用的是一個基類的對象岛琼,那么被調(diào)
    用是基類的虛函數(shù)底循;
    (2)若該引用引用的是一個派生類的對象,那么被
    調(diào)用的是派生類的虛函數(shù)槐瑞。
    這種機(jī)制也叫做“多態(tài)”熙涤。
class CBase {
public:
    virtual void SomeVirtualFunction() { }
};
class CDerived :public CBase {
public:
    virtual void SomeVirtualFunction() { }
};
int main() {
    CDerived ODerived;
    CBase & r = ODerived;
    r.SomeVirtualFunction(); //調(diào)用哪個虛函數(shù)取決于r引用哪種類型的對象
    return 0;
}

  • 多態(tài)的作用
    在面向?qū)ο蟮某绦蛟O(shè)計中使用多態(tài),能夠增強(qiáng)程序的可擴(kuò)充性困檩,即程序需要修改或增加功能的時候祠挫,需要改動和增加的代碼較少。

用基類指針數(shù)組存放指向各種派生類對象的指針悼沿,然后遍歷該數(shù)組等舔,就能對各個派生類對象做各種操作,是很常用的做法

  • 構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛函數(shù)
    在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛函數(shù)糟趾,不是多態(tài)慌植。編譯時即可確定,調(diào)用的函數(shù)是自己的類或基類中定義的函數(shù)义郑,不會等到運(yùn)行時才決定調(diào)用自己的還是派生類的函數(shù)蝶柿。

2.多態(tài)的實現(xiàn)原理

“多態(tài)” 的關(guān)鍵在于通過基類指針或引用調(diào)用
一個虛函數(shù)時,編譯時不確定到底調(diào)用的是基類還是派生類的函數(shù)非驮,運(yùn)行時才確定 ---- 這叫“動態(tài)聯(lián)編” 交汤。

  • 多態(tài)實現(xiàn)的關(guān)鍵 --- 虛函數(shù)表
    每一個有虛函數(shù)的類(或有虛函數(shù)的類的派生類)都有一個虛函數(shù)表,該類的任何對象中都放著虛函數(shù)表的指針劫笙。虛函數(shù)表中列出了該類的虛函數(shù)地址芙扎。 多出來的4個字節(jié)就是用來放虛函數(shù)表的地址的。


    批注 2020-08-13 221906.png

3.虛析構(gòu)函數(shù)

  • 通過基類的指針刪除派生類對象時填大,通常情況下只調(diào)用基類的析構(gòu)函數(shù)
    ? 但是戒洼,刪除一個派生類的對象時,應(yīng)該先調(diào)用派生類的析構(gòu)函數(shù)栋盹,然后調(diào)用基類的析構(gòu)函數(shù)施逾。
    ?解決辦法:把基類的析構(gòu)函數(shù)聲明為virtual
    ? 派生類的析構(gòu)函數(shù)可以virtual不進(jìn)行聲明
    ? 通過基類的指針刪除派生類對象時敷矫,首先調(diào)用派生類的析構(gòu)函數(shù)例获,然后調(diào)用基類的析構(gòu)函數(shù)
    ? 一般來說,一個類如果定義了虛函數(shù)曹仗,則應(yīng)該將析構(gòu)函數(shù)也定義成虛函數(shù)榨汤。或者怎茫,一個類打算作為基類使用收壕,也應(yīng)該將析構(gòu)函數(shù)定義成虛函數(shù)妓灌。
    注意: 不允許以虛函數(shù)作為構(gòu)造函數(shù)
class son {
public:
    ~son() { cout << "bye from son" << endl; };
};
class grandson :public son {
public:
    ~grandson() { cout << "bye from grandson" << endl; };
};
int main() {
    son *pson;
    pson = new grandson();
    delete pson;
    return 0;
}
//輸出: bye from son 沒有執(zhí)行g(shù)randson::~grandson()!!!
class son {
public:
    virtual ~son() { cout << "bye from son" << endl; };
};
class grandson :public son {
public:
    ~grandson() { cout << "bye from grandson" << endl; };
};
int main() {
    son *pson;
    pson = new grandson();
    delete pson;
    return 0;
}
//輸出: bye from grandson
//bye from son
//執(zhí)行g(shù)randson::~grandson(),引起執(zhí)行son::~son()C巯堋3婀 !

4.純虛函數(shù)和抽象類

? 純虛函數(shù): 沒有函數(shù)體的虛函數(shù)

class A {
private: int a;
public:
    virtual void Print() = 0; //純虛函數(shù)
    void fun() { cout << "fun"; }
};
  • 包含純虛函數(shù)的類叫抽象類
    ? 抽象類只能作為基類來派生新類使用圃验,不能創(chuàng)建抽象類的對象
    ? 抽象類的指針和引用可以指向由抽象類派生出來的類的對象
A a ; // 錯掉伏, A 是抽象類,不能創(chuàng)建對象
A * pa ; // ok,可以定義抽象類的指針和引用
pa = new A ; //錯誤, A 是抽象類澳窑,不能創(chuàng)建對象
  • 在抽象類的成員函數(shù)內(nèi)可以調(diào)用純虛函數(shù)斧散,但是在構(gòu)造函數(shù)或析構(gòu)函數(shù)內(nèi)部
    不能調(diào)用純虛函數(shù)。
  • 如果一個類從抽象類派生而來摊聋,那么當(dāng)且僅當(dāng)它實現(xiàn)了基類中的所有純虛函
    數(shù)鸡捐,它才能成為非抽象類。
class A {
public:
    virtual void f() = 0; //純虛函數(shù)
    void g() {
        this->f(); //ok
    }
    A() { //f( ); // 錯誤
    }
};
class B :public A {
public:
    void f() { cout << "B:f()" << endl; }
};
int main() {
    B b;
    b.g();
    return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麻裁,一起剝皮案震驚了整個濱河市箍镜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌煎源,老刑警劉巖鹿寨,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異薪夕,居然都是意外死亡脚草,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門原献,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馏慨,“玉大人,你說我怎么就攤上這事姑隅⌒戳ィ” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵讲仰,是天一觀的道長慕趴。 經(jīng)常有香客問我,道長鄙陡,這世上最難降的妖魔是什么冕房? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮趁矾,結(jié)果婚禮上耙册,老公的妹妹穿的比我還像新娘。我一直安慰自己毫捣,他們只是感情好详拙,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布帝际。 她就那樣靜靜地躺著,像睡著了一般饶辙。 火紅的嫁衣襯著肌膚如雪蹲诀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天弃揽,我揣著相機(jī)與錄音侧甫,去河邊找鬼。 笑死蹋宦,一個胖子當(dāng)著我的面吹牛披粟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播冷冗,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼守屉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蒿辙?” 一聲冷哼從身側(cè)響起拇泛,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎思灌,沒想到半個月后俺叭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡泰偿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年熄守,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耗跛。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡裕照,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出调塌,到底是詐尸還是另有隱情晋南,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布羔砾,位于F島的核電站负间,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏姜凄。R本人自食惡果不足惜政溃,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望檀葛。 院中可真熱鬧玩祟,春花似錦、人聲如沸屿聋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽润讥。三九已至转锈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間楚殿,已是汗流浹背撮慨。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留脆粥,地道東北人砌溺。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像变隔,于是被迫代替她去往敵國和親规伐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348