C++明确指出:当派生类对象是由一个基类指针释放的,而基类中的析构函数不是虚函数,那么结果是未定义的。其实我们执行时其结果就是:只调用最上层基类的析构函数,派生类及其中间基类的析构函数得不到调用。

 #include <iostream>

 using namespace std;

 class TimeKeeper
{
public:
TimeKeeper();
~TimeKeeper();
};
TimeKeeper::TimeKeeper()
{
cout << "Construct TimeKeeper" << endl;
}
TimeKeeper::~TimeKeeper()
{
cout << "Destruct TimeKeeper" << endl;
} class WristWatch : public TimeKeeper
{
public:
WristWatch();
~WristWatch();
};
WristWatch::WristWatch()
{
cout << "Construct WristWatch" << endl;
}
WristWatch::~WristWatch()
{
cout << "Destruct WristWatch" << endl;
} int main()
{
TimeKeeper* pt = new WristWatch;
38 delete pt; // 仅调用TimeKeeper::~TimeKeeper
return ;
}

现在我们将基类的析构函数变为虚析构,代码只改动一行,在~TimeKeeper()前面加上virtual,那么用基类指针释放派生类对象时,就会先调用WristWatch::~WristWatch,然后调用TimeKeeper::~TimeKeeper。

注意:

1> 如果在定义一个类时可以确保该类不会作为多态的基类,那么不要为其定义虚析构函数。因为虚函数的实现机制会增大对象的空间(必须保存一个指向vtable的vptr指针,会占用32bit或者64bit的存储空间)。因此,经验是:只有当一个class中至少含有一个virtual函数,才为其定义virtual析构函数。

2> 不要从non-virtual析构函数的类型继承。

有时候让一个类带有pure virtual析构函数更便利一些:

 class Base
{
public:
virtual ~Base() = ; // pure virtual destructor
};
Base::~Base() // definition
{ }

主要有两方面的好处:

1> 你想拥有一个抽象类(接口),但还没找到任何有用的virtual函数可供使用

2> 同时解决了多态的析构调用问题。

但此时你必须注意:必须为这个pure virtual析构函数提供一个实现。因为在析构过程中,编译器会在派生类的析构函数中调用基类的析构函数,如果没定义,则必然发生错误。

总结:

  • 多态基类必须声明一个virtual析构函数。
  • 如果一个类中至少有一个virtual函数,说明该类的目的是作为多态基类存在,它就必须拥有一个virtual析构函数。
  • 如果设计一个类的目的不是作为基类使用,或者是基类但不具有多态性,那么不要声明virtual析构函数。

条款7:为多态基类声明virtual析构函数的更多相关文章

  1. Effective C++_笔记_条款07_为多态基类声明virtual析构函数

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个规则只适用于polymorphic(带多态性质的)base ...

  2. Effective C++ 条款七 为多态基类声明virtual析构函数

    class TimeKeeper { public: TimeKeeper(); // ~TimeKeeper(); 错误,此作为一个基类,被继承了.其继承类被delete后,基类被销毁,但继承类可能 ...

  3. 《effective C++》:条款07——为多态基类声明virtual析构函数

    在继承中,基类的析构函数需要定义为虚析构函数数否则: (1)当派生类对象经由一个base类指针删除时,而这个base类的析构函数不是虚函数时,其结果是未定义的. (2)这样做会导致derived类部分 ...

  4. 为多态基类声明virtual析构函数

    一个函数的返回值为基类指针,而当指针指向一个派生类对象,接下来派生类对象被这个基类指针删除的时候,就出现了局部销毁的问题.因为C++指出,当派生类经由一个基类指针被删除,而该基类指针带着一个non-v ...

  5. Effective C++ -----条款07:为多态基类声明virtual析构函数

    polymorphic(带多态性质的)base classes应该声明一个virtual析构函数.如果class带有任何virtual函数,它就应该拥有一个virtual析构函数. Classes的设 ...

  6. 【C++】为多态基类声明virtual析构函数

    来自<Effective C++>条款07:为多态声明virtual析构函数 当derived class对象经由一个base class指针被删除,而该base class带着一个non ...

  7. [Effective C++ --007]为多态基类声明virtual析构函数

    引言: 我们都知道类的一个很明显的特性是多态,比如我们声明一个水果的基类: class Fruit { public: Fruit() {}; ~Fruit(){}; } 那么我们根据这个Fruit基 ...

  8. effective c++(07)之为多态基类声明virtual析构函数

    class TimeKeeper { public: TimeKeeper() ; ~TimeKepper() ; ... } ; class AtomicClock:public TimeKeepe ...

  9. NO.6: 为多态基类声明virtual析构函数

    注意:polymorphic base class 应该具有虚析构函数,如果class带有任何virtual函数,也应具有虚析构函数 class不具备polymorphic属性则不应该声明virtua ...

随机推荐

  1. 开源项目:DolphinPlayer

    Dolphin Player是一款基于FFmpeg解码视频播放器,支持大多数的音频和视频格式. 项目主页:http://code.google.com/p/dolphin-player/ 源代码Git ...

  2. WWF3入门<第一篇>

    工作流是什么东西?暂时还不是很弄得清除. 工作流是用来解决什么问题的?暂时只是形成了一个很模糊的概念,还没办法用语言描述出来. 一.入门范例 以VS2008为例,先来创建一个WWF程序. 在工具箱中, ...

  3. WP_从独立存储区读取缓存的图片

      ///<summary> /// 独立存储缓存的图片源 /// 用法:item.img = new StorageCachedImage(newUri(http://www.baidu ...

  4. hbase日常运维管用命令,region管理

    1         Hbase日常运维 1.1       监控Hbase运行状况 1.1.1        操作系统 1.1.1.1 IO 群集网络IO,磁盘IO,HDFS IO IO越大说明文件读 ...

  5. JSF Action 与ActionListener的区别

    JSF Action 与ActionListener的区别 标签: 杂谈    事件  检验  参数  事件产生  页面跳转  Action  有 无参数,不传入当前控件,有返回值    当铵钮被单击 ...

  6. Oracle小数点格式化

    1. select to_char(123456789.12345,'fm999999990.99') from dual; 如果fm后位数不足则会显示 ## select to_char(12345 ...

  7. css3选择器 以及当天知道的东西

    10.25日伪类:a:link{}未访问的链接      a:visited{}已访问的链接     a:hover{}鼠标移动到链接上      a:active{}选定的链接  注:a:hover ...

  8. Linux安装VritualBox实现虚拟机win2003端口映射 支持远程

    1. 使用VNC登录到Linux系统 2. 安装VritualBox 找到VritualBox的软件包 这里的是run格式的 可以直接在终端运行  需要几分钟时间 3.VritualBox新建虚拟机 ...

  9. 如何调节datagridview中字体

    设置ColumnHeaderDefaultCellStyle的Font属性 或者 编程 datagridview.Columns[index].DefaultCellStyle.Font.Size=“ ...

  10. 控制不能离开Finally子句主体

    1.在try{}catch{}finally{}的结构中不可以将返回语句放置在finally的主体当中2.如果在catch{}中有向上一级从新抛出异常操作,在finally{}之后的语句将不会执行 3 ...