派生類的構造函數和析構函數
基類的構造函數和析構函數不能被繼承。
在派生類中,如果派生類新增的成員進行初始化,就必須加入新的構造函數。與此同時,對所有從基類繼承下來的成員的初始化工作還是由基類的構造函數完成,必須在派生類中對基類的構造函數所需要的參數進行設置。同樣,對派生類對象的掃尾,清理工作也需要加入析構函數。
首先看下面例子:
class A //默認構造函數為空
{
public:int x;
};
class B:public A //默認構造函數為空
{
public:int y;
};
當創建B類對象b1后,對象b1可以訪問下x,y這兩個成員。那么是否可以認為b1實際上是下面C類的對象呢?
class C
{
public:int x,y;
};
若利用C類創建對象c1,從成員訪問權限上看,對象b1和c1沒有差別。但是b1的x和c1的x不同,它繼承于基類。由于派生類不能繼承父類的構造函數和析構函數,因此對象b1的x占據的內存區域只能通過基類的構造函數初始化。同樣,銷毀對象時,b1的x占據的內存也只能由基類的析構函數進行清理。而對象c1的x是由C類構造函數初始化,由C類析構函數進行清理工作的。因此b1和c1僅僅是表面相似而已。由于派生類構造過程涉及基類構造函數的調用,因此其構造函數比較復雜。
1、構造函數
派生類構造函數的一般形式為
派生類::派生類(參數總表)::基類1(參數表1),……,基類n(參數表n),內嵌對象1(對象參數表1),……,內嵌對象m(對象參數表m){
派生類新增加成員的初始化;
}
這個聲明形式很復雜,應該注意以下幾點:
①對于基類繼承的數據成員,應采用基類構造函數初始化,并且應放在派生類構造函數的初始化列表中,不應放到構造函數體中初始化。
②參數總表包括全部基類和全部內嵌對象的所有參數,同時也包含派生類新增數據成員的初始化參數。最后一個冒號后面的基類和內嵌對象的參數全部取自前面的參數總部。
③當派生類使用基類無參數的默認構造函數初始化繼承的數據成員時,初始化列表中就不存在“基類(參數表)”的初始化部分。
④當派生類中無內嵌對象或者內嵌對象使用無參數的默認構造函數時,初始化列表中就不存在“內嵌對象(參數表)”的初始化列表部分。
⑤當基類有待參數的構造函數時,派生類應當定義構造函數,提供一個將參數傳遞給基類的構造函數的途徑
?
派生類構造函數的執行次序為:執行基類構造函數——執行內嵌對象的構造函數——執行派生類構造函數體的內容
派生類析構函數的執行次序為:執行派生類析構函數——執行內嵌對象的析構函數——執行基類析構函數
?
派生類構造函數和析構函數的執行
代碼分析:
從輸出結果可以清楚地看出,構造函數執行順序為先祖先(Person 張三),后客人(Person 王五),最后自己(Employee),這里Wang是Person類只的一個對象,被派生類Emoloyee所有。
同時,從上面的輸出結果中可以看出,析構函數的執行次序恰好與構造函數相反,先執行自身(Employee)的析構函數,而后是客人(Person 王五),最后祖先(Person 張三)
?
?