在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 实现的动态析构的更多相关文章

  1. 析构函数virtual与非virtual区别 [转]

    作为通常的原则,如果一个类定义了虚函数,那么它的析构函数就应当是virtual的.因为定义了虚函数则隐含着:这个类会被继承,并且会通过基类的指针指向子类对象,从而得到多态性.   这个类可能会被继承, ...

  2. effective c++:virtual函数在构造函数和析构函数中的注意事项

    如不使用自动生成函数要明确拒绝 对于一个类,如果你没有声明,c++会自动生成一个构造函数,一个析构函数,一个copy构造函数和一个copy assignment操作符. class Empty { p ...

  3. 为什么内联函数,构造函数,静态成员函数不能为virtual函数

    http://blog.csdn.net/freeboy1015/article/details/7635012 为什么内联函数,构造函数,静态成员函数不能为virtual函数? 1> 内联函数 ...

  4. C++虚析构函数解析

    当派生类对象从内存中撤销时一般先运行派生类的析构函数,然后再调用基类的析构函数. 如果用new运算符建立的派生类的临时对象,对指向基类的指针指向这个临时对象当用delete运算符撤销对象时,系统执行的 ...

  5. 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?

    五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的 ...

  6. 虚函数(virtual)为啥不能是static

    静态成员函数,可以不通过对象来调用,即没有隐藏的this指针. virtual函数一定要通过对象来调用,即有隐藏的this指针. static成员没有this指针是关键!static function ...

  7. C++回顾day03---<纯虚函数和抽象类以及虚析构函数,delete使用>

    一:纯虚函数和抽象类 纯虚函数是一个在基类中说明的虚函数,在基类中没有定义,要求任何派生类都定义自己的版本 纯虚函数为各个派生类提供一个公共接口 纯虚函数的形式: virtual 类型 函数名(参数列 ...

  8. C++ 在继承中使用virtual

    使用virtual:如果方法是通过引用类型或指针而不是对象调用的,它将确定使用哪一种方法.如果没有使用关键字irtual,程序将根据引用类型或指针类型选择方法:如果使用了irtual,程序将根据引用或 ...

  9. C++学习---- virtual的三种用法

    virtual用法一:多态 #include<iostream> using namespace std; class A{ public: virtual void display(){ ...

随机推荐

  1. rbd-mirror配置指南-单向备份

    前言 RBD 的 mirroring 功能将在Jewel中实现的,这个Jewel版本已经发布了很久了,这个功能已经在这个发布的版本中实现了,本来之前写过一篇文章,但是有几个朋友根据文档配置后,发现还是 ...

  2. mysql 创建数据库知识总结

    表设计 库名.表名.字段名必须使用小写字母,"_"分割,且名称长度不超过12个字符并且要做到见名知意. 建议使用InnoDB存储引擎. 存储精确浮点数必须使用DECIMAL替代FL ...

  3. Spring中@Translational注解失效场景

    今天面试被问到@Translational注解什么场景下失效,我一脸懵逼,说的恍恍惚惚的,下来我就总结一下@Translational注解失效的场景! @Transactional 注解相信大家并不陌 ...

  4. Android ContentProvider 启动分析

    对于 ContentProvider 还不是很熟悉的同学,可以阅读上一篇 Android ContentProvider 基本原理和使用详解.本文主要是对 contentProvider 的源码进行分 ...

  5. 安装Ubuntu16.04系统后分辨率底的问题

    问题描述:安装Ubuntu系统后有可能会遇到分辨率很低的问题,别着急,这是一个小问题. 解决方案:修改/etc/default/grub,打开终端用命令:sudo gedit /etc/default ...

  6. 打开WPS时出现MathType错误弹窗怎么办

    MathType是一款特别优秀的公式编辑器,特别是在文档中出现大量的复杂数学公式需要编辑时.不过MathType与Office的兼容性还算好,与WPS的兼容性要略逊一筹,有时候会出现如下的报错弹窗.提 ...

  7. Vegas让人物回眸更有韵味的方法分享

    "回眸一笑百媚生,六宫粉黛无颜色",是白居易在<长恨歌>中描述杨贵妃美貌的名句,这一句运用夸张的手法,反映了杨贵妃回眸时的娇媚横生,百般娇媚. 接下来,小编就教你用视频 ...

  8. 重新认识Lombok

    Lombok插件 简介 那么lombok到底是个什么呢,lombok是一个可以通过简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 Java 代码的工具,简单来说,比如我们新建了一个类,然后 ...

  9. 从Guarded Block来看Java中的wait和notify方法

    目录 预备知识 概览 线程同步 wait()方法 wait() wait(long timeout) wait(long timeout, int nanos) notify() & noti ...

  10. 检查字符串结尾 判断一个字符串(str)是否以指定的字符串(target)结尾。

    function confirmEnding(str, target) { var arr = str.replace(/\s+/g, ""); var bb = arr.subs ...