作为通常的原则,如果一个类定义了虚函数,那么它的析构函数就应当是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区别 [转]的更多相关文章

  1. C++-基类的析构函数为什么要加virtual虚析构函数(转)

    知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅:  C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...

  2. C#中virtual与abstract的区别

    C#中virtual与abstract的区别 C#的virtual & abstract经常让人混淆,这两个限定词都是为了让子类进行重新定义,覆盖父类的定义.但是用法上差别很大. a)     ...

  3. asp.net中virtual和abstract的区别

    这篇文章主要介绍了asp.net中virtual和abstract的区别,较为详细的分析了virtual与abstract的概念与具体用法,并以实例的形式予以总结归纳,需要的朋友可以参考下 本文实例分 ...

  4. asp.net中virtual和abstract的区别分析

    这篇文章主要介绍了asp.net中virtual和abstract的区别,较为详细的分析了virtual与abstract的概念与具体用法,并以实例的形式予以总结归纳,需要的朋友可以参考下 本文实例分 ...

  5. C#中virtual和abstract的区别

    先说区别: virtual意思是虚拟,abstract意思是抽象. virtual只修饰方法,abstract修饰方法和类. virtual方法必须有实现,abstract方法必须没有实现. publ ...

  6. 【C++】C++中基类的析构函数为什么要用virtual虚析构函数?

    正面回答: 当基类的析构函数不是虚函数,并且基类指针指向一个派生类对象,然后通过基类指针来删除这个派生类对象时,如果基类的析构函数不是虚析构函数,那么派生类的析构函数就不会被调用,从而产生内存泄漏 # ...

  7. c++ virtual 和 pure virtual的区别

    参考资料: http://stackoverflow.com/questions/1306778/c-virtual-pure-virtual-explained 验证代码: #include < ...

  8. 析构函数和Dispose的使用区别

    老生常谈的问题了,MSDN也有非常详细的说明但看起来不是很系统.也曾经做过分析,但没有总结下来又忘了,这次整理一下MSDN和网上搜集的一些资料,以备不时只需. 下面是MSDN对这两个函数的建议使用方法 ...

  9. IO多路复用,同步,异步,阻塞和非阻塞 区别

    一.什么是socket?什么是I/O操作? 我们都知道unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO.管道.终端,对我们来说,一切都是 ...

随机推荐

  1. CSS的::selection使用方法

    请选择本页面文本看看:http://hovertree.com/h/bjaf/38hq6y9d.htm CSS改变默认文本选中的颜色的方法 一般情况下在网页里的文本我们用鼠标选中的时候都是蓝色的,这个 ...

  2. 操作数数据类型 ntext 对于 max 运算符无效

    SoStyle.chi_description AS chi_description, SoStyle.description AS eng_description, SoStyle.chi_qual ...

  3. CSS3 Transitions, Transforms和Animation的使用

    一.前言 CSS3动画相关的几个属性是:transition, transform, animation:分别理解为过渡,变换,动画.虽意义相近,但具体的功能和在CSS3中承担的工作有一定的差异. t ...

  4. Android中AsyncTask分析--你所不注意的坑

    AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI ...

  5. 数据集转换为Json

    数据集转换为Json 第一步:新建一个类对象  通常我会写三个属性:状态.返回信息.数据集 第二步:新建一个JSON转换类 第三步:把类对象当做参数传入JSON转换类 ———————————————— ...

  6. ListView和Adapter的配合使用以及Adapter的重写

    ListView和Adapter的使用   首先介绍一下ListView是Android开发过程中较为常见的组件之一,它将数据以列表的形式展现出来.一般而言,一个ListView由以下三个元素组成: ...

  7. MySQL如何导出带日期格式的文件

    一网友问在MySQL中如何只用SQL语句导出带日期格式的文件.觉得有点意思,于是尝试了一下.导出文件使用SELECT INTO OUTFILE 但是OUTFILE后面的值不能使用变量,所以只能使用动态 ...

  8. 深入理解SQL的四种连接-左外连接、右外连接、内连接、全连接(转)

    1.内联接(典型的联接运算,使用像 =  或 <> 之类的比较运算符).包括相等联接和自然联接.     内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行.例如,检索 stude ...

  9. Terminate Instance 操作详解 - 每天5分钟玩转 OpenStack(33)

    本节通过日志详细分析 Nova Terminate 操作. Terminate 操作就是删除 instance,下面是 terminate instance 的流程图 向 nova-api 发送请求 ...

  10. Ubuntu 网络参数设置

    修改网络设置 sudo vim /etc/network/interfaces 修改计算机名 sudo vim /etc/hostname sudo vim /etc/hosts