【日常】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 ...
随机推荐
- 雪花降落CADisplayLink
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px "PingFang SC"; color: #1d9421 } p.p2 ...
- Solr field alias
Field alias Any field, function, or transformer can be displayed with a different name in the output ...
- hdoj1072 Nightmare bfs
题意:在一个地图里逃亡,2是起点,3是终点,1是路,0是墙,逃亡者携带一个炸弹,6分钟就会炸,要在6分钟前到达4可以重制时间,问是否能逃亡,若能则输出最小值 我的思路:bfs在5步内是否存在3,存在则 ...
- PHP语言开发微信公众平台(订阅号)之curl命令
在开发过程中,经常会遇到要求用curl命令调用接口的情况 那么,什么是curl,简单来说curl是一个利用url语法规定来传输文件和哦数据的工具,支持很多协议,如 http.ftp.telent 等, ...
- 图解Javascript——作用域、作用域链、闭包
什么是作用域? 作用域是一种规则,在代码编译阶段就确定了,规定了变量与函数的可被访问的范围.全局变量拥有全局作用域,局部变量则拥有局部作用域. js是一种没有块级作用域的语言(包括if.for等语句的 ...
- Linux之lsof命令
lsof是一个列出当前系统中所有打开文件的工具 lsof filename 显示打开指定文件的所有进程 lsof -c string 显示COMMAND中包含指定字符的进程的所有打开文件 ...
- python复习。知识点小记
1.对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符: >>> ord('A') >>> ord('中' ...
- raise RuntimeError("autoconf error") RuntimeError: autoconf error
pip 安装模块时遇到下错误,没有粘贴全,差不多都是这样.这个情况是 pip 安装模块 需要 gcc 及 python-devle 支持, ubuntu 是 python-dev ,使用Yum 安装即 ...
- JDBC连接数据库实现删除功能
这次同样运用之前写过的部分代码进行改变,实现一个删除功能,这个功能很好添加,表单中只要form一个参数到DeleteServlet中,所以重点的代码还是在DeleteServlet中实现业务逻辑. 我 ...
- 1.Java集合总结系列:Java集合概述
一.概述 集合是 Java 中非常重要的 API,在实际应用中非常广泛,在许多面试中也是必考的知识点. Java 所有集合类都位于 java.util 包下,Java 的集合只能保存对象,而无法保存保 ...