C++ 消失的析构函数 —— virtual 实现的动态析构
在C++类的结构中可以使用类方法创建内存,使用类的析构函数去施放内存,但有这么一种情况会导致:即使在析构函数中释放了内存,但由于析构函数没有被调用而导致内存泄漏,如下代码。
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 class Father
7 {
8 public:
9 Father(const char* addr = "Father 带参构造")
10 {
11 cout << "执行了 Father 的构造函数" << endl;
12 int len = strlen(addr) + 1;
13 this->addr = new char[len];
14 strcpy_s(this->addr, len, addr);
15 }
16
17 ~Father()
18 {
19 cout << "执行了 Father 的析构函数" << endl;
20 if (this->addr)
21 {
22 delete addr;
23 addr = NULL;
24 }
25 }
26 private:
27 char *addr;
28 };
29
30
31 class Son :public Father
32 {
33 public:
34 Son(const char *game = "Son 带参构造", const char *addr = "继承 Father 带参构造" ) :Father(addr)
35 //Son(const char* game = "Son 带参构造")
36 {
37 cout << "执行了 Son 的构造函数" << endl;
38 int len = strlen(game) + 1;
39 this->game = new char[len];
40 strcpy_s(this->game, len, game);
41 }
42 ~Son()
43 {
44 cout << "执行了 Son 的析构函数" << endl;
45 if (this->game)
46 {
47 delete game;
48 game = NULL;
49 }
50 }
51
52 private:
53 char* game;
54 };
55
56 int main()
57 {
58 cout << "--------case 1----------" <<endl;
59 Father* father = new Father();
60 delete father;
61
62 cout << "\n--------case 2----------" << endl;
63 Son* son = new Son();
64 delete son;
65
66 cout << "\n--------case 3----------" << endl;
67 father = new Son();
68 delete father;
69
70 return 0;
71 }
运行结果:

以上打印,case 1和case 2都正常。再看67行代码,在看 case 3 的打印,会发现少释放一个 Son ,
而解决这个问题也很简单,讲父类的析构函数修饰为虚函数便可。还是上边的代码,第17行,父类析构函数前增加 virtual:
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 class Father
7 {
8 public:
9 Father(const char* addr = "Father 带参构造")
10 {
11 cout << "执行了 Father 的构造函数" << endl;
12 int len = strlen(addr) + 1;
13 this->addr = new char[len];
14 strcpy_s(this->addr, len, addr);
15 }
16
17 virtual ~Father()
18 {
19 cout << "执行了 Father 的析构函数" << endl;
20 if (this->addr)
21 {
22 delete addr;
23 addr = NULL;
24 }
25 }
26 private:
27 char *addr;
28 };
29
30
31 class Son :public Father
32 {
33 public:
34 Son(const char *game = "Son 带参构造", const char *addr = "继承 Father 带参构造" ) :Father(addr)
35 //Son(const char* game = "Son 带参构造")
36 {
37 cout << "执行了 Son 的构造函数" << endl;
38 int len = strlen(game) + 1;
39 this->game = new char[len];
40 strcpy_s(this->game, len, game);
41 }
42 ~Son()
43 {
44 cout << "执行了 Son 的析构函数" << endl;
45 if (this->game)
46 {
47 delete game;
48 game = NULL;
49 }
50 }
51
52 private:
53 char* game;
54 };
55
56 int main()
57 {
58 cout << "--------case 1----------" <<endl;
59 Father* father = new Father();
60 delete father;
61
62 cout << "\n--------case 2----------" << endl;
63 Son* son = new Son();
64 delete son;
65
66 cout << "\n--------case 3----------" << endl;
67 father = new Son();
68 delete father;
69
70 return 0;
71 }
打印结果:
申请的内存均正确的释放。

结论:当我们把父类的析构函数定义为虚函数,这种修饰不是为了重写,他会让 Father 类(基类)的指针进行 Delete 操作时使用动态析构(如果这个指针指向的是子类对象,那么会先调用该子类的析构函数,然后在调用自己类的析构函数)。
养成习惯:为了防止内存泄漏,最好是在基类的析构函数上添加关键字 virtual ,使基类析构函数为虚函数。
======================================================================================================================
C++ 消失的析构函数 —— virtual 实现的动态析构的更多相关文章
- 析构函数virtual与非virtual区别 [转]
作为通常的原则,如果一个类定义了虚函数,那么它的析构函数就应当是virtual的.因为定义了虚函数则隐含着:这个类会被继承,并且会通过基类的指针指向子类对象,从而得到多态性. 这个类可能会被继承, ...
- effective c++:virtual函数在构造函数和析构函数中的注意事项
如不使用自动生成函数要明确拒绝 对于一个类,如果你没有声明,c++会自动生成一个构造函数,一个析构函数,一个copy构造函数和一个copy assignment操作符. class Empty { p ...
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数
http://blog.csdn.net/freeboy1015/article/details/7635012 为什么内联函数,构造函数,静态成员函数不能为virtual函数? 1> 内联函数 ...
- C++虚析构函数解析
当派生类对象从内存中撤销时一般先运行派生类的析构函数,然后再调用基类的析构函数. 如果用new运算符建立的派生类的临时对象,对指向基类的指针指向这个临时对象当用delete运算符撤销对象时,系统执行的 ...
- 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?
五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的 ...
- 虚函数(virtual)为啥不能是static
静态成员函数,可以不通过对象来调用,即没有隐藏的this指针. virtual函数一定要通过对象来调用,即有隐藏的this指针. static成员没有this指针是关键!static function ...
- C++回顾day03---<纯虚函数和抽象类以及虚析构函数,delete使用>
一:纯虚函数和抽象类 纯虚函数是一个在基类中说明的虚函数,在基类中没有定义,要求任何派生类都定义自己的版本 纯虚函数为各个派生类提供一个公共接口 纯虚函数的形式: virtual 类型 函数名(参数列 ...
- C++ 在继承中使用virtual
使用virtual:如果方法是通过引用类型或指针而不是对象调用的,它将确定使用哪一种方法.如果没有使用关键字irtual,程序将根据引用类型或指针类型选择方法:如果使用了irtual,程序将根据引用或 ...
- C++学习---- virtual的三种用法
virtual用法一:多态 #include<iostream> using namespace std; class A{ public: virtual void display(){ ...
随机推荐
- Docker版EKL安装记录文档
Docker版EKL安装记录文档 拉取已下三个镜像 docker.io/logstash 7.5.2 b6518c95ed2f 6 months ago 805 MB docker.io/kibana ...
- CSS opacity设置不透明度
1.opacity设置不透明度 opacity会将含有这个属性的子类都变成具有opacity属性,可以改变元素.元素内容.字标签的不透明度.而rgba只会改变设置的那个背景颜色的透明度效果 <! ...
- 使用Java将XSL和XML文件输出为HTML(XSL学习笔记二)
XSL 指扩展样式表语言(EXtensible Stylesheet Language),前面一篇博客介绍了使用XSL即可直接将XML输出为HTML片段被浏览器解析,但是这样在web应用中浏览器的解析 ...
- ssh 方面问题总结
ssh 远程执行命令: https://www.cnblogs.com/youngerger/p/9104144.html ssh免密登录: https://blog.csdn.net/jeikerx ...
- 实验吧[WEB]——程序逻辑问题
拿到题 通过查看网页源代码发现index.txt 通过index.txt我们获得了后端的源代码 我们可以通过我画出来的这两个重要的信息得知 第一个sql查询语句没有任何过滤说明存在SQL注入漏洞. 第 ...
- 安装git和lsof
yum install git yum install lsof 查看80端口 lsof -i:80
- jmeter录制请求
用了一段时间的jmeter感觉比LR方便很多,界面也比较简洁,开源免费,配置环境也方便,LR简直没法比,但唯一的是功能没有LR强大,毕竟是免费的,要求别那么高. 下面开始进入正题,配置环境和下载就不多 ...
- JQuery案例:购物车编辑
购物车编辑 实现了:商品的加减,总价的变动 实现了:全选/全不选(使用prop而不是attr) 实现了:删除(遮罩层) <html> <head> <meta chars ...
- JQuery案例:左右选
左右选 <head> <meta charset="UTF-8"> <title></title> <style> se ...
- 容器中实现拉取其它服务器的jar包程序
缘由:在做接口自动化测试时,若业务场景有一个前置仓库,在该仓库内完成一系列的场景测试,一旦某一场景测试失败,脏数据对环境造成影响则需要清理: 1.我容器的内核系统为Debian GNU/Linux 1 ...