【C++】C++中基类的析构函数为什么要用virtual虚析构函数?
正面回答:
当基类的析构函数不是虚函数,并且基类指针指向一个派生类对象,然后通过基类指针来删除这个派生类对象时,如果基类的析构函数不是虚析构函数,那么派生类的析构函数就不会被调用,从而产生内存泄漏
#include<iostream>
#include<bits/stdc++.h>
using namespace std; class A
{
public:
A()
{
cout<<"constructing A"<<endl;
}
~A()
{
delete p;
cout<<"destructing A"<<endl;
}
private:
int *p;
}; class B:public A
{
public:
B()
{
cout<<"constructing B"<<endl;
}
~B()
{
delete p;
cout<<"destructing B"<<endl;
}
private:
int *p;
}; int main()
{ A *a=new B();
delete a;
}
/*
constructing A
constructing B
destructing A
*/
分析:只调用了基类A的析构函数,而派生类B的析构函数却没有被调用,这时会产生内存泄漏
如果给基类A的析构函数是虚析构函数,那么便不会产生这个问题
#include<iostream>
#include<bits/stdc++.h>
using namespace std; class A
{
public:
A()
{
cout<<"constructing A"<<endl;
}
virtual ~A()
{
delete p;
cout<<"destructing A"<<endl;
}
private:
int *p;
}; class B:public A
{
public:
B()
{
cout<<"constructing B"<<endl;
}
~B()
{
delete p;
cout<<"destructing B"<<endl;
}
private:
int *p;
}; int main()
{ A *a=new B();
delete a;
}
/*
constructing A
constructing B
destructing B
destructing A
*/
此时派生类B的析构函数被调用了!内存泄漏的问题得以解决
注意构造函数和析构函数的执行顺序:
派生类构造时:先执行基类的构造函数,然后执行派生类的构造函数
派生类析构时:先执行派生类的析构函数,然后执行基类的析构函数
上面内存泄漏产生的必要条件:
1.基类析构函数不是虚析构函数
2.派生类对象的析构函数中有内存需要回收
3.基类指针指向派生类对象,通过删除该基类指针来删除派生类对象
那这种情况下为什么会产生内存泄漏呢?
这种情况下,当删除基类指针指向的派生类对象时不会触发动态绑定,虚函数是动态绑定的基础,现在基类的析构函数不是虚函数,所以不会发生动态绑定,而是静态绑定,指针的静态类型为基类类型,所以delete的时候只会调用基类的析构函数
结论:
人生建议,继承时,基类的析构函数中最好加上virtual。
【C++】C++中基类的析构函数为什么要用virtual虚析构函数?的更多相关文章
- C++中基类的析构函数为什么要用virtual虚析构函数
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...
- C++-基类的析构函数为什么要加virtual虚析构函数(转)
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...
- C++中基类虚析构函数的作用及其原理分析
虚析构函数的理论前提是 执行完子类的析构函数,那么父类的虚构函数必然会被执行. 那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义虚析构函数,那么将只会调用父类的析构函数,而不会调 ...
- 基类的析构函数写成virtual虚析构函数
虚函数作用:动态绑定,实现多态效果. 场景问题: 派生类中有资源需要回收,而在编程中采用多态,由基类的指针指向派生类,则在释放的时候,如果基类的析构函数不是virtual,则派生类的析构函数得不到释放 ...
- 详解C++中基类与派生类的转换以及虚基类
很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...
- C++多态性中基类析构函数声明为虚函数
在用基类指针指向派生类时, 在基类析构函数声明为virtual的时候,delete基类指针,会先调用派生类的析构函数,再调用基类的析构函数. 在基类析构函数没有声明为virtual的时候,delete ...
- lua中基类和“继承机制”
基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lu ...
- (转) C++中基类和派生类之间的同名函数的重载问题
下面有关派生类与基类中存在同名函数 fn: class A { public: void fn() {} void fn(int a) {} }; class B : public A { publi ...
- c++中基类与派生类中隐含的this指针的分析
先不要看结果,看一下你是否真正了解了this指针? #include<iostream> using namespace std; class Parent{ public: int x; ...
随机推荐
- Vue – 基础学习(4):事件修饰符
Vue – 基础学习(3):事件修饰符
- css flex兼容性
我测试了一下css flex的兼容性 已经可以兼容到IE10了呀 为啥MDN上面的IE兼容性还是兼容到IE11 有点更新不及时的感觉
- C# 连接数据操作的时候抛异常,连接超时
先说说我的业务.我在发送优惠券的时候,同时给6千多个会员发送优惠券,执行了update 和insert语句,这写语句都是通过字符串拼接而来的.update和insert语句加起来一共是一万多条语句.在 ...
- 下载win10系统
有时候想重装系统但总找不到下载的地方,今天记录一下.nsdn我告诉你,这里有许多软件下载 网站URL:https://msdn.itellyou.cn/ 我想下载一个Windows10 磁力地址 ed ...
- logger(三)log4j2简介及其实现原理
一.log4j2简介 log4j2是log4j 1.x和logback的改进版,据说采用了一些新技术(无锁异步.等等),使得日志的吞吐量.性能比log4j 1.x提高10倍,并解决了一些死锁的bug, ...
- 关于pytest的命令行传参
#conftest.py import pytest def pytest_addoption(parser): #parser:用户命令行参数与ini文件值的解析器 # group = parser ...
- axios跨域处理
本质分析: 因为axios在vue中利用中间件http-proxy-middleware做了一个本地的代理服务A,相当于你的浏览器通过本地的代理服务A请求了服务端B,浏览器通过服务A并没有跨域,因此就 ...
- Sonarqube C#静态代码规范检查(一)
使用说明 代码规范对于每个开发来说重要也重要,说不重要其实也没那么重要,简单点的vs的code analysis也能提供很多的建议,重量级一点的Resharper不仅能提供建议,还提供了更方便快捷的一 ...
- Spring Cloud微服务安全实战_2-1_开发环境
开发环境: JDK :1.8 IDE : idea 数据库:mysql 5.6.5 框架:springboot,mybatisplus PGA:(后边用到再安装) Promethus (普罗米修斯 ...
- 原生php分页的封装,只封装函数,可适用所有的表
<?php/** * 封装分页函数 * $table [字符串] 表名 * @$size [数字][每页显示条数] */function fenye($table, $size){ $link ...