条款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析构函数。

 

你可能感兴趣的:(virtual)