当父类是一个抽象类,即它具备至少一个virtual函数的时候,如果没有virtual的析构函数,gcc在打开-Wall的时候,会给出警告:

abstract.cc:5: 警告:‘class Base’ 有虚函数却没有虚析构函数
abstract.cc:10: 警告:‘class Child’ 有虚函数却没有虚析构函数
为了规避这个警告,可以给父类增加一个virtual的析构函数。那么这个析构函数到底有什么用处呢?
下面的代码的运行结果为:
child call
child call
Child destroy
Base destroy
Child destroy
Base destroy
可以看到,子类析构的时候,编译器会自动调用父类的析构函数。

 C++ |  copy code |? 
01
02
  #include <iostream>
03
 
04
  using namespace std;
05
 
06
  class Base {
07
      public:
08
          virtual void call() = 0;
09
          virtual ~Base(){
10
              cout << "Base destroy" << endl;
11
          }
12
  };
13
 
14
  class Child : public Base{
15
      public:
16
          void call(){
17
              cout << "child call" << endl;
18
          }
19
          ~Child(){
20
              cout << "Child destroy" << endl;
21
          }
22
  };
23
 
24
  int main()
25
  {
26
      Child c;
27
      c.call();
28
 
29
      Base* b = new Child();
30
      b->call();
31
      delete b;
32
 
33
      return 0;
34
  }
35

但是,如果把Base析构函数的virtual去掉,gcc仍然会给出警告,运行结果:

child call

child call

Base destroy

Child destroy

Base destroy

这代表着,当显示操作子类Child的时候,会先调用Child的析构函数,然后编译器自动调用父类Base的析构函数。但是,当使用父类的指针操作Child的时候,就仅调用了父类Base的析构函数!

所以,《C++大学教程》里有这样的两段话:

1、如果您打算让别人从您的类中派生子类,并希望能够通过父类指针多态的删除它们,就把父类的析构函数定义为虚函数。

2、如果您想创建一个父类,可以被派生,但是不要多态的删除它们,那么就把父类的析构函数定义为protected的非虚函数。这样,子类仍然可以隐式调用父类的析构函数,但是其他函数,由于无法访问父类的非public函数,就无法直接调用父类的析构函数了。

Leave a Reply