虚析构和纯虚析构原理

直接上代码:请根据编号查看代码说明。

先总结:

  1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

  2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

  3. 拥有纯虚析构函数的类也属于抽象类

animal类

//3.
class animal
{
public:animal() { cout << "animal构造函数调用" << endl; }//能调用子类析构函数 来释放堆区的解决方法://利用虚析构可以解决父类指针释放子类对象时不干净的问题//virtual ~animal() { cout << "animal虚析构函数调用" << endl; }//而如果想避免基类实例化,则可以将析构函数写成纯虚析构//但因为派生类(子类)不可能来实现基类(父类)的析构函数,//所以基类析构函数虽然可以标为纯虚,但是仍必须实现析构函数,//否则派生类无法继承,也无法编译通过。//纯虚析构 要声明也要实现(类外定义)//有了纯虚析构之后,这个类也属于抽象类,并无法实例化对象virtual  ~animal() = 0;virtual void speak() = 0;
};//纯虚析构函数要类外定义
animal::~animal() { cout << "animal纯虚析构函数调用" << endl; }

cat类,里面继承了父类animal

// 4.
class cat : public animal
{
public:cat(string name){cout << "cat构造函数调用" << endl;m_Name = new string(name);}virtual void speak() { cout << *m_Name << "小猫在说话" << endl; }~cat(){if (m_Name != NULL){cout << "cat析构函数调用" << endl;delete m_Name;m_Name = NULL;}}string* m_Name;
};
// 5.
void te01()
{//父类指针指向了一个开辟在堆区的子类数据animal* a = new cat("Tom");//new一个在堆区的cat类型的对象,cat继承自animal//我们知道创建子类时会先创建父类//所以先调用了animal的构造函数//再是cat的构造函数//亿点细节://在创建父类时,如果发现父类中有虚函数//编译器就会使用一个叫虚函数表的东西,保存所有的虚函数,包括纯虚函数//在这里,animal父类的虚函数表中,有两个虚函数/*class animal   size(4):+---0      | (vfptr)+---animal::$vftable@:| &animal_mata|  00        | &animal::(dtor) 1     | &animal::speak*///&animal::(dtor)  就是animal的纯虚析构函数的地址//dtor是destructor的缩写,是析构函数的意思,中文直译叫"垃圾焚毁炉"//&animal::speak   就是speak虚函数的地址//接着,子类继承了这个表,重写了speak。/*class cat       size(8):+---0          | +--- (base class animal)0        | | {vfptr}| +---4         | m_Name+---cat::$vftable@:| &cat_meta|  0| &cat::(dtor)0     | &cat::speak*///这个dtor我不知道算不算重写,我觉的应该是的//但我不了解原理,所以搬了一个别人的解释://当父类析构函数定义为虚函数后,子类默认就是虚析构函数,跟普通成员函数一样//现在将父类析构函数 定义为虚函数,子类再继承了 父类的虚函数表//子类的虚函数表中,就存在父类的 虚析构函数的地址,//但子类的析构函数 也是虚函数,所以重写了自己虚函数表中 父类虚析构函数的地址//变成了子类的虚析构函数地址//虽然父子的析构函数名字不一样,但是他们占同一个坑//(即父子析构函数在虚函数表中的位置是一样的,否则就不存在多态了)//用父类指针指向子类,并最后通过父类指针删除子类对象的时候,//发现animal类的析构函数是虚函数,就到子类对象的虚函数表里找析构函数//此时就会调用虚函表中 子类的虚析构函数 并很好的防止了内存泄漏//然后还有个问题,//既然子类的虚函数表中只有子类虚析构函数,那它怎样析构父类呢?//父类的析构函数又在哪呢?//其实在子类的析构函数中,底层包含着对父类析构函数的调用//原因我认为是://对象都存放在栈中,创建子类对象先调用父类的对象,//父类对象压入栈,然后是子类对象入栈,由于栈是先进后出,//delete父类的时候就先调用子类对象,在调用父类对象a->speak();//因为子类的speak重写了父类的speak,父类指针调用的是子类的speak delete a;//父类指针在析构的时候 不会调用子类中的析构函数//导致子类如果有堆区属性,出现内存泄漏//原因是指针a是animal类型的指针,也就是父类类型的指针//释放a时只进行animal类的析构函数。//但父类析构函数变成虚析构之后,这个问题就解决了}
// 1.
int main()
{// 2.te01();return 0;
}

本人才疏学浅,若有疏漏和错误,请指正 2892870137@qq.com
欢迎拜访我的主博客:https://h-james.github.io/

虚析构和纯虚析构原理相关推荐

  1. c/c++入门教程 - 2.4.7 多态、函数地址晚绑定(重写,虚函数,纯虚函数,抽象类,虚析构,纯虚析构)

    目录 4.7 多态 4.7.1 多态的基本概念(超级重要) 4.7.2 多态的原理刨析(超级重要) 4.7.2 多态案例一:计算器类 4.7.3 纯虚函数和抽象类 4.7.4 多态案例二 - 制作饮品 ...

  2. C++虚析构和纯虚析构

    C++虚析构和纯虚析构 虚析构和纯虚析构 示例 总结 虚析构和纯虚析构 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码 解决方式:将父类中的析构函数改为虚析构或者 ...

  3. c++中多态---3(虚析构和纯虚析构,向上类型转化和向下类型转化)

    虚析构和纯虚析构 虚析构 virtual ~类名(){} 类内声明,类内实现 解决问题:通过父类指针指向子类对象释放时候不干净的问题 纯虚析构 写法 virtual ~类名(){}=0; 类内声明 类 ...

  4. C++_类和对象_C++多态_虚析构和纯虚析构函数---C++语言工作笔记074

    然后我们再来看,虚析构和纯虚析构函数的用法,上面有大体的介绍了. 但是我们还是用一个例子来说明一下更好. 首先,我们去创建一个Animal类,类中我们去写上一个spreak这个,纯虚函数,然后,让我们 ...

  5. C++虚函数、纯虚函数、虚析构、纯虚析构、动态绑定和抽象类详解。

    目录 1.虚函数的概念 2.虚函数的定义 3.虚函数的作用 4.用虚函数实现多态的方法 5.动态绑定和静态绑定 6.纯虚函数和抽象类 7.虚析构和纯虚析构 1.虚函数的概念 在C++程序中我们经常可以 ...

  6. C++中的各种“虚“-- 虚函数、纯虚函数、虚继承、虚基类、虚析构、纯虚析构、抽象类讲解

    C++中的各种"虚" 1. 菱形继承 1.1 虚继承 && 虚基类 1.2 虚基类指针(vbptr)&& 虚基类表(vbtable) 2. 多态 2 ...

  7. C++面向对象-26-虚析构和纯虚析构

    这篇来学习多态中可能会发生内存泄漏和解决办法,就要使用到虚析构函数和纯虚析构函数.先不介绍概念,肯定和前面学构造函数和析构函数中的析构函数有关系.先通过引出问题,然后介绍这两个概念和特点. 1.多态基 ...

  8. C++类与对象笔记十四:多态六:虚析构和纯虚析构

    多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用子类的析构代码. 即:父类指针无法调用子类实例对象内的析构函数.造成堆区内存泄漏. 解决方案:将父类中的析构函数改为虚析构或者纯虚析 ...

  9. C++多态之虚析构与纯虚析构

    一.虚析构与纯虚析构的共同点: 都是释放子类的堆区资源. 都需要具体实现. 二.虚析构与纯虚析构的不同点: 使用纯虚析构函数的父类属于抽象类,不能实例化具体对象.代码示例如下: #include &l ...

最新文章

  1. 如何使Sybase ASE中对象名不区分大小写?
  2. scrum回顾_沙龙回顾 | 大规模敏捷框架-Essential SAFe介绍
  3. vue 怎么样不重复往数组里插入数据_Vue.js在数组中插入重复数据的实现代码分享...
  4. 百度痞哥:百度贴吧的回帖为什么没做点赞功能?
  5. ecshop的smarty库还原成smarty原生库方法
  6. Delphi多线程详解CreateThread、TThread,以及线程间通过临界区(CriticalSection)实现同步
  7. 关于发邮件报错535 Error:authentication failed解决方法
  8. 50行python代码自动生成文章_如何通过50行Python代码获取公众号全部文章
  9. linux 目录与分区与文件,LINUX中的分区与文件系统
  10. C#生成Guid,SqlServer生成Guid
  11. 小米笔记本安装Win 10历程
  12. eclipse svn切换账号
  13. 【渝粤教育】电大中专液压与气动技术_1作业 题库
  14. 微信与QQ聊天记录从旧电脑到新电脑之间无缝备份迁移
  15. java毕业生设计演唱会网上订票购票系统计算机源码+系统+mysql+调试部署+lw
  16. Oracle10g ora12170,ORA-3136、TNS-12535 12170 12606
  17. 【软路由】openwrt 搭建个人NAS-超简单
  18. 遨博机械臂——末端工具ROS驱动
  19. [bzoj4084][Sdoi2015]双旋转字符串_hash
  20. RNN学习笔记3-LSTM

热门文章

  1. lightroom最新版本下载_win10系列之如何最快速从微软官网下载最新版本iso映像
  2. 支付渠道被攻击了有什么好的办法吗?
  3. 用C++写洛谷P1425小鱼的游泳时间
  4. 解决-BASH: /xxx/Jxxx/JDK1.8.0_221/BIN/JAVA: 权限不够问题
  5. 车道线检测CLRNet算法复现在Tusimple数据集测试demo
  6. JAVA基于局域网的聊天室系统的设计与实现
  7. 单片机 CH340下载 反向串联二极管
  8. Tomcat 面试题(总结最全面的面试题!!!)
  9. 道听途说:Cadence与Synopsys后端工具非正规比较
  10. Vue 之 Vuex(3)mapState 的使用