網站首頁 編程語言 正文
C++何推薦要把基類析構函數設置成虛函數
在C++中常聽老師講要把基類析構函數聲明成虛函數,這是因為要防止使用基類指針在調用派生類對象析構函數時,觸發靜態綁定,調用不到派生類的析構函數,導致內存泄漏
//Base表示基類
//Derive表示派生類
Base* ptr = new Derive d;
在這里如果沒有把基類析構函數聲明成虛函數,那么就沒有構成多態,那么編譯器只會去調用Base的析構函數而非Derive
C++中析構函數為虛函數問題
1、析構函數是否定義為虛函數的區別
(1)析構函數定義為虛函數時:基類指針可以指向派生類的對象(多態性),如果刪除該指針delete []p;就會調用該指針指向的派生類析構函數,而派生類的析構函數又自動調用基類的析構函數,這樣整個派生類的對象完全被釋放。
(2)析構函數不定義為虛函數時:編譯器實施靜態綁定,在刪除基類指針時,只會調用基類的析構函數而不調用派生類析構函數,這樣就會造成派生類對象析構不完全。
下面看幾個例子
2、派生類指針操作派生類對象,基類析構函數不是虛函數
#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; // 派生類指針操作派生類對象
p->DoSomething();
delete p;
system("pause");
return 0;
}
注:派生類指針操作派生類對象,基類析構函數不是虛函數,此時會先是否派生類的資源,再釋放基類的資源,這里資源就不會出現泄漏的情況。
3、基類指針操作派生類對象,基類析構函數不是虛函數
#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; // 基類指針操作派生類對象
p->DoSomething();
delete p;
system("pause");
return 0;
}
注:基類指針操作派生類對象,基類析構函數不是虛函數:此時只是釋放了基類的資源,而沒有調用派生類的析構函數。調用dosomething()函數執行的也是基類定義的函數。這樣的刪除只能夠刪除基類對象,而不能刪除子類對象,形成了刪除一半形象,造成內存泄漏。
4、基類指針操作派生類對象,基類析構函數是虛函數
#include<iostream>
using namespace std;
class ClxBase{
public:
ClxBase() {};
// 定義為虛函數
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; // 基類指針操作派生類對象
p->DoSomething();
delete p;
system("pause");
return 0;
}
注:基類指針操作派生類對象,基類析構函數是虛函數:此時釋放了派生類的資源,再調用基類的析構函數。調用dosomething()函數執行的也是派生類定義的函數。
在公有繼承中,基類對派生類及其對象的操作,只能影響到那些從基類繼承下來的成員。如果想要用基類對非繼承成員進行操作,則要把基類的這個函數定義為虛函數。
析構函數自然也應該如此:如果它想析構子類中的重新定義或新的成員及對象,當然也應該聲明為虛的。
5、基類析構函數定義為虛函數的情況
如果不需要基類對派生類及對象進行操作,則不能定義虛函數,因為這樣會增加內存開銷.當類里面有定義虛函數的時候,編譯器會給類添加一個虛函數表,里面來存放虛函數指針,這樣就會增加類的存儲空間。所以,只有當一個類被用來作為基類的時候,并且有使用到基類指針操作派生類的情況時,才把析構函數寫成虛函數。
總結
原文鏈接:https://blog.csdn.net/qq_62236390/article/details/127474027
相關推薦
- 2024-01-06 RocketMQ重復消費問題
- 2022-12-25 go?slice不同初始化方式性能及數組比較詳解_Golang
- 2024-07-18 【SpringBoot】SpringCache輕松啟用Redis緩存
- 2024-03-04 css鼠標移動上去才顯示滾動條
- 2023-01-09 基于Go語言實現插入排序算法及優化_Golang
- 2022-06-28 ASP.NET?WebAPI導入CSV_實用技巧
- 2023-05-20 Golang中map的三種聲明定義方式實現_Golang
- 2022-11-23 TypeScript前端上傳文件到MinIO示例詳解_其它
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支