条款7:为多态基类声明virtual析构函数

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

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class TimeKeeper
 6 {
 7 public:
 8     TimeKeeper();
 9     ~TimeKeeper();
10 };
11 TimeKeeper::TimeKeeper()
12 {
13     cout << "Construct TimeKeeper" << endl;
14 }
15 TimeKeeper::~TimeKeeper()
16 {
17     cout << "Destruct TimeKeeper" << endl;
18 }
19
20 class WristWatch : public TimeKeeper
21 {
22 public:
23     WristWatch();
24     ~WristWatch();
25 };
26 WristWatch::WristWatch()
27 {
28     cout << "Construct WristWatch" << endl;
29 }
30 WristWatch::~WristWatch()
31 {
32     cout << "Destruct WristWatch" << endl;
33 }
34
35 int main()
36 {
37     TimeKeeper* pt = new WristWatch;
38     delete pt;      // 仅调用TimeKeeper::~TimeKeeper
39
40     return 0;
41 }

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

注意:

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

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

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

1 class Base
2 {
3 public:
4     virtual ~Base() = 0;    // pure virtual destructor
5 };
6 Base::~Base()               // definition
7 {
8
9 }

主要有两方面的好处:

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

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

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

总结:

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

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

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

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个规则只适用于polymorphic(带多态性质的)base class身上.这种base class的设计目的是为了用来“通过base class接口处理derived class对象”.假如我们在程序中设计factory(工厂)函数,让它返回base class指针,指向新生成的derived class对象,假设base class有个non-virtu

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

class TimeKeeper { public: TimeKeeper(); // ~TimeKeeper(); 错误,此作为一个基类,被继承了.其继承类被delete后,基类被销毁,但继承类可能没被销毁 virtual ~TimeKeeper();//必须声明为virtual类型才可以. protected: private: };   class AtomicClock: public TimeKeeper{}; //继承   TimeKeeper* ptk = getTimeKeepe

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

1. 如果一个类将要作为基类,那么它应该具有一个虚析构函数以防止delete经由基类指针指向的派生类对象时发生的"局部销毁"问题,避免造成内存泄露,数据结构败坏,在调试器上浪费时间等问题;任何带有虚函数的类几乎肯定需要一个虚析构函数. 2. 在不必需的情况下不应该将成员函数设为虚函数,否则,如果导致一个本来没有虚函数的类带有虚函数,那么它就会增加一个隐含的vptr(virtual table pointer)指针(指向虚函数表用于支持动态绑定),在这种情况下,类的"体积&qu

条款7:为多态基类声明virtual析构函数

1.假设有如下时间类: class TimeKeeper { public: TimeKeeper(); ~TimeKeeper(); }; class AtomicClock :public TimeKeeper {}; factory函数(用户只是想调用时间,而不想操心时间如何计算等细节):TimeKeeper *getTimeKeeper() //返回一个base class指针,并指向新生成的derived class TimeKeeper *a = getTimeKeeper();//

Effective C++ Item 07-为多态基类声明virtual析构函数

Item 07-为多态基类声明virtual析构函数 Declare destructors virtual in polymorphic base class why?  http://blog.csdn.net/wxqian25/article/details/7361069 Ex: 记录时间有多种做法,一个基类和一些派生类 class TimeKeeper{                        //    base class 基类 public: TimeKeeper(); ~

effective c++ 条款07:为多态基类声明virtual析构函数

记住:带多态性质的基类应该声明一个virtual析构函数.如果class带有任何virtual函数,它就应该拥有一个virtual析构函数.class的设计目的如果不是作为基类使用,或不是为了具备多态性,就不该声明virtual析构函数. class TimeKeeper { public: TimeKeeper(); ~TimeKeeper(); ... }; class AtomicClock: public TimeKeeper { ... }; class WaterClock: pub

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

注意:polymorphic base class 应该具有虚析构函数,如果class带有任何virtual函数,也应具有虚析构函数 class不具备polymorphic属性则不应该声明virtual 析构函数 1.老生常谈,如果一个类需要被使用为base calss 则为它声明 "virtual析构函数",确保删除一个"指向派生类对象的基类指针" 时内存完整删除 2.对于不需要使用为base class的类,反而不声明virtual 函数是最好的,如果你的类只具

Effective C++学习笔记 条款07:为多态基类声明virtual析构函数

一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的derived成分没有被销毁!(注:使用基类引用派生类的方式使用多态,由于引用只是对原对象的一个引用或者叫做别名,其并没有分配内存,对其引用对象内存的销毁,将由原对象自己负责,所以使用引用的时候,如果析构函数不为virtual,那么也不会发生derived成员没有销毁的情况) 例如: class b

effective c++ 条款07(为多态基类声明virtual析构函数)整理

一.虚函数表原理 陈皓的一篇blog讲的很透彻:http://blog.csdn.net/haoel/article/details/1948051/ 虚函数表可以分为:单一继承无虚函数覆盖.单一继承有虚函数覆盖.多重继承无虚函数覆盖和多重继承和有虚函数覆盖. 注意与虚拟继承区分开来 二.多态实现原理 多态则是通过继承.虚函数(virtual).指针来实现. class A { public: virtual void func() const { coust << "A::func