注意:本文中代碼均使用 Qt 開發(fā)編譯環(huán)境
派生類的目的是為了發(fā)展确封,派生類繼承了基類的成員,實現(xiàn)了原有代碼的重用,這只是一部分廊宪,而代碼的擴充才是最主要的,只有通過添加新的成員眉踱,加入新的功能挤忙,類的派生才有實際意義。
派生類的構(gòu)造函數(shù)只負責對新增的成員進行初始化谈喳,對所有從基類繼承來的成員级历,其初始化工作還是由基類的構(gòu)造函數(shù)完成初狰。同樣,對派生類對象的掃尾、清理工作慕趴,也需要加入新的的析構(gòu)函數(shù)。
基類的構(gòu)造函數(shù)并沒有繼承下來薪缆,要完成這些工作漾唉,就必須給派生類添加新的構(gòu)造函數(shù)。派生類的構(gòu)造函數(shù)需要以合適的初值作為參數(shù)膛壹,其中一些參數(shù)要用于對派生類新增成員進行初始化驾中,另一些參數(shù)要分別傳遞給基類的構(gòu)造函數(shù)和對象成員的構(gòu)造函數(shù),用于初始化相應的成員模聋。
什么時候需要聲明派生類的構(gòu)造函數(shù)肩民?###
如果基類聲明了帶有形參表的構(gòu)造函數(shù)時,派生類就應當聲明構(gòu)造函數(shù)链方,提供一個將參數(shù)傳遞給基類構(gòu)造函數(shù)的途徑持痰,保證在基類進行初始化時能夠獲得必要的數(shù)據(jù)。當然祟蚀,如果基類沒有聲明構(gòu)造函數(shù)工窍,派生類也可以不聲明構(gòu)造函數(shù)割卖,全部采用默認構(gòu)造函數(shù),這時新增成員的初始化工作可以用其他公有函數(shù)來完成患雏。
派生類構(gòu)造函數(shù)執(zhí)行的一般次序如下:
(1) 調(diào)用基類構(gòu)造函數(shù)鹏溯,調(diào)用順序按照它們被繼承時的順序(從左至右)
(2) 調(diào)用內(nèi)嵌成員對象的構(gòu)造函數(shù),調(diào)用順序按照它們在類中聲明的順序
(3) 派生類構(gòu)造函數(shù)體中的內(nèi)容
其中纵苛,如果派生類中新增成員中有內(nèi)嵌的對象剿涮,第二步調(diào)用才會執(zhí)行,否則攻人,就直接跳轉(zhuǎn)到第三步取试。
示例:
#include <QCoreApplication>
#include <QDebug>
class B1
{
public:
B1(int i){qDebug()<<"Constructing B1 "<<i;} //基類B1,構(gòu)造函數(shù)有參數(shù)
};
class B2
{
public:
B2(int j){qDebug()<<"Constructing B2 "<<j;} //基類B2怀吻,構(gòu)造函數(shù)有參數(shù)
};
class B3
{
public:
B3(){qDebug()<<"Constructing B3 *";} //基類B3瞬浓,構(gòu)造函數(shù)無參數(shù)
};
class C : public B2,public B1,public B3 //派生類C,注意此處的繼承順序蓬坡!
{
public:
C(int a,int b, int c,int d):B1(a),memberB2(d),memberB1(c),B2(b){}
private:
B1 memberB1;
B2 memberB2;
B3 memberB3;
};
int main()
{
C obj(1,2,3,4);
return 0;
}
注意:
首先猿棉,這里并沒有列出全部的基類和成員對象,由于B3類只有默認構(gòu)造函數(shù)屑咳,不需要給它傳遞參數(shù)萨赁,因此,基類B3以及B3類成員對象memberB3就不必列出兆龙。
其次杖爽,基類名和成員對象名的順序是隨意的。這個派生類構(gòu)造函數(shù)的函數(shù)體為空紫皇,可見實際上只是起到了傳遞參數(shù)和調(diào)用基類及內(nèi)嵌對象構(gòu)造函數(shù)的作用慰安。
輸出:
基類構(gòu)造函數(shù)的調(diào)用順序是按照派生類定義時的順序,因此應該是先B2聪铺,再B1化焕,再B3,而內(nèi)嵌對象的構(gòu)造函數(shù)調(diào)用順序應該是按照成員在類中聲明的順序铃剔,應該是先B1撒桨,再B2,再B3键兜,程序運行的結(jié)果也完全印證這種分析凤类。
拷貝構(gòu)造函數(shù)###
如果要為派生類編寫拷貝構(gòu)造函數(shù),則需要為基類相應的拷貝構(gòu)造函數(shù)傳遞參數(shù)蝶押。例如假設C類是B類的派生類踱蠢,C類的拷貝構(gòu)造函數(shù)形式如下:
C::C(C &c1):B(c1){…}
B類的拷貝構(gòu)造函數(shù)參數(shù)類型應該是B類對象的引用火欧,為什么要用C類對象的引用c1作為參數(shù)呢棋电?
這是因為類型兼容規(guī)則在這里起到了作用:可以用派生類的引用去初始化基類的引用茎截。因此當函數(shù)的形參是基類的引用時,實參可以是派生類的引用赶盔。
析構(gòu)函數(shù)###
從下面的實例輸出結(jié)果可以簡單的看出派生類析構(gòu)函數(shù)執(zhí)行次序和構(gòu)造函數(shù)正好嚴格相反企锌。
在上面的示例基礎上稍加調(diào)整:
#include <QCoreApplication>
#include <QDebug>
class B1
{
public:
B1(int i){qDebug()<<"Constructing B1 "<<i;} //基類B1,構(gòu)造函數(shù)有參數(shù)
~B1(){qDebug()<<"Destructing B1";}
};
class B2
{
public:
B2(int j){qDebug()<<"Constructing B2 "<<j;} //基類B2于未,構(gòu)造函數(shù)有參數(shù)
~B2(){qDebug()<<"Destructing B2";}
};
class B3
{
public:
B3(){qDebug()<<"Constructing B3 *";} //基類B3撕攒,構(gòu)造函數(shù)無參數(shù)
~B3(){qDebug()<<"Destructing B3";}
};
class C : public B2,public B1,public B3 //派生類C,注意此處的繼承順序烘浦!
{
public:
C(int a,int b, int c,int d):B1(a),memberB2(d),memberB1(c),B2(b){}
private:
B1 memberB1;
B2 memberB2;
B3 memberB3;
};
int main()
{
C obj(1,2,3,4);
return 0;
}
輸出結(jié)果: