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与Ceph的分与合
前言 docker是一个管理工具,在操作系统之上提供了一个新的独立轻环境,好处是本地提供了一个基础镜像,然后基于镜像再运行环境,也可以把环境重新打包为镜像,管理起来类似于git,感觉非常的方便,并且能 ...
- 循序渐进VUE+Element 前端应用开发(27)--- 数据表的动态表单设计和数据存储
在我们一些系统里面,有时候会需要一些让用户自定义的数据信息,一般这些可以使用扩展JSON进行存储,不过每个业务表的显示项目可能不一样,因此需要根据不同的表单进行设计,然后进行对应的数据存储.本篇随笔结 ...
- [web安全原理分析]-XEE漏洞入门
前言 1 前言 XXE漏洞 XXE漏洞全称(XML External Entity Injection)即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致 ...
- tp5配置引入使用redis
1.首先你的php得是已经安装了redis扩展的 2.在tp里找到config.php配置文件,找到cache,改成下面的样子 'cache' => [ // 选择模式 'type' => ...
- 鱼骨图是什么?怎么用iMindMap画鱼骨图?
鱼骨图是一种发现问题"根本原因"的方法,它也可以称之为"因果图".其特点是简捷实用,深入直观."鱼头"处标注的一般是问题或后果.按出现机会多 ...
- ThreadLocal以及强软弱虚引用
1.ThreadLocal ThreadLocal即线程本地,可以实现每个线程存入取出TreadLocal值互不影响.因为TheadLocal底层是用了一个Map结构存放数据,而这个Map是从当前这个 ...
- SRX_Test_2_sound
声音(sound) [问题描述] 雅礼中学的校门口在修建地铁,而由此带来的噪音问题让周边的居民困扰不已.环保局正在研究 一项评估模型,可以定量评价噪音的危害程度.这项评估模型是这样的:将每一条街道视作 ...
- nmap安装和使用
nmap安装和使用 安装 官网地址 https://nmap.org/download.html 许多流行的Linux发行版(Redhat.Mandrake.Suse等)都使用RPM软件包管理系统,方 ...
- Java蓝桥杯01——第一题集锦:堆煤球、购物单、哪天返回、第几天、分数
堆煤球(2016JavaB) 有一堆煤球,堆成三角棱锥形.具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形), .... 如果一共有100 ...
- day101:MoFang:模型构造器ModelSchema&注册功能之手机号唯一验证/保存用户注册信息/发送短信验证码
目录 1.模型构造器:ModelSchema 1.SQLAlchemySchema 2.SQLAlchemyAutoSchema 2.注册功能基本实现 1.关于手机号码的唯一性验证 2.保存用户注册信 ...