【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; ...
 
随机推荐
- Linux C 后台服务程序单进程控制
			
介绍 通常后台服务器程序都必须有且只有一个进程,那么如何单进程呢? 本例子是通过flock函数对/var/run/myserver.pid记录pid文件的进行加锁 若加锁不正常,说明后台服务进程已经在 ...
 - 实现HTML调用打开本地软件文件
			
有时候我们想要实现一个功能,就是在HTML页面点击一个链接就能调用打开本地可执行文件.就像腾讯QQ.迅雷这种. 而实现这种功能其实也很简单,就是需要我们添加修改注册表,实现自定义URL Protoco ...
 - TinyMCE基础配置
			
选择器配置 插件配置 工具栏配置 菜单配置 皮肤配置 编辑区宽高配置 编辑区样式配置 隐藏状态栏 选择器配置 选择器就是CSS选择器,它告诉TinyMCE哪个元素是可编辑的. 示例: tinymce. ...
 - RMAN笔记
			
Rman常用命令 Preview选项 1) 显示用于还原system表空间数据文件的备份文件 RMAN> restore datafile 2 preview; 2) 显示用于还原特 ...
 - 【学习笔记】PYTHON语言程序设计(北理工 嵩天)
			
1 Python基本语法元素 1.1 程序设计基本方法 计算机发展历史上最重要的预测法则 摩尔定律:单位面积集成电路上可容纳晶体管数量约2年翻倍 cpu/gpu.内存.硬盘.电子产品价格等都遵 ...
 - 2.redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?
			
作者:中华石杉 面试题 redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 面试官心理分析 这个是问 redis 的时候,最基本的 ...
 - PAT 乙级 1036.跟奥巴马一起编程 C++/Java
			
题目来源 美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014 年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏 ...
 - Android架构师吐槽腾讯王者荣耀的程序员,排位匹配算法怎么搞的,每次都输
			
腾讯王者荣耀的开发来来来出来聊聊,真是日了狗了,多次离上王者还差两三颗星的时候队友就开始水的一塌糊涂,对面就牛逼的不行. 又连跪回去了,被对面把屎都打出来了,实在忍不住来吐槽,你们这个排位匹配算法到底 ...
 - 费马平方和定理&&斐波那契恒等式&&欧拉四平方和恒等式&&拉格朗日四平方和定理
			
费马平方和定理 费马平方和定理的表述是:奇素数能表示为两个平方数之和的充分必要条件是该素数被4除余1. 1. 如果两个整数都能表示为两个平方数之和的形式,则他们的积也能表示为两个平方数之和的形式. $ ...
 - Flask内的特殊装饰器
			
@app.template_global() # 全局变量 @app.template_filter() # 偏函数 @app.before_request # 请求进入视图函数之前,比 ...