虚析构函数使用

说到虚析构函数,我们先来看看析构函数的作用:在删除指向动态分配对象的指针时,需要运行析构函数在释放对象的内存之前清除对象。

在处理继承层次的对象时,指针的静态类型可能与被删除对象的动态类型不符,可能会删除实际指向派生类对象的基类类型指针。

怎么理解这句话呢,在有继承的时候,如果我们删除一个指向子类的基类类型的指针F,也就是说指针F的类型是基类,但这个指针指向子类。这个时候如果要删除这个指针,调用的应该是基类的析构函数。如下代码:

 1 //base.h
 2 
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 class A{
 8 public:
 9     A() {
10         cout << "A" << endl;
11     }
12     ~A() {
13         cout << "~A" << endl;
14     }
15 };
16 
17 class B: public A{
18 public:
19     B() {
20         cout << "B" << endl;
21     }
22     ~B() {
23         cout << "~B" << endl;
24     }
25 };
 1 //main.cpp
 2 
 3 #include"base.h" 
 4 #include<iostream>
 5 
 6 using namespace std;
 7 
 8 int main(int argc,char*argv[])
 9 { 
10     A* te = new B;
11     delete te;
12     return 0;
13 } 

运行结果是:

A
B
~A
请按任意键继续. . .

但是实际上对象是B类型的,也就是说应该调用B的析构函数才对。

我们来考虑一种情况,当类B中有一个新的函数,改函数开出了一个内存空间,如new 出了一个对象。那么在删除指针F的时候,我们调用的是基类的析构函数,但基类的析构函数没有释放类B中的那个函数开出的空间,就会造成内存泄漏。为了解决这个问题,我们必须另基类的析构函数为虚函数。

如果基类的析构函数为虚函数,那么通过指针调用时,运行哪个析构函数将因指针所指的对象类型的不同而不同。

如下:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class A{
 6 public:
 7     A() {
 8         cout << "A" << endl;
 9     }
10     virtual ~A() {
11         cout << "~A" << endl;
12     }
13 };
14 
15 class B: public A{
16 public:
17     B() {
18         cout << "B" << endl;
19     }
20     ~B() {
21         cout << "~B" << endl;
22     }
23 };

运行结果:

A
B
~B
~A
请按任意键继续. . .

像其他虚函数一样,析构函数的虚函数性质都将继承。因此,如果层次中根类的析构函数为虚函数,那么派生类的析构函数也将是虚函数,无论派生类显式定义析构函数还是使用合成析构函数,派生类的析构函数都是虚函数。

因此,为了程序的正常运行,就算析构函数没有工作要做,继承层次的根类也应该定义一个虚析构函数。

原文地址:https://www.cnblogs.com/xiezhw3/p/3545220.html