多態性是在父類或各子類中執行最合適成員函數。一般來說,只會選擇父類或子類中的某一個成員函數來執行。這可給析構函數帶來了麻煩!如果有的資源是父類的構造函數申請的,有的資源是子類的構造函數申請的,而虛函數只允許程序執行父類或子類中的某一個析構函數,豈不是註定有一部分資源將無法被釋放?爲了解決這個問題,虛析構函數變得與衆不同。
下面我們就來給析構函數的前面加上保留字virtual,看看運行的結果會怎麼樣:(程序17.8)
//animal.h
#include <iostream>
using namespace std;
class Animal
{
public:
Animal(int w=0,int a=0);
virtual ~Animal();//虛析構函數
protected:
int weight,age;
};
Animal::Animal(int w,int a)
{
cout <<"Animal consturctor is running..." <<endl;
weight=w;
age=a;
}
Animal::~Animal()
{
cout <<"Animal destructor is running..." <<endl;
}
//cat.h
#include "animal.h"
class Cat:public Animal
{
public:
Cat(int w=0,int a=0);
~Cat();
};
Cat::Cat(int w,int a):Animal(w,a)
{
cout <<"Cat constructor is running..." <<endl;
}
Cat::~Cat()
{
cout <<"Cat destructor is running..." <<endl;
}
//main.cpp
#include "cat.h"
int main()
{
Animal *pa=new Cat(2,1);
Cat *pc=new Cat(2,4);
cout <<"Delete pa:" <<endl;
delete pa;
cout <<"Delete pc:" <<endl;
delete pc;
return 0;
}
運行結果:
Animal consturctor is running...
Cat constructor is running...
Animal consturctor is running...
Cat constructor is running...
Delete pa:
Cat destructor is running...
Animal destructor is running...
Delete pc:
Cat destructor is running...
Animal destructor is running...
我們驚訝地發現,虛析構函數不再是運行父類或子類的某一個析構函數,而是先運行合適的子類析構函數,再運行父類析構函數。即兩個類的析構函數都被執行了,如果兩塊資源分別是由父類構造函數和子類構造函數申請的,那麼使用了虛析構函數之後,兩塊資源都能被及時釋放。
我們修改程序17.8,將Animal類析構函數前的virtual去掉,會發現運行結果中刪除pa指向的Cat對象時,不執行Cat類的析構函數。如果這時Cat類的構造函數裏申請了內存資源,就會造成內存泄漏了。
所以說,虛函數與虛析構函數的作用是不同的。虛函數是爲了實現多態,而虛析構函數是爲了同時運行父類和子類的析構函數,使資源得以釋放。