網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
C++何推薦要把基類(lèi)析構(gòu)函數(shù)設(shè)置成虛函數(shù)
在C++中常聽(tīng)老師講要把基類(lèi)析構(gòu)函數(shù)聲明成虛函數(shù),這是因?yàn)橐乐故褂没?lèi)指針在調(diào)用派生類(lèi)對(duì)象析構(gòu)函數(shù)時(shí),觸發(fā)靜態(tài)綁定,調(diào)用不到派生類(lèi)的析構(gòu)函數(shù),導(dǎo)致內(nèi)存泄漏
//Base表示基類(lèi)
//Derive表示派生類(lèi)
Base* ptr = new Derive d;
在這里如果沒(méi)有把基類(lèi)析構(gòu)函數(shù)聲明成虛函數(shù),那么就沒(méi)有構(gòu)成多態(tài),那么編譯器只會(huì)去調(diào)用Base的析構(gòu)函數(shù)而非Derive
C++中析構(gòu)函數(shù)為虛函數(shù)問(wèn)題
1、析構(gòu)函數(shù)是否定義為虛函數(shù)的區(qū)別
(1)析構(gòu)函數(shù)定義為虛函數(shù)時(shí):基類(lèi)指針可以指向派生類(lèi)的對(duì)象(多態(tài)性),如果刪除該指針delete []p;就會(huì)調(diào)用該指針指向的派生類(lèi)析構(gòu)函數(shù),而派生類(lèi)的析構(gòu)函數(shù)又自動(dòng)調(diào)用基類(lèi)的析構(gòu)函數(shù),這樣整個(gè)派生類(lèi)的對(duì)象完全被釋放。
(2)析構(gòu)函數(shù)不定義為虛函數(shù)時(shí):編譯器實(shí)施靜態(tài)綁定,在刪除基類(lèi)指針時(shí),只會(huì)調(diào)用基類(lèi)的析構(gòu)函數(shù)而不調(diào)用派生類(lèi)析構(gòu)函數(shù),這樣就會(huì)造成派生類(lèi)對(duì)象析構(gòu)不完全。
下面看幾個(gè)例子
2、派生類(lèi)指針操作派生類(lèi)對(duì)象,基類(lèi)析構(gòu)函數(shù)不是虛函數(shù)
#include<iostream>
using namespace std;
class ClxBase{
public:
ClxBase() {};
~ClxBase() { cout << "Output from the destructor of class ClxBase!" << endl; };
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(){
ClxDerived *p = new ClxDerived; // 派生類(lèi)指針操作派生類(lèi)對(duì)象
p->DoSomething();
delete p;
system("pause");
return 0;
}
注:派生類(lèi)指針操作派生類(lèi)對(duì)象,基類(lèi)析構(gòu)函數(shù)不是虛函數(shù),此時(shí)會(huì)先是否派生類(lèi)的資源,再釋放基類(lèi)的資源,這里資源就不會(huì)出現(xiàn)泄漏的情況。
3、基類(lèi)指針操作派生類(lèi)對(duì)象,基類(lèi)析構(gòu)函數(shù)不是虛函數(shù)
#include<iostream>
using namespace std;
class ClxBase{
public:
ClxBase() {};
~ClxBase() { cout << "Output from the destructor of class ClxBase!" << endl; };
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(){
ClxBase *p = new ClxDerived; // 基類(lèi)指針操作派生類(lèi)對(duì)象
p->DoSomething();
delete p;
system("pause");
return 0;
}
注:基類(lèi)指針操作派生類(lèi)對(duì)象,基類(lèi)析構(gòu)函數(shù)不是虛函數(shù):此時(shí)只是釋放了基類(lèi)的資源,而沒(méi)有調(diào)用派生類(lèi)的析構(gòu)函數(shù)。調(diào)用dosomething()函數(shù)執(zhí)行的也是基類(lèi)定義的函數(shù)。這樣的刪除只能夠刪除基類(lèi)對(duì)象,而不能刪除子類(lèi)對(duì)象,形成了刪除一半形象,造成內(nèi)存泄漏。
4、基類(lèi)指針操作派生類(lèi)對(duì)象,基類(lèi)析構(gòu)函數(shù)是虛函數(shù)
#include<iostream>
using namespace std;
class ClxBase{
public:
ClxBase() {};
// 定義為虛函數(shù)
virtual ~ClxBase() { cout << "Output from the destructor of class 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(){
ClxBase *p = new ClxDerived; // 基類(lèi)指針操作派生類(lèi)對(duì)象
p->DoSomething();
delete p;
system("pause");
return 0;
}
注:基類(lèi)指針操作派生類(lèi)對(duì)象,基類(lèi)析構(gòu)函數(shù)是虛函數(shù):此時(shí)釋放了派生類(lèi)的資源,再調(diào)用基類(lèi)的析構(gòu)函數(shù)。調(diào)用dosomething()函數(shù)執(zhí)行的也是派生類(lèi)定義的函數(shù)。
在公有繼承中,基類(lèi)對(duì)派生類(lèi)及其對(duì)象的操作,只能影響到那些從基類(lèi)繼承下來(lái)的成員。如果想要用基類(lèi)對(duì)非繼承成員進(jìn)行操作,則要把基類(lèi)的這個(gè)函數(shù)定義為虛函數(shù)。
析構(gòu)函數(shù)自然也應(yīng)該如此:如果它想析構(gòu)子類(lèi)中的重新定義或新的成員及對(duì)象,當(dāng)然也應(yīng)該聲明為虛的。
5、基類(lèi)析構(gòu)函數(shù)定義為虛函數(shù)的情況
如果不需要基類(lèi)對(duì)派生類(lèi)及對(duì)象進(jìn)行操作,則不能定義虛函數(shù),因?yàn)檫@樣會(huì)增加內(nèi)存開(kāi)銷(xiāo).當(dāng)類(lèi)里面有定義虛函數(shù)的時(shí)候,編譯器會(huì)給類(lèi)添加一個(gè)虛函數(shù)表,里面來(lái)存放虛函數(shù)指針,這樣就會(huì)增加類(lèi)的存儲(chǔ)空間。所以,只有當(dāng)一個(gè)類(lèi)被用來(lái)作為基類(lèi)的時(shí)候,并且有使用到基類(lèi)指針操作派生類(lèi)的情況時(shí),才把析構(gòu)函數(shù)寫(xiě)成虛函數(shù)。
總結(jié)
原文鏈接:https://blog.csdn.net/qq_62236390/article/details/127474027
相關(guān)推薦
- 2022-12-02 C語(yǔ)言實(shí)現(xiàn)三子棋小游戲的示例代碼_C 語(yǔ)言
- 2022-12-23 go語(yǔ)言?xún)?yōu)雅地處理error工具及技巧詳解_Golang
- 2022-05-13 修復(fù)ffmpeg寫(xiě)文件時(shí)的幀率異常問(wèn)題記錄
- 2022-10-23 Android文件存儲(chǔ)SharedPreferences源碼解析_Android
- 2022-10-14 VS Code注釋插件doxygen documentation generator
- 2022-06-19 GO語(yǔ)言對(duì)數(shù)組切片去重的實(shí)現(xiàn)_Golang
- 2022-05-28 C語(yǔ)言?超詳細(xì)講解算法的時(shí)間復(fù)雜度和空間復(fù)雜度_C 語(yǔ)言
- 2022-09-25 FFmpeg源碼分析:SwsContext圖像轉(zhuǎn)換上下文
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支