析构函数virtual与非virtual区别 [转]
作为通常的原则,如果一个类定义了虚函数,那么它的析构函数就应当是virtual的。因为定义了虚函数则隐含着:这个类会被继承,并且会通过基类的指针指向子类对象,从而得到多态性。 这个类可能会被继承,并且会通过基类的指针指向子类对象”,因此基类的析构函数是否为虚将决定子类的对象是否被析构
示例代码:
#include <iostream.h> struct A
{
virtual ~A() {cout<<"~A()\n";}
}; struct B: public A
{
~B() {cout<<"~B()\n";}
}; void main()
{
A* p = new B;
delete p;
}
如果 A的析构函数不是virtual的,那么此时就不是先调用B的析构函数再调用A的析构函数。
Output:
~A();
如果A 的析构函数为virtual,则先~B(),再~A()
Output:
~B();
~A();
类如果会被派生的话,析构函数一般都应该定义为virtual的,主要不是防止内存泄露,而是为了正确的析构。如果是个封闭类(即不再被派生),就不要定义为virtual的。虚函数毕竟耗费较大的。
不用virtual 的几种情况:
1、作为非公有基类。仅作为 private base class 使用的 class 不需要使用虚拟析构函数
2、不作为接口使用的基类。
3. 如果你可以保证这个类不被public继承(private/protected继承的话,在非friend函数/类中就无法用基类指针指向派生类了)
4. 如果它的所有派生类(包括派生类的派生类)的析构函数都是trivial的(这里的trivial指的是在程序员的层次什么事也不做)
5. 如果不需要用基类的指针指向派生类的对象
在这五种情况下,不把析构函数声明为virtual都是可以的,何况效率会高一些——但前提是你得保证前提的成立——不过这些保证常常是很难100%的:谁能保证别人在派生你的类的时候,析构函数是trivial的,或者别人不用你提供的基类的指针指向派生类对象?这些常常是很难得到保证的。
声明基类的析构函数为virtual并非总是为了防止memory leak 另外这也只是作为一般的原则(基类中有虚函数则把其析构函数声明为virtual)。如果你的析构函数什么事也不作,从效果上来说,不声明为virtual也无妨.
析构函数virtual与非virtual区别 [转]的更多相关文章
- C++-基类的析构函数为什么要加virtual虚析构函数(转)
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...
- C#中virtual与abstract的区别
C#中virtual与abstract的区别 C#的virtual & abstract经常让人混淆,这两个限定词都是为了让子类进行重新定义,覆盖父类的定义.但是用法上差别很大. a) ...
- asp.net中virtual和abstract的区别
这篇文章主要介绍了asp.net中virtual和abstract的区别,较为详细的分析了virtual与abstract的概念与具体用法,并以实例的形式予以总结归纳,需要的朋友可以参考下 本文实例分 ...
- asp.net中virtual和abstract的区别分析
这篇文章主要介绍了asp.net中virtual和abstract的区别,较为详细的分析了virtual与abstract的概念与具体用法,并以实例的形式予以总结归纳,需要的朋友可以参考下 本文实例分 ...
- C#中virtual和abstract的区别
先说区别: virtual意思是虚拟,abstract意思是抽象. virtual只修饰方法,abstract修饰方法和类. virtual方法必须有实现,abstract方法必须没有实现. publ ...
- 【C++】C++中基类的析构函数为什么要用virtual虚析构函数?
正面回答: 当基类的析构函数不是虚函数,并且基类指针指向一个派生类对象,然后通过基类指针来删除这个派生类对象时,如果基类的析构函数不是虚析构函数,那么派生类的析构函数就不会被调用,从而产生内存泄漏 # ...
- c++ virtual 和 pure virtual的区别
参考资料: http://stackoverflow.com/questions/1306778/c-virtual-pure-virtual-explained 验证代码: #include < ...
- 析构函数和Dispose的使用区别
老生常谈的问题了,MSDN也有非常详细的说明但看起来不是很系统.也曾经做过分析,但没有总结下来又忘了,这次整理一下MSDN和网上搜集的一些资料,以备不时只需. 下面是MSDN对这两个函数的建议使用方法 ...
- IO多路复用,同步,异步,阻塞和非阻塞 区别
一.什么是socket?什么是I/O操作? 我们都知道unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO.管道.终端,对我们来说,一切都是 ...
随机推荐
- jquery右键菜单
点击这里体验效果 如果要屏蔽页面原来的右键菜单,请设置disable_native_context_menu:true 以下是源代码: <!DOCTYPE html> <html&g ...
- JavaScript toUpperCase() 方法和 toLowerCase() 方法
1,toUpperCase() 方法用于把字符串转换为大写. 一个新的字符串,在其中 stringObject 的所有小写字符全部被转换为了大写字符. 语法为: stringObject.toUppe ...
- 学习zepto.js(对象方法)[6]
first: 获取当前对象集合中的第一个dom元素. $("div").first(); // 返回第一个div对象(zepto对象) //相当于$("div" ...
- JAVA静态代理模式(从现实生活角度理解代码原理)
代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问. 代理模式说白了就是"真实对象"的代表,在访问对象时引入一定程度的间接性,因为这种间接性可以附加多种用途. 在 ...
- iOS开发之功能模块--本地序列化
下面只展示项目开发中,本地序列化的示例代码: AuthenticationManager.h #import <Foundation/Foundation.h> #import " ...
- 从0到1,教你实现基于Ruby的watir-webdriver自动化测试
一.为什么选择Ruby []完全开源. []多平台:Ruby可以运行在Linux, UNIX, Windows, MS-DOS, BeOS, OS/.. []多线程:线程就是指在一个程序中处理若干控制 ...
- Linux命令学习总结: file命令
命令简介: 该命令用来识别文件类型,也可用来辨别一些文件的编码格式.它是通过查看文件的头部信息来获取文件类型,而不是像Windows通过扩展名来确定文件类型的. 执行权限 :All User 指令所在 ...
- Linux 克隆虚拟机引起的“Device eth0 does not seem to be present, delaying initialization”
虚拟机Vmware上克隆了一个Red Hat Enterprise Linx启动时发现找不到网卡,如下所示,如果你在命令窗口启动网络服务就会遇到"Device eth0 does not s ...
- DDD实施经验分享—价值导向、从上往下进行(圈内第一个吃螃蟹DDD实施方案)
阅读目录: 1.背景 2.从业务开始 3.从战略到战术 4.借助外力推动研发(QA.领导.自动化测试) 5.领域模型与SAAS平台的内核(价值最大化) 6.最后 1.背景 DDD本身的技术就不介绍了, ...
- 《java JDK7 学习笔记》之异常处理
1.java中所有的错误都会被打包为对象,JVM会尝试执行try区块中的程序代码,如果发生错误,执行流程会跳离错误发生点,然后比较catch括号中声明的异常类型,是否符合被抛出的错误对象类型,如果是的 ...