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 对象模型探索 / 多重继承下基类指针释放子类对象的原理说明(虚析构函数的作用)相关推荐
- 基类指针和子类指针相互赋值
首先,给出基类animal和子类fish [cpp] view plaincopy print? //================================================= ...
- Cpp 对象模型探索 / 单一继承的类的内存布局
目录 1.父类和子类都没有虚函数 2.父类有虚函数.子类没有虚函数 3.父类没有虚函数,子类有虚函数 4.父类和子类都有虚函数 5.总结 #include <iostream> class ...
- Cpp 对象模型探索 / 多重继承虚函数表分析
一.源码 #include <iostream>class Base1 { public:virtual void func11(){std::cout << "Ba ...
- 基类指针调用派生类函数_C++ 多态性:虚函数--基类与派生类类型转换(第7章 05)例子问题解析(学习笔记:第8章 05)...
虚函数[1] 问题:还记得第7章的例子吗[2]? 例7-3 类型转换规则举例 #include <iostream> using namespace std; class Base1 { ...
- Cpp 对象模型探索 / 不能被继承的类
两种方法 C++ 11 final 关键字 友元类 + 虚继承. 栗子 class A { private:A() {}friend class B; }; class B : virtual pub ...
- 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?...
五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的 ...
- Cpp 对象模型探索 / 含有虚基类的类的内存布局
一.栗子 class Grand { public:int i_grand_ = 8; };class Parent1 : public virtual Grand { public:int i_pa ...
- Cpp 对象模型探索 / 带有虚继承类的构造函数的调用顺序
栗子 #include <iostream> class A { public:A() { std::cout << "A" << std::e ...
- C++ day22 继承(二)基类指针数组通过虚方法实现智能的多态
继承一共有三种: 公有继承 私有继承 保护继承 文章目录 公有继承 基类和派生类的关系 is-a(用公有继承表示"是一种"的关系) has-a uses-a is-like-a i ...
最新文章
- jet nano 车道识别
- rust的权限柜怎么做_潍坊装修知识~二胎家庭不做上下铺,把两张床靠墙放,中间做收纳柜,你感觉怎么样?...
- 前端学习(2424):关于问题的解决方式
- 变更数据推送java_idea 团队成员修改工程后push推送
- 两个整数求平均值,防止溢出的问题
- Net设计模式实例之观察者模式(Observer Pattern)
- Unix 下获得 root权限
- 案例实操-Top10热门品类
- 人口logistic模型公式_人口指数增长模型和Logistic模型
- 《心经》-翻译、中英梵对照
- juniper设备配置syslog日志发送到远程日志服务器
- 全连接网络实现Fashion数据集学习/预测
- “单向网闸”技术介绍
- jadx工具介绍及使用
- 在Excel中将人民币金额小写转成大写(转)
- CSDN 博客被自己误删了怎么办---(联系QQ客服)
- httpclient Accept-Encoding 乱码
- 一文读懂 协方差矩阵
- 广东省谷歌地球高程DEM等高线下载
- 李刚疯狂java抄袭,推荐:疯狂java讲义--李刚著作(3)