多態時最好將基類的解構函式設為virtual,這樣在析構時會先調用子類的解構函式,再調用基類的解構函式,否則如果delete的是基類的指標,則只調用基類的解構函式.樣本如下:
#include <iostream.h>
class Base
{
public:
Base() { mPtr = new int; }
virtual ~Base() { delete mPtr; cout<<"~Base::Base()"<<endl;}
private:
int* mPtr;
} ;
class Derived : public Base
{
public:
Derived() { mDerived = new long; }
~Derived() { delete mDerived; cout<<"~Derived::Derived()"<<endl;}
private:
long* mDerived;
} ;
void main()
{
Base* p = new Derived;
delete p;
}
結果:
先調用子類的解構函式:釋放mDerived,輸出"~Derived::Derived()";
再調用父類的解構函式:釋放mPtr,輸出"~Base::Base()"。
------------
#include <iostream.h>
class Base
{
public:
Base() { mPtr = new int; }
~Base() { delete mPtr; cout<<"~Base::Base()"<<endl;}
private:
int* mPtr;
} ;
class Derived : public Base
{
public:
Derived() { mDerived = new long; }
~Derived() { delete mDerived; cout<<"~Derived::Derived()"<<endl;}
private:
long* mDerived;
} ;
void main()
{
Base* p = new Derived;
delete p;
}
結果:只調用了父類的解構函式:釋放mPtr,輸出"~Base::Base()"。
以上代碼會產生記憶體泄露,因為new出來的是Derived類資源,採用一個基類的指標來接收,析構的時候,編譯器因為只是知道這個指標是基類的,所以只將基類部分的記憶體析構了,而不會析構子類的,就造成了記憶體泄露,如果將基類的解構函式改成虛函數,就可以避免這種情況,因為虛函數是後綁定,其實就是在虛函數列表中,解構函式將基類的解構函式用實際對象的一組解構函式替換掉了,也就是先執行子類的虛函數再執行父類的虛函數,這樣子類的記憶體析構了,父類的記憶體也釋放了,就不會產生記憶體泄露。
上面代碼中,如~Base()不是virtual,而~Derived()為virtual,則
Base* p = new Derived; delete p;
仍然只調用~Base::Base(),因為delete p中的p是Base*類型,而Base的解構函式~Base()不是virtual。
另:delete子類指標時,會調用子類的解構函式,然後自動調用其父類的解構函式(不管~Derived::Derived()是否為virtual,~Derived::Derived()內部總會自動調用~Base::Base()),如:
Derived * pd = new Derived;
delete pd;//調用 ~Derived::Derived(),並自動析構父類(調用~Base::Base())
註:
1.解構函式其實是一個函數,不論子類還是父類,雖然可能看起來名字不一樣。而且解構函式執行過程都是執行子類再到父類。
2.多態的時候一定要將解構函式寫成虛函數,防止記憶體泄露,各個子類維護自己內部資料釋放。
virtual 是實現多態的基礎
它使得具體的函數跳轉從編譯時間延遲到運行時然而建構函式的調用是編譯器期間就決定的,因此它不能為虛.