C++虛函數(shù)注意事項(xiàng)
文章轉(zhuǎn)自公眾號(hào):Coder梁(ID:Coder_LT)
一、虛函數(shù)注意事項(xiàng)
在之前的文章當(dāng)中,我們已經(jīng)討論了虛函數(shù)的使用方法,也對(duì)它的原理進(jìn)行了簡(jiǎn)單的介紹。
這里簡(jiǎn)單做一個(gè)總結(jié):
- 在基類的方法聲明中使用關(guān)鍵字virtual可以聲明虛函數(shù)
- 加上了virtual關(guān)鍵字的函數(shù)在基類以及派生類和派生類再派生出來的類中都是虛的
- 在調(diào)用虛函數(shù)時(shí),程序?qū)?huì)根據(jù)對(duì)象的類型執(zhí)行對(duì)應(yīng)的方法而非引用或指針的類型
- 在定義基類時(shí),需要將要在派生類中重新定義的類方法聲明為虛,如析構(gòu)函數(shù)
除了這些之外,我們還有一些其他需要注意的事項(xiàng)。
1.構(gòu)造函數(shù)
構(gòu)造函數(shù)不能是虛函數(shù),創(chuàng)建派生類對(duì)象時(shí)將調(diào)用派生類的構(gòu)造函數(shù),而非基類的構(gòu)造函數(shù),畢竟構(gòu)造函數(shù)是根據(jù)類名調(diào)用的。
一般我們會(huì)在派生類中調(diào)用基類的構(gòu)造函數(shù),這其實(shí)不是繼承機(jī)制,所以將類構(gòu)造函數(shù)聲明為虛沒有意義。
2.析構(gòu)函數(shù)
前文說過析構(gòu)函數(shù)應(yīng)該是虛函數(shù),除非類不被繼承。
因?yàn)榕缮惍?dāng)中往往含有獨(dú)有的成員變量,如果析構(gòu)函數(shù)非虛,那么會(huì)導(dǎo)致在對(duì)象析構(gòu)時(shí)僅調(diào)用基類的析構(gòu)函數(shù),從而導(dǎo)致獨(dú)有的成員變量?jī)?nèi)存不被釋放,引起內(nèi)存泄漏。
所以通常我們會(huì)將析構(gòu)函數(shù)設(shè)置成virtual,即使不用做基類也不會(huì)引起錯(cuò)誤,至多只會(huì)影響一點(diǎn)效率。但在大型合作開發(fā)的項(xiàng)目當(dāng)中,許多組件和類都是共享的,我們往往無法保證我們開發(fā)的類是否會(huì)被其他開發(fā)者繼承,因此設(shè)置虛析構(gòu)函數(shù)也是一種常規(guī)做法。
3.友元
友元函數(shù)不能是虛函數(shù),因?yàn)橛言皇穷惓蓡T,只有成員函數(shù)才能是虛函數(shù)。
如果我們希望友元函數(shù)也能實(shí)現(xiàn)類似虛函數(shù)的功能, 我們可以在友元函數(shù)當(dāng)中使用虛函數(shù)來解決。
4.沒有重新定義
如果派生類當(dāng)中沒有重新定義虛函數(shù),那么將使用該函數(shù)的基類版本。如果派生類位于派生鏈中,如B繼承了A,C繼承了B這種情況,那么派生類將會(huì)使用最新的虛函數(shù)版本。
5.重新定義將隱藏方法
我們來看一個(gè)例子:
class Mammal { ?private: ? string name; ?public: ? Mammal(string n): name(n) {} ? virtual void speak() const { ? ?cout << "can't say anything" << endl; ? } }; class Human : public Mammal{ ?private: ? string job; ?public: ? Human(string n, string j): Mammal(n), job(j) {} ? virtual void speak(const string st) const { ? ?cout << "i'm human" << endl; ? } };
我們?cè)诟割惍?dāng)中定義了一個(gè)無參虛函數(shù)speak
,而在子類Human
當(dāng)中也定義了一個(gè)需要傳入一個(gè)string
類型的虛函數(shù)speak
。
我試了一下,在我的g++編譯器當(dāng)中,會(huì)報(bào)錯(cuò):
但根據(jù)C++ Primer
中的說法,在一些古老的編譯器當(dāng)中,可能不會(huì)報(bào)錯(cuò),甚至可能連警告都沒有。
在這類編譯器當(dāng)中,我們重新定義父類中的虛函數(shù),這樣的重新定義不會(huì)生成兩個(gè)重載版本,而是隱藏了父類無參的版本,只保留了接受string
類型的版本,這種情況有別于函數(shù)重載。
在派生類當(dāng)中重新定義函數(shù),不是使用相同的函數(shù)特征標(biāo)覆蓋基類聲明,而是隱藏同名的基類方法,不管函數(shù)特征標(biāo)如何。
C++ Primer當(dāng)中給出了兩條經(jīng)驗(yàn)規(guī)則:
如果重新定義繼承的方法,應(yīng)該保證與原來的原型完全相同,唯一的例外是返回的類型,如果基類返回的是基類的引用或指針,派生類可以改成派生類的引用或指針:
class Mammal { ?private: ? string name; ?public: ? Mammal(string n): name(n) {} ? virtual Mammal* build(); }; class Human : public Mammal{ ?private: ? string job; ?public: ? Human(string n, string j): Mammal(n), job(j) {} ? virtual Human* build(); };
如果基類聲明被重載了,那么應(yīng)該在派生類中聲明所有的基類版本:
class Mammal { ?private: ? string name; ?public: ? Mammal(string n): name(n) {} ? virtual void speak() const ; ? ? ?virtual void speak(int n) const; ? ? ?virtual void speak(const string st) const; }; class Human : public Mammal{ ?private: ? string job; ?public: ? Human(string n, string j): Mammal(n), job(j) {} ? virtual void speak() const ; ? ? ?virtual void speak(int n) const; ? ? ?virtual void speak(const string st) const; };
如果我們只重新定義了一個(gè)版本,那么另外兩個(gè)版本將隱藏。
但這可能和編譯器版本有關(guān),在新版的編譯器當(dāng)中似乎取消了這一設(shè)定。
我嘗試了一下,發(fā)現(xiàn)并不會(huì)隱藏,一樣可以順利調(diào)用父類方法。
class Mammal { ?private: ? string name; ?public: ? Mammal(string n): name(n) {} ? virtual void speak() const { ? ?cout << "can't say anything from empty" << endl; ? } ? virtual void speak(const string st) const { ? ?cout << "can't say anything from string input" << endl; ? } }; class Human : public Mammal{ ?private: ? string job; ?public: ? Human(string n, string j): Mammal(n), job(j) {} ? virtual void speak(const string st) const { ? ?cout << "i'm human" << endl; ? } }; int main() { ?Mammal *m = new Human("man", "spiderman"); ?m->speak(); ?return 0; }
到此這篇關(guān)于EC++虛函數(shù)注意事項(xiàng)的文章就介紹到這了,更多相關(guān)EC++虛函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中的數(shù)字轉(zhuǎn)字符串to_string
這篇文章主要介紹了C++中的數(shù)字轉(zhuǎn)字符串to_string,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Qt 使用QDialog實(shí)現(xiàn)界面遮罩的示例(蒙版)
界面遮罩在很多時(shí)候都可以用到,例如彈窗,本文主要介紹了Qt 使用QDialog實(shí)現(xiàn)界面遮罩的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04教你用Matlab制作立體動(dòng)態(tài)相冊(cè)
沒想到吧,MATLAB竟也能制作3D相冊(cè)!本文將為大家詳細(xì)介紹Matlab制作立體動(dòng)態(tài)相冊(cè)的方法步驟,感興趣的小伙伴可以跟隨小編一起動(dòng)手試一試2022-03-03OpenCV + MFC實(shí)現(xiàn)簡(jiǎn)單人臉識(shí)別
這篇文章主要為大家詳細(xì)介紹了OpenCV + MFC實(shí)現(xiàn)簡(jiǎn)單人臉識(shí)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08C++實(shí)現(xiàn)高校教室管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)高校教室管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C/C++ 中sizeof(''a'')對(duì)比詳細(xì)介紹
這篇文章主要介紹了C/C++ 中sizeof('a')的值對(duì)比詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2017-02-02