C++中的为什么需要虚析构函数

让我们先看一个简答的例子:

#include 
using namespace std;

class Fish
{
public:
   Fish()
   {
      cout << "Constructed Fish" << endl;
   }
   ~Fish()
   {
      cout << "Destroyed Fish" << endl;
   }
};

class Tuna:public Fish
{
public:
   Tuna()
   {
      cout << "Constructed Tuna" << endl;
   }
   ~Tuna()
   {
      cout << "Destroyed Tuna" << endl;
   }
};

void DeleteFishMemory(Fish* pFish)
{
   delete pFish;
}

int main() 
{
    cout << "Allocating a Tuna on the free store:" << endl;
   Tuna* pTuna = new Tuna;
   cout << "Deleting the Tuna: " << endl;
   DeleteFishMemory(pTuna);

   cout << "Instantiating a Tuna on the stack:" << endl;
   Tuna myDinner;
   cout << "Automatic destruction as it goes out of scope: " << endl;

   return 0;
}

读者可以直接复制代码试试看,运行结果如下:
C++中的为什么需要虚析构函数_第1张图片

主函数中,我们使用new在自由存储区创建了一个实例,然后马上使用辅助函数DeleteFishMemory释放分配的内存,处于比较目的,我们在后面创建了一个Tuna实例–局部变量myDinner,main()结束时,他将不再作用域内,输出的是Fish和Tuna的构造函数和析构函数中的cout语句,注意到使用关键字new,在自由存储区构造了Tuna和Fish,但是delete没有调用Tuna的析构函数么只是调用了Fish的析构函数,这与myDinner的构造与析构形成了鲜明的对比。

以上结果表明,对于使用new在自由存储区中实例化派生类对象,如果将其赋给基类指针,并通过该指针调用delete,将不会调用派生类的析构函数,这可能导致资源未释放,内存泄漏等问题。

解决办法很简单,如标题所言,将析构函数声明为虚函数即可:

`
virtual ~Fish()
{
cout << "Destroyed Fish" << endl;
}
我们在看看运行结果:
C++中的为什么需要虚析构函数_第2张图片
`
可以看到多了一行:Destroyed Tuna。(注意构造和析构的调用顺序不一样)。
虽然上面不是一个大问题(编译能通过),但是编写高质量的c++程序还是需要注意的。

参考书籍 Sams Teach Yourself C++ in One Hour a Day(* chapter 11*

你可能感兴趣的:(c++进阶)