1、派生類的構造函數、析構函數默認會調用基類的構造函數、析構函數。
順序:基類構造、派生類構造;派生類析構,基類析構。
舉例:
/******************************************************************************************************
* File:Constructor&DestructorTest
* Introduction:測試構造函數、析構函數、虛構造函數與純虛構造函數的一些特性。
* Author:CoderCong
* Date:20141013
* LastModifiedDate:20160113
*******************************************************************************************************/
#include "stdafx.h"
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base:Constructing" << endl;
}
~Base()
{
cout << "Base: Destructing!" << endl;
}
};
class Derived:public Base
{
public:
Derived()
{
cout << "Derived:Constructing" << endl;
}
~Derived()
{
cout << "Derived: Destructing!" << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Derived *pDerived=new Derived;
delete pDerived;
return 0;
}
運行結果:
Base:Constructing
Derived:Constructing
Derived: Destructing!
Base: Destructing!
2、如果你的類用作派生類的基類,最好定義其析構函數爲虛函數。
好處:定義其析構函數爲虛函數,可以利用動態綁定,把一個子類對象綁定到一個基類指針上時,可以自動調用基類的析構函數。從而默認地調用基類的析構函數。
舉例:
同樣是上邊的函數,我們把_tmain函數改爲這樣:
Base *pBase = new Derived;
delete pBase;
同志們注意運行結果:
Base:ConstructingDerived:Constructing
Base: Destructing!
天哪!居然沒有調用派生類的析構函數!
注意,你delete的指針是Base類的指針。而Base的析構函數不是虛函數。當然不用調用派生類的析構函數!
天真的你也許會說,這也沒什麼大不了的吧?
沒什麼大不了的?再也沒有比這更大的事情了。這可能會造成一個嚴峻的問題:內存泄露!我們真正想刪除的是一個派生類對象,而實際上只是刪除了派生類對象中基類的那一部分。如果派生部分有一些需要釋放的資源,如網絡、內存等,那麼這些資源將無法得到釋放。
作爲一個嚴謹的C++程序員,我們當然不允許這樣的事情發生。我們把Base類的析構函數改爲虛函數試試看:
virtual ~Base()
{
cout << "Base: Destructing!" << endl;
}
運行結果:Base:Constructing
Derived:Constructing
Derived: Destructing!
Base: Destructing!
我們驚喜得發現,一切都正常了。
再來理一遍:
我們new一個Derived類對象,調用了Derived類的構造函數,而此構造函數又默認地調用了基類Base的析構函數;
然後,我們把這個Derived對象綁定到Base類指針pBase,這時候,這個pBase的靜態類型是Base*,動態類型卻是Derived*。我們刪除pBase,系統跟據動態綁定,最終調用的是~Derived,而不是~Base。調用~Derived之後,系統又默認地調用了基類析構函數~Base。
就是這樣。
3、爲什麼構造函數不能是虛函數?
virtual ~Base() =0;
Base::~Base(){}
程序正常運行了。說明我們的猜測是正確的。