C++中的(純)虛函數(shù)

簡介

本章節(jié)會介紹在C++中虛函數(shù)純虛函數(shù)的主要作用腾它,C++也是通過虛函數(shù)實現(xiàn)動態(tài)綁定报亩,本小節(jié)不會去講述動態(tài)綁定內(nèi)部實現(xiàn)原理吕座,具體可以參考[C++動態(tài)綁定原理].

結(jié)構(gòu)圖

  • 虛函數(shù)
    • 成員函數(shù)(member function)為虛函數(shù)(virtual function)
    • 析構(gòu)函數(shù)為虛函數(shù)
  • 純虛函數(shù)
    • 成員函數(shù)為純虛函數(shù)(pure virtual function)
    • 析構(gòu)函數(shù)為純虛函數(shù)

虛函數(shù)

  • 成員函數(shù)為虛函數(shù)

    在開始虛函數(shù)之前匣沼,先看一段代碼分析其中的問題。

#include <iostream>
class Animal {
public:
    Animal() {}
    ~Animal(){}
    void run(void) {
        std::cout << "Animal run..." << std::endl;
    }
};

class Cat : public Animal{
public:
    Cat() : Animal(){}
    void run(void) {
        std::cout << "Cat run..." << std::endl;
    }
};
int main(int argc,char** argv)
{
    Animal *animal = new Cat; //創(chuàng)建Cat對象雷酪,然后執(zhí)行向上類型轉(zhuǎn)換
    animal->run();
    return 0;
}
/*輸出結(jié)果*/
//Animal run...

在以上代碼中淑仆,animal所指向的為Cat對象,但是當(dāng)調(diào) 用run函數(shù)的時候哥力,打印的值是"Animal run...",并不是"Cat run...",這是因為當(dāng)編譯器看到"animal"的指針類型是"Animal"時蔗怠,自然而然的就會調(diào)用Animal::run(),在編譯時期,就已經(jīng)確定所要調(diào)用的具體函數(shù)吩跋,這也就是所說的靜態(tài)綁定蟀淮。

在開始后面講解之前,需要先記住兩點知識:
1. 聲明一個虛函數(shù)需要使用關(guān)鍵字:virtual
2. 當(dāng)基類(或稱為父類)中的某函數(shù)A()被聲明為虛函數(shù)之后钞澳,在繼生類(或稱為子類)中重載的A(),即不使用virtual修飾,也是虛函數(shù)

現(xiàn)在對上面的代碼進行修改涨缚,將void Animal::run()修改為虛函數(shù)轧粟,即改為virtual void Animal::run(),觀察修改后的運行情況策治。

#include <iostream>
class Animal {
public:
    Animal() {}
    ~Animal() {}
    virtual void run(void) {  //!!!!!!!!!!注意此處的修改
        std::cout << "Animal run..." << std::endl;
    }
};

class Cat : public Animal {
public:
    Cat() : Animal() {}
    void run(void) {
        std::cout << "Cat run..." << std::endl;
    }
};
int main(int argc, char** argv)
{
    Animal *animal = new Cat; //創(chuàng)建Cat對象,然后執(zhí)行向上類型轉(zhuǎn)換
    animal->run();
    return 0;
}
//輸出結(jié)果:
//Cat run...

當(dāng)Animal::run()為虛函數(shù)時兰吟,輸出結(jié)果為Cat run...,這也就是虛函數(shù)的作用通惫,此時在程序運行時去決定調(diào)用哪一個run()函數(shù),這也就是動態(tài)綁定混蔼。在這里animal實際上指向的是Cat對象履腋,所以調(diào)用的是Cat::run()

  • 析構(gòu)函數(shù)為虛函數(shù)

    當(dāng)基類中包含虛成員函數(shù)的時候惭嚣,一般會把析構(gòu)函數(shù)
    也定義為虛析構(gòu)函數(shù)

    虛析構(gòu)函數(shù)虛成員函數(shù)在函數(shù)定義上是一樣的遵湖,只需要添加virtual關(guān)鍵字就可以了,這里主要介紹定義虛析構(gòu)函數(shù)的原因:

    1. 為了通過基類指針正確釋放該指針?biāo)赶虻膶ο?該指針可能指向一個子類)

    通過實例了解一下:

#include <iostream>
class Base1 {
public:
    virtual void print(void) {
        std::cout << "Base1 print" << std::endl;
    }
    ~Base1(){
        std::cout << "Base1's destructor" << std::endl;
    }
};
class Derived1 : public Base1
{
public:
    Derived1(int n) {
        p = new char[n];
    }
    void print(void) {
        std::cout << "Derived1 print" << std::endl;
    }
    ~Derived1() {
        delete[]p;
        std::cout << "Derived1's destructor" << std::endl;
    }
private:
    char *p;
};

class Base2 {
public:
    virtual void print(void) {
        std::cout << "Base2 print" << std::endl;
    }
    virtual ~Base2() {
        std::cout << "Base2's destructor" << std::endl;
    }
};
class Derived2 : public Base2
{
public:
    Derived2(int n) {
        p = new char[n];
    }
    void print(void) {
        std::cout << "Derived2 print" << std::endl;
    }
    ~Derived2() {
        delete[]p;
        std::cout << "Derived2's destructor" << std::endl;
    }
private:
    char *p;
};
int main(int argc, char** argv)
{
    std::cout << "Base1 test: \n";
    Base1 *base1 = new Derived1(5);
    base1->print();
    delete base1;
    std::cout << "\n\nBase2 test: \n";
    Base2 *base2 = new Derived2(5);
    base2->print();
    delete base2;
    return 0;
}
//輸出結(jié)果:
Base1 test:
Derived1 print
Base1's destructor


Base2 test:
Derived2 print
Derived2's destructor
Base2's destructor

base1實際指向Derived1對象晚吞,在Derived中通過new在堆上創(chuàng)建了5個char,但是當(dāng)執(zhí)行delete base1;的時候延旧,只調(diào)用了Base1::~Base1(),但卻沒有調(diào)用Derived1::~Derived1(),最終導(dǎo)致這5個char無法釋放槽地,而導(dǎo)致內(nèi)存泄漏迁沫。

當(dāng)把Base2的析構(gòu)函數(shù)聲明為虛函數(shù)的時候,調(diào)用delete base2,會先調(diào)用Derived2::~Derived2(),然后再調(diào)用Base2::~Base2(),所有內(nèi)存成功釋放捌蚊。

純虛函數(shù)

TODO

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末集畅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子缅糟,更是在濱河造成了極大的恐慌挺智,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溺拱,死亡現(xiàn)場離奇詭異逃贝,居然都是意外死亡,警方通過查閱死者的電腦和手機迫摔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門沐扳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人句占,你說我怎么就攤上這事沪摄。” “怎么了纱烘?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵杨拐,是天一觀的道長。 經(jīng)常有香客問我擂啥,道長哄陶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任哺壶,我火速辦了婚禮屋吨,結(jié)果婚禮上蜒谤,老公的妹妹穿的比我還像新娘。我一直安慰自己至扰,他們只是感情好鳍徽,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著敢课,像睡著了一般阶祭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上直秆,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天濒募,我揣著相機與錄音,去河邊找鬼切厘。 笑死萨咳,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疫稿。 我是一名探鬼主播培他,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼遗座!你這毒婦竟也來了舀凛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤途蒋,失蹤者是張志新(化名)和其女友劉穎猛遍,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體号坡,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡懊烤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了宽堆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腌紧。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖畜隶,靈堂內(nèi)的尸體忽然破棺而出壁肋,到底是詐尸還是另有隱情,我是刑警寧澤籽慢,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布浸遗,位于F島的核電站,受9級特大地震影響箱亿,放射性物質(zhì)發(fā)生泄漏跛锌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一届惋、第九天 我趴在偏房一處隱蔽的房頂上張望察净。 院中可真熱鬧驾茴,春花似錦、人聲如沸氢卡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽译秦。三九已至,卻和暖如春击碗,著一層夾襖步出監(jiān)牢的瞬間筑悴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工稍途, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留阁吝,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓械拍,卻偏偏與公主長得像突勇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坷虑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

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

  • C++虛函數(shù) C++虛函數(shù)是多態(tài)性實現(xiàn)的重要方式甲馋,當(dāng)某個虛函數(shù)通過指針或者引用調(diào)用時,編譯器產(chǎn)生的代碼直到運行時才...
    小白將閱讀 1,745評論 4 19
  • 一個博客迄损,這個博客記錄了他讀這本書的筆記定躏,總結(jié)得不錯∏鄣校《深度探索C++對象模型》筆記匯總 1. C++對象模型與內(nèi)...
    Mr希靈閱讀 5,593評論 0 13
  • 1.面向?qū)ο蟮某绦蛟O(shè)計思想是什么痊远? 答:把數(shù)據(jù)結(jié)構(gòu)和對數(shù)據(jù)結(jié)構(gòu)進行操作的方法封裝形成一個個的對象。 2.什么是類氏捞?...
    少帥yangjie閱讀 5,008評論 0 14
  • 1. 結(jié)構(gòu)體和共同體的區(qū)別碧聪。 定義: 結(jié)構(gòu)體struct:把不同類型的數(shù)據(jù)組合成一個整體,自定義類型幌衣。共同體uni...
    breakfy閱讀 2,130評論 0 22
  • 今天是2017年8月26日 是劍耀每天一篇原創(chuàng)文章的 第13篇 《孫子兵法》中有一句是:兵者矾削,國之大事,死生之地豁护,...
    愿你歸來還是少年閱讀 702評論 0 1