虚析构函数

在 Effective C++ 中找到了答案。书中说到在 C++ 中,当派生类(derived class)对象由一个基类(base class)指针删除时,若基类有一个非虚函数(non-virtual)的析构函数时,其结果是未定义的——实际执行时通常发生的是对象的派生类部分没有被销毁。例如下面的示例:

#include <iostream>
using namespace std;class Shape
{
public:Shape() {cout <<"CRAT: shape" <<endl;}~Shape() {cout <<"DEST: shape" <<endl;}
};class Player
{
public:Player() {cout <<"CRAT: player" <<endl;}~Player() {cout <<"DEST: player" <<endl;}
};class Ball
{
public:Ball() {cout <<"CRAT: ball" <<endl;  }~Ball() {cout <<"DEST: ball" <<endl; }private:Shape shape_;
};class Football : public Ball
{
public:Football() {cout <<"CRAT: football" <<endl;}~Football() {cout <<"DEST: football" <<endl;}private:Player players_;
};int main()
{Ball *ball = new Football();delete ball;return 0;
}

结果:

CRAT: shape
CRAT: ball
CRAT: player
CRAT: football
DEST: ball
DEST: shape

可以看到,当基类指针指向派生类对象时,在删除对象时,并没有调用派生类成员对象及派生类自身的析构函数,而只是调用了基类成员对象及基类的析构函数,于是就造成了“局部销毁”对象的现象,从而导致内存泄露,正确的做法是为基类指定一个虚析构函数 。

为了避免上述问题的出现,我们是不是可以为每个类都声明一个虚析构函数呢?考虑如下的示例:

class Point
{
public:Point(int x, int y);~Point();private:int x_, y_;
};

上述Point类在32-bit机器上所占用的内存空间为8字节。若我们将Point类的析构函数指定为析函数,那么Point类不得不提供一个vptr(即,virtual table pointer)指针,它指向一个由函数指针构成的数组(vtbl, virtal table)。每个带有虚函数的类都有一个相应的vtbl。当对象调用某个虚函数时,实际被调用的函数取决于该对象的vptr所指向的那个vtbl。因此,无端的将所有类的析构函数声明为虚函数也是错误的。

总结:

1.带多态性质的基类应该声明一个虚析构函数,如果类中包含其他虚函数,也应该拥有一个虚析构函数。
2.若类的设计目的不是作为基类使用,或不是为了具备多态性,就不应该声明虚析构函数。

什么时候要用虚析构函数?
      通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。
      一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。
原因:
      在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。
那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。
注意:
如果不需要基类对派生类及对象进行操作,则不能定义虚函数(包括虚析构函数),因为这样会增加内存开销。

什么时候要用虚析构函数相关推荐

  1. C++继承中构造函数、析构函数调用顺序及虚析构函数

    首先说说构造函数,大家都知道构造函数里就可以调用成员变量,而继承中子类是把基类的成员变成自己的成员,那么也就是说子类在构造函数里就可以调用基类的成员了,这就说明创建子类的时候必须先调用基类的构造函数, ...

  2. unique函数_C++智能指针2:(虚?)析构函数(标准与实现的差异)

    只要是有良心的 C++ 教材,总是会苦心孤诣地告诫初学者,在继承关系中,应该把父类的析构函数定义成虚函数.这已然成为一条铁律,如果违背,不仅有内存泄漏的风险,在多继承情况下甚至会出现未定义行为.因此, ...

  3. C++对象模型7——类的成员函数、反汇编虚析构函数、RTTI、多态的开销

    一.类成员函数 class test { public:void myfunc(){}virtual void vfunc() {}static void sfunc() {} };void myfu ...

  4. C++编程进阶2(编译器在类内默认生成的函数讨论以及纯虚析构函数)

    三.编译器默认提供的类内函数讨论 1.当写下一个空类时,编译器会在必要的时候默认提供四个函数:构造.拷贝构造.operator=和析构函数,而且都是public的 class Empty{ }; 上述 ...

  5. 为什么一般要定义析构函数为虚析构函数

    没有使用虚析构函数可能会出现的问题: #include <iostream> #include <string> using namespace std;class A { p ...

  6. C++ 虚析构函数

    类型需要虚析构函数的另外一个特征 是该类型具有指针成员或引用成员.如果有指针成员和引用成员,则该类型通常需要实现析构函数以及拷贝操作. 通常,一个实现了析构函数的类型同时也需要实现拷贝构造函数与拷贝复 ...

  7. C++继承中析构函数 构造函数的调用顺序以及虚析构函数

    首先说说构造函数.大家都知道构造函数里就能够调用成员变量,而继承中子类是把基类的成员变成自己的成员,那么也就是说子类在构造函数里就能够调用基类的成员了,这就说明创建子类的时候必须先调用基类的构造函数, ...

  8. C++中基类的析构函数为什么要用virtual虚析构函数

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

  9. 多态基类与虚析构函数

    假设我们有一个基类A,很不幸的,A的析构函数是一个non-virtual.同时我们有一个派生类B,它派生自A. 我们定义了一个A类型指针,它指向的实际对象是B: A * ptr = new B; 然后 ...

  10. 【c++】28.虚析构函数、纯虚函数

    1.虚函数:在类的成员函数前面加virtual关键字的函数: 一般把虚函数定义在public区,方便在主函数中调用 如果一个类有一个虚函数,则该类就有一个虚函数列表,所有该类的对象都共享这个虚函数表: ...

最新文章

  1. CF-1207 G.Indie Album(Trie上跑AC自动机)
  2. Tip:使用Extender的ResolveControlID事件
  3. .NET Core 批量重置 Azure Blob Storage 的 mime type
  4. 2017.5.28 codeforce h题思考记录
  5. c语言malloc返回值,malloc(0)的返回值
  6. Atitit 物化视图与触发器性能测试方法 attilax总结 1.1. 触发器主要影响更新性能。。。 1 1.2. 临时打开关闭触发器,如果db不支持可以更改条件使其不触发 1 1.3. 打开定时
  7. RabbitMQ五种工作模式学习总结
  8. linux下keytool生成证书_keytool命令
  9. 手机通达信正在连接服务器,通达信服务器全部连接超时
  10. 简书的css排版,浅谈前端(WEB)排版
  11. SpringMVC —— @ResponseBody原理
  12. 论文阅读_Same Coverage, Less Bloat: Accelerating Binary-only Fuzzing with Coverage-preserving Coverage-g
  13. java wmf 转 svg_java处理word公式(wmf格式转换成svg)
  14. 操作系统学习总结(上)
  15. Linux后台进程管理
  16. thebrain 导出html,思维导图软件TheBrain最新问答集锦——如何让TheBrain文件轻松导出Zotero库...
  17. Scrapy爬虫:代理IP配置
  18. Android开发入门——推箱子游戏开发实战(十二)
  19. 机器学习实战 : k-近邻算法(史诗级干货长文)
  20. 从事金融行业需要考什么证书?

热门文章

  1. 北航操作系统课程-第九次作业-设备管理-IO与磁盘
  2. Linux服务器java海康威视SDK
  3. js 判断是 Android 设备还是苹果设备?
  4. 你工作快乐么?你的工作好么?——2011年终倾情奉献
  5. Python一键下载原神官网漫画,送给同样喜欢原神的人美心善你们
  6. fiddler之数据分析和查看(inspectors)-抓包
  7. Java 泛型,你了解类型擦除吗?
  8. 提示:‘for‘ loop can be replaced with enhanced ‘for‘
  9. 面试技术型中高层管理人员的问题
  10. WebMagic使用阿布云HTTP代理ip