C++中有无数的坑,但毕竟……

今天就踩到了,也算是基本问题了,记录一下,顺便以后可以考考自己。你也可以猜猜答案,大牛绕行。

0x1 先看这个:

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
Bpp* b = new Bpp();
delete b; system("pause");
return ;
}

结果:

~Bpp

~App
请按任意键继续. . .

0x02 : 再来 ,改了第32行

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
App* b = new Bpp();
delete b; system("pause");
return ;
}

结果:

~App
请按任意键继续. . .

0x03 下一个 改动 7 line

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
virtual ~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
App* b = new Bpp();
delete b; system("pause");
return ;
}

结果:

~Bpp

~App
请按任意键继续. . .

0x04 next 改动 line 20

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
virtual ~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
virtual ~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
App* b = new Bpp();
delete b; system("pause");
return ;
}

结果和 0x03一样:

~Bpp

~App
请按任意键继续. . .

0x05 接着 再在第7 行中 去掉 virtual

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
virtual ~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
App* b = new Bpp();
delete b; system("pause");
return ;
}

结果:

在33行,程序报错,崩溃。

0x6 改动 32行:

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
virtual ~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
void* b = new Bpp();
delete b; system("pause");
return ;
}

结果:执行成功。

请按任意键继续. . .

0x07 把所有 virtual 去掉

#include <stdio.h>
#include <stdlib.h> class App
{
public:
~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
void* b = new Bpp();
delete b; system("pause");
return ;
}

结果:

请按任意键继续. . .

0x08 加上所有 virtual :

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
virtual ~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
virtual ~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
void* b = new Bpp();
delete b; system("pause");
return ;
}

结果:

请按任意键继续. . .

0x09 最后:

 #include <stdio.h>
#include <stdlib.h> class App
{
public:
~App()
{
printf("\n~App\n");
}
void output()
{
printf("A");
}
}; class Bpp : public App
{
public:
virtual ~Bpp()
{
printf("\n~Bpp\n");
}
void output()
{
printf("B");
}
}; int main(char args[])
{
Bpp* b = new Bpp();
delete b; system("pause");
return ;
}

结果,可以猜猜:

 ~Bpp

 ~App
请按任意键继续. . .

最后的答案

结语:

1. 通常应该给基类提供一个虚析构函数,即使它不需要析构函数 —— 《C++ Primer Plus (第6版)中文版》, 505页

2. 如果一个类带有任何 virtual 函数,这个类就应该拥有 virtual 析构函数 —— 《Effective C++ 中文版,第三版》,条款07:为多态基类声明 virtual 析构函数,44页

3. 如果一个类被当作基类(也就是说这个类需要被其他类继承),那这个类的析构函数就要加上 virual 关键字!

【日常】C++ 的那些“坑” —— delete 与 析构函数 与 virtual 的 9 个小例子的更多相关文章

  1. new、delete、析构函数、自动类型转换

    new 分配内存,返回指针 new 类型名T (初值列表) 功能:申请用于存放T类型对象的内存空间,并依初值列表赋以初值 结果值: 成功->T类型的指针,指向新分配的内存 失败->0(NU ...

  2. delete和析构函数

    new一个类的时候,调用这个类的构造函数,然后在这个类的生命周期内可能会动态生成很多指向堆上的内存,所以应该在析构函数里回收这些内存: 当delete这个类的时候,会首先调用这个类的析构函数,即回收生 ...

  3. JavaScript日常会跳的坑系列(二)

    1.Number()将部分非数字类型转换为0 强制转换为数值类型函数: parseFloat.parseInt 优点:对非数值类型统一返回NaN 缺点:会将一部分符合数值类型的字符串也识别为数值 pa ...

  4. C++类继承--基类析构函数加上Virtual

    下面的内容要说明两个问题:1. 基类的析构函数为什么要加上Virtual--防止内存泄露 1. 基类虚构函数无virtual,派生类无法析构,会导致内存泄露 #include <stdio.h& ...

  5. C++类中使用new及delete小例子

    //默认复制构造函数的不足//尽管有默认的复制构造函数来解决一般对象与对象之间的初始化问题, 但是在有些情况下我们必须手动显式的去定义复制构造函数, 例如: #include <iostream ...

  6. activiti 用户手册中 10分钟 小例子 简单代码搭建 及 其中的 各种坑

    看mossle的 5.16 用户手册中的  快速起步:10分钟教程 想自己跑一下,虽然官方文档已经写的非常详细了,但是实际操作中还是遇到各种坑,这里记录下来. 首先官网下载最新的 5版本 full G ...

  7. C++类中使用new及delete小例子(续)

    在该示例中我们显式定义了复制构造函数来代替默认复制构造函数, 在该复制构造函数的函数体内, 不是再直接将源对象所申请空间的地址赋值给被初始化的对象, 而是自己独立申请一处内存后再将源对象的属性复制过来 ...

  8. C/C++ New与Delete (小例子)

    转自:http://blog.csdn.net/chenzujie/article/details/7011639   先来看两段小程序: 1). #include <iostream.h> ...

  9. Chrome 开发者工具中的命令菜单

    单 大家对命令菜单(Command Menu)应该都不陌生.目前主流的编辑器中都内置了对该功能的支持.在 Sublime Text 和 Visual Studio Code 中你都可以通过快捷键 Ct ...

随机推荐

  1. 九度oj1163题

    题目描述: 输入一个整数n(2<=n<=10000),要求输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数,如果没有则输出-1. 输入: 输入有多组数据. 每组一行,输入n. ...

  2. ImportError: No module named cv2 解决方法

    ImportError: No module named cv2 解决方法   import cv2时会出现这个问题 解决方法:将openCV安装目录里的python文件夹内的cv2.pyd复制到Py ...

  3. Unity中溶解shader的总结

    在实际的游戏工程中,经常美术和策划会提出溶解的表现要求.比如子弹在飞行的时候,弹道不断的消融:角色受到大型炮弹的攻击,在击飞的时候不断的消融等等诸如此类的表现.一般的消融都是结合粒子系统来实现,通过给 ...

  4. 读headFirst设计模式 - 装饰者模式

    继承可以在复用父类代码的情况下扩展父类的功能,但同时继承增加了对象之间的耦合度,所以要慎用继承.那么有没有既能扩展父类的功能,又能使对象间解耦的方法呢?答案是肯定的,这就是我们今天要学习的装饰者模式. ...

  5. 介绍Office 365 中文用户社区 4.0

    本文于2017年3月18日首发于LinkedIn,原文链接在这里 为了给广大用户提供一个可以自由交流.切磋技术的平台,微软和其他一些国际知名的大型软件公司一样,都有创建用户社区(Community,或 ...

  6. 如何使用bootstrap

    前言: 前几天,本想做一个登陆界面,但自己写form表单必然很丑,所以想用下bootstarp框架,之前听别人说bootstrap很牛的样子.但我完全不会bootstrap... 下载&目录 ...

  7. swig编译GDAL的C#库时遇到的代码安全问题及解决方法

    之前一直用的是别人编译好的gdal库开发,今天自己编译了gdal的2.0.0版本,踩了不少坑,但总算解决了. 编译方法主要参考http://blog.csdn.net/liminlu0314/arti ...

  8. Oracle子查询中any、some、all之间的区别

    用some,any和all对子查询中返回的多行结果进行处理. 下面我们来简单介一下这几个关键词的含义. * Some在此表示满足其中一个的意义,是用or串起来的比较从句. * Any也表示满足其中一个 ...

  9. 使用VS2015将解决方案同步更新到Github上

    如今开源已经是一种趋势与潮流了,今天就来谈一谈如何将利用VS将我们的解决方案同步更新到Github上. 第一步:登录自己的Github账号(没有的自行注册). 我的Github登录后的界面: 第二步: ...

  10. mysql中 decimal、numeric数据类型

    例 如:salary DECIMAL(5,2) 在这个例子中,5 (精度(precision)) 代表重要的十进制数字的数目,2 (数据范围(scale)) 代表在小数点后的数字位数.在这种情况下,因 ...