構造函數
1.基類構造函數。如果有多個基類,則構造函數的調用順序是某類在類派生表中出現的順序,而不是它們在成員初始化表中的順序。
2.成員類對象構造函數。如果有多個成員類對象則構造函數的調用順序是對象在類中被聲明的順序,而不是它們出現在成員初始化表中的順序。
3.派生類構造函數。
析構函數
析構函數的調用順序與構造函數的調用順序正好相反,將上面3個點反過來用就可以了,首先調用派生類的析構函數;其次再調用成員類對象的析構函數;最后調用基類的析構函數。
析構函數在下邊3種情況時被調用:
1.對象生命周期結束,被銷毀時(一般類成員的指針變量與引用都i不自動調用析構函數);
2.delete指向對象的指針時,或delete指向對象的基類類型指針,而其基類虛構函數是虛函數時;
3.對象i是對象o的成員,o的析構函數被調用時,對象i的析構函數也被調用。
virtual析構函數
下面來說一說為多態基類聲明virtual析構函數:
在C++中,構造函數不能聲時為虛函數,這是因為編譯器在構造對象時,必須知道確切類型,才能正確的生成對象,因此,不允許使用動態束定;其次,在構造函數執行之前,對象並不存在,無法使用指向此此對象的指針來調用構造函數,然而,析構函數是可以聲明為虛函數;C++明白指出,當derived class對象經由一個base class指針被刪除,而該base class帶着一個non-virtual析構函數,其結果未有定義---實際執行時通常發生的是對象的derived成分沒被銷毀掉。
class Derive:public Base
{
public:
Derive(){ std::cout<<"Derive::Derive()"<<std::endl; }
~Derive(){ std::cout<<"Derive::~Derive()"<<std::endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
Base* pBase = new Derive();
delete pBase;
return 0;
}
輸出結果是:
Base::Base()
Derive::Derive()
Derive::~Derive()
Base::~Base()
由結果可以看出,在父類的虛析構函數有自己的實現時,當調用完子類對象的析構函數結束后,還會調用父類的析構函數。而一般的虛函數都是子類覆蓋了父類的,調用完子類方法后不會再調用父類的方法。況且虛析構函數也不能想一般的虛函數一樣寫成純虛函數的形式。這一切還是由於析構函數的特殊性決定的。
構造和析構函數都有着特別的意義,這是與其它函數不同的,並且在一個類層次中析構函數都會被調用,並且調用順序是有規定的(文章開頭已講),這些是編譯器決定的。因此我們必須給出虛析構函數的函數體以供調用。既然調用順序已定,父類對象的析構函數總是會被調用,所以就沒有被子類覆蓋之說了。
