Cpp 对象模型探索 / 多重继承下基类指针释放子类对象的原理说明(虚析构函数的作用)
生活随笔
收集整理的這篇文章主要介紹了
Cpp 对象模型探索 / 多重继承下基类指针释放子类对象的原理说明(虚析构函数的作用)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
源碼
#include <iostream>class Base1 { public:virtual void func_1_1(){ std::cout << "Base1::func_1_1()" << std::endl; }virtual void func_1_2(){ std::cout << "Base1::func_1_2()" << std::endl; }virtual ~Base1() {} };class Base2 { public:virtual void func_2_1(){ std::cout << "Base2::func_2_1()" << std::endl; }virtual void func_2_2(){ std::cout << "Base1::func_2_2()" << std::endl; }virtual ~Base2() {} };class Son :public Base1, public Base2 { public:virtual void func_s(){ std::cout << "Son::func_s()" << std::endl; }virtual void func_2_1(){ std::cout << "Son::func_2_1()" << std::endl; } };int main() {Base2 *pb2 = new Son();delete pb2;return 0; }分析
Son類的內存布局如下所示:
在代碼 delete pb2; 處打下斷點,進入匯編,如下圖所示:
總結過程,如下:
delete pb2 時,根據 Base2 的虛函數表,找到 trunk 項,從而獲得了子類對象的首地址,并且調用子類對象的虛析構函數。然后先后執行了 Base2、Base1和Son類的虛構函數,最后完成?new Son 對象的釋放。
若是如下代碼:
Base1 *pb1 = new Son();delete pb1;則 Base1 虛函數表中的 trunk 項對應的代碼中就不包含了調整 pb1 指針的位置,因為 pb1 本身就指向了 Son 類對象的首地址,所以直接調用了 Son 類對象的析構函數。
拓展:
1、虛函數表中的 trunk 項,實際上一段匯編代碼的首地址,執行的內容如下:
- 將 pb2 偏移到子類對象的首地址。
- 執行子類對象的虛析構函數。
2、上述釋放內存的成功實現的前提是,基類的析構函數必須是虛函數。若不是,則直接執行了 Base2 那部分的析構函數,這就導致了 Son 類對象時只釋放 Base2 對應的那部分。
對于操作系統的內存分配機制來說,相對于內存塊前面的固定位置會記錄著該內存塊的信息,包括該內存塊的字節數。由于上述操作中,釋放 Base2 對應的部分是時候,沒有辦法找到這部分的內存信息,從而導致了釋放內存失敗,程序運行崩潰。
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的Cpp 对象模型探索 / 多重继承下基类指针释放子类对象的原理说明(虚析构函数的作用)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/Cpp / STL / 各个实现版本
- 下一篇: Cpp 对象模型探索 / 虚继承带虚函数