【日常】C++ 的那些“坑” —— delete 与 析构函数 与 virtual 的 9 个小例子
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 个小例子的更多相关文章
- new、delete、析构函数、自动类型转换
new 分配内存,返回指针 new 类型名T (初值列表) 功能:申请用于存放T类型对象的内存空间,并依初值列表赋以初值 结果值: 成功->T类型的指针,指向新分配的内存 失败->0(NU ...
- delete和析构函数
new一个类的时候,调用这个类的构造函数,然后在这个类的生命周期内可能会动态生成很多指向堆上的内存,所以应该在析构函数里回收这些内存: 当delete这个类的时候,会首先调用这个类的析构函数,即回收生 ...
- JavaScript日常会跳的坑系列(二)
1.Number()将部分非数字类型转换为0 强制转换为数值类型函数: parseFloat.parseInt 优点:对非数值类型统一返回NaN 缺点:会将一部分符合数值类型的字符串也识别为数值 pa ...
- C++类继承--基类析构函数加上Virtual
下面的内容要说明两个问题:1. 基类的析构函数为什么要加上Virtual--防止内存泄露 1. 基类虚构函数无virtual,派生类无法析构,会导致内存泄露 #include <stdio.h& ...
- C++类中使用new及delete小例子
//默认复制构造函数的不足//尽管有默认的复制构造函数来解决一般对象与对象之间的初始化问题, 但是在有些情况下我们必须手动显式的去定义复制构造函数, 例如: #include <iostream ...
- activiti 用户手册中 10分钟 小例子 简单代码搭建 及 其中的 各种坑
看mossle的 5.16 用户手册中的 快速起步:10分钟教程 想自己跑一下,虽然官方文档已经写的非常详细了,但是实际操作中还是遇到各种坑,这里记录下来. 首先官网下载最新的 5版本 full G ...
- C++类中使用new及delete小例子(续)
在该示例中我们显式定义了复制构造函数来代替默认复制构造函数, 在该复制构造函数的函数体内, 不是再直接将源对象所申请空间的地址赋值给被初始化的对象, 而是自己独立申请一处内存后再将源对象的属性复制过来 ...
- C/C++ New与Delete (小例子)
转自:http://blog.csdn.net/chenzujie/article/details/7011639 先来看两段小程序: 1). #include <iostream.h> ...
- Chrome 开发者工具中的命令菜单
单 大家对命令菜单(Command Menu)应该都不陌生.目前主流的编辑器中都内置了对该功能的支持.在 Sublime Text 和 Visual Studio Code 中你都可以通过快捷键 Ct ...
随机推荐
- 【HAL库每天一例】freemodbus移植
例程下载:资料包括程序.相关说明资料以及软件使用截图 百度云盘:https://pan.baidu.com/s/1slN8rIt 密码:u6m1 360云盘:https://yunpan.cn/OcP ...
- JavaSE之认识java
本来很早之前就应该总结自己在JavaSE中系统学到的知识了,马上就要出去工作了,想想自己还是非常菜的菜鸟,自己就夜不能寐呀.现在从zero基础开始带大家一起回顾学习的基础知识. 现在已经是凌晨了,但是 ...
- Java 8并发工具包漫游指南
Java 8并发工具包简介 Java 8并发工具包由3个包组成,分别是java.util.concurrent.java.util.concurrent.atomic和java.util.concur ...
- 如何javascript获取css中的样式
obj.style.height只能获取行间样式,但是我们要怎么获取写在css文件中的样式呢? 首先我们要用一个新的方法currentStyle.这个方法由current和style两个单词组成意思是 ...
- 搭建高可用mongo集群3.4版本
搭建高可用mongo集群3.4版本 说在开始之前:在搭建这个环境之前,已经有了一个师兄搭好的环境,虽然一样很棒,但是没有经过自己的手出来的东西,还是不属于自己,所以摸索着自己搭建一个吧,好巧不巧的是, ...
- 【记录】iOS10 点击推送栏的问题
之前做的一个用户点击 推送栏然后处理相应事件是在这里面处理的 - (void)application:(UIApplication *)application didReceiveRemoteNoti ...
- docker工作流程
Docker提供一种方法在容器中运行安全隔离的应用程序,应用程序与所有依赖项和库一起打包在容器中.因为你的应用程序总是可以使用它在构建镜像中期望的环境运行,测试和部署比以往任何时候都更简单,因为你的构 ...
- 在NAS设备上用NFS服务为RAC数据库和集群件存储oracle文件时的mount选项
今天在家折腾自己的小实验室,把自己NAS上的一个目录用NFS挂载到一套11g RAC的实验环境中. 当我在备份数据库到NAS上时,发现一个奇怪的问题,同样的目录下,默认backup 备份集的情况,备份 ...
- Laravel Session 遇到的坑
这两天遇到了一个很奇怪的问题,更新session ,session的值不变.经过一番追查,终于找到问题,并搞明白了原理.写这篇博客记录下. 框架版本 Laravel 5.4 问题 先来描述下问题,我在 ...
- python爬虫实战(二)--------千图网高清图
相关代码已经修改调试----2017-3-21 实现:千图网上高清图片的爬取 程序运行20小时,爬取大约162000张图片,一共49G,存入百度云.链接:http://pan.baidu.com/s/ ...