詳解C++中虛析構(gòu)函數(shù)的作用及其原理分析
C++中的虛析構(gòu)函數(shù)到底什么時(shí)候有用的,什么作用呢。
一.虛析構(gòu)函數(shù)的作用
總的來說虛析構(gòu)函數(shù)是為了避免內(nèi)存泄露,而且是當(dāng)子類中會(huì)有指針成員變量時(shí)才會(huì)使用得到的。也就說虛析構(gòu)函數(shù)使得在刪除指向子類對象的基類指針時(shí)可以調(diào)用子類的析構(gòu)函數(shù)達(dá)到釋放子類中堆內(nèi)存的目的,而防止內(nèi)存泄露的.
我們知道,用C++開發(fā)的時(shí)候,用來做基類的類的析構(gòu)函數(shù)一般都是虛函數(shù)??墒?,為什么要這樣做呢?下面用一個(gè)小例子來說明:
#include<iostream> using namespace std; class ClxBase { public: ClxBase() {}; virtual ~ClxBase() { cout<<"delete ClxBase"<<endl; }; virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; }; }; class ClxDerived : public ClxBase { public: ClxDerived() {}; ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }; }; int main(int argc, char const* argv[]) { ClxBase *pTest = new ClxDerived; pTest->DoSomething(); delete pTest; return 0; }
但是,如果把類ClxBase析構(gòu)函數(shù)前的virtual去掉,那輸出結(jié)果就是下面的樣子了:
沒有調(diào)動(dòng)子類的析構(gòu)函數(shù)
也就是說,類ClxDerived的析構(gòu)函數(shù)根本沒有被調(diào)用!一般情況下類的析構(gòu)函數(shù)里面都是釋放內(nèi)存資源,而析構(gòu)函數(shù)不被調(diào)用的話就會(huì)造成內(nèi)存泄漏。我想所有的C++程序員都知道這樣的危險(xiǎn)性。當(dāng)然,如果在析構(gòu)函數(shù)中做了其他工作的話,那你的所有努力也都是白費(fèi)力氣。
所以,文章開頭的那個(gè)問題的答案就是--這樣做是為了當(dāng)用一個(gè)基類的指針刪除一個(gè)派生類的對象時(shí),派生類的析構(gòu)函數(shù)會(huì)被調(diào)用。
當(dāng)然,并不是要把所有類的析構(gòu)函數(shù)都寫成虛函數(shù)。因?yàn)楫?dāng)類里面有虛函數(shù)的時(shí)候,編譯器會(huì)給類添加一個(gè)虛函數(shù)表,里面來存放虛函數(shù)指針,這樣就會(huì)增加類的存儲(chǔ)空間。所以,只有當(dāng)一個(gè)類被用來作為基類的時(shí)候,才把析構(gòu)函數(shù)寫成虛函數(shù)。
總結(jié)一下虛析構(gòu)函數(shù)的作用:
(1)如果父類的析構(gòu)函數(shù)不加virtual關(guān)鍵字
當(dāng)父類的析構(gòu)函數(shù)不聲明成虛析構(gòu)函數(shù)的時(shí)候,當(dāng)子類繼承父類,父類的指針指向子類時(shí),delete掉父類的指針,只調(diào)動(dòng)父類的析構(gòu)函數(shù),而不調(diào)動(dòng)子類的析構(gòu)函數(shù)。
(2)如果父類的析構(gòu)函數(shù)加virtual關(guān)鍵字
當(dāng)父類的析構(gòu)函數(shù)聲明成虛析構(gòu)函數(shù)的時(shí)候,當(dāng)子類繼承父類,父類的指針指向子類時(shí),delete掉父類的指針,先調(diào)動(dòng)子類的析構(gòu)函數(shù),再調(diào)動(dòng)父類的析構(gòu)函數(shù)。
二.虛析構(gòu)函數(shù)的原理分析
#include<iostream> using namespace std; class Base { public: Base(){cout<<"create Base"<<endl;} virtual ~Base(){cout<<"delete Base"<<endl;} }; class Der : public Base { public: Der(){cout<<"create Der"<<endl;} ~Der(){cout<<"Delete Der"<<endl;} }; int main(int argc, char const* argv[]) { Base *b = new Der; delete b; return 0; }
從創(chuàng)建講起,用gdb調(diào)試你會(huì)發(fā)現(xiàn),
(1)先調(diào)用父類的構(gòu)造函數(shù),再調(diào)用子類的構(gòu)造函數(shù),
這里有一個(gè)問題:父類的構(gòu)造函數(shù)/析構(gòu)函數(shù)與子類的構(gòu)造函數(shù)/析構(gòu)函數(shù)會(huì)形成多態(tài),但是當(dāng)父類的構(gòu)造函數(shù)/析構(gòu)函數(shù)即使被聲明virtual,子類的構(gòu)造/析構(gòu)方法仍無法覆蓋父類的構(gòu)造方法和析構(gòu)方法。這是由于父類的構(gòu)造函數(shù)和析構(gòu)函數(shù)是子類無法繼承的,也就是說每一個(gè)類都有自己獨(dú)有的構(gòu)造函數(shù)和析構(gòu)函數(shù)。
(2)而由于父類的析構(gòu)函數(shù)為虛函數(shù),所以子類會(huì)在所有屬性的前面形成虛表,而虛表內(nèi)部存儲(chǔ)的就是父類的虛函數(shù)
即使子類也有虛函數(shù),但是由于是單繼承,所以也只有一張?zhí)摫?,這在上一篇博客多態(tài)中講到過。
執(zhí)行 Base *b = new Der;之后b的最終形態(tài)
(3)當(dāng)delete父類的指針時(shí),由于子類的析構(gòu)函數(shù)與父類的析構(gòu)函數(shù)構(gòu)成多態(tài),所以得先調(diào)動(dòng)子類的析構(gòu)函數(shù);之所以再調(diào)動(dòng)父類的析構(gòu)函數(shù),是因?yàn)閐elete的機(jī)制所引起的,delete 父類指針?biāo)傅目臻g,要調(diào)用父類的析構(gòu)函數(shù)。
所以結(jié)果就是這樣
以上所述是小編給大家介紹的C++中虛析構(gòu)函數(shù)的作用及其原理分析詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
- C++超詳細(xì)講解構(gòu)造函數(shù)與析構(gòu)函數(shù)的用法及實(shí)現(xiàn)
- C++深入講解對象的銷毀之析構(gòu)函數(shù)
- C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹
- 詳解C++ 編寫String 的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值函數(shù)
- C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的調(diào)用順序詳解
- 淺談C++基類的析構(gòu)函數(shù)為虛函數(shù)
- C++類成員構(gòu)造函數(shù)和析構(gòu)函數(shù)順序示例詳細(xì)講解
- C++ 私有析構(gòu)函數(shù)的作用示例詳解
相關(guān)文章
C語言實(shí)現(xiàn)小學(xué)生隨機(jī)出題測試計(jì)分
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)小學(xué)生隨機(jī)出題測試計(jì)分,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03C語言編程時(shí)常犯十八個(gè)錯(cuò)誤小結(jié)
C語言的最大特點(diǎn)是:功能強(qiáng)、使用方便靈活。C編譯的程序?qū)φZ法檢查并不象其它高級(jí)語言那么嚴(yán)格,這就給編程人員留下“靈活的余地”,但還是由于這個(gè)靈活給程序的調(diào)試帶來了許多不便,尤其對初學(xué)C語言的人來說,經(jīng)常會(huì)出一些連自己都不知道錯(cuò)在哪里的錯(cuò)誤2013-07-07C++?TCP網(wǎng)絡(luò)編程詳細(xì)講解
TCP/IP是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,它會(huì)保證數(shù)據(jù)不丟包、不亂序。TCP全名是Transmission?Control?Protocol,它是位于網(wǎng)絡(luò)OSI模型中的第四層2022-09-09C++實(shí)現(xiàn)LeetCode(198.打家劫舍)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(198.打家劫舍),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C&C++設(shè)計(jì)風(fēng)格選擇 命名規(guī)范
本文難免帶有主觀選擇傾向,但是會(huì)盡量保持客觀的態(tài)度歸納幾種主流的命名風(fēng)格,僅供參考2018-04-04