5、继承与派生4-派生类的构造和析构函数
派生類的構(gòu)造函數(shù)只負責對派生類新增的成員進行初始化,對所有從基類繼承下來成員,其初始化工作還是由基類的構(gòu)造函數(shù)完成。同樣,對派生類對象的掃尾、清理工作也需要加入新的析構(gòu)函數(shù)。
1、構(gòu)造函數(shù)
構(gòu)造派生類的對象時,就要對基類數(shù)據(jù)成員、新增數(shù)據(jù)成員和成員對象的數(shù)據(jù)成員進行初始化。派生類的構(gòu)造函數(shù)需要以合適的初值作為參數(shù),其中一些參數(shù)要用于對派生類新增的成員進行初始化,另一些參數(shù)要分別傳遞給基類的構(gòu)造函數(shù)和對象成員的構(gòu)造函數(shù)。用于初始化相應(yīng)的成員。
在構(gòu)造派生類的對象時,會首先隱含調(diào)用基類和內(nèi)嵌對象成員的構(gòu)造函數(shù),來初始化他們各自的數(shù)據(jù)成員,然后才執(zhí)行派生類構(gòu)造函數(shù)的函數(shù)體。
派生類構(gòu)造函數(shù)的一般語法形式為:
派生類名::派生類名(參數(shù)總表):基類名1(參數(shù)表1),...,基類名n(參數(shù)表n),
內(nèi)嵌對象名1(內(nèi)嵌對象參數(shù)表1),...,內(nèi)嵌對象名m(內(nèi)嵌對象參數(shù)表m)
{
派生類新增成員的初始化語句;
}
這里的派生類的構(gòu)造函數(shù)名與類名相同。在生成派生類對象時,系統(tǒng)首先會使用這里列出的參數(shù),調(diào)用基類和內(nèi)嵌對象成員的構(gòu)造函數(shù)。
下面來討論什么時候需要聲明派生類的構(gòu)造函數(shù)。如果基類聲明了帶有形參表的構(gòu)造函數(shù)時,派生類就應(yīng)當聲明構(gòu)造函數(shù),提供一個將參數(shù)傳遞給基類構(gòu)造函數(shù)的途徑,保證在基類進行初始化時能夠獲得必要的數(shù)據(jù)。
派生類構(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í)行。
eg:派生類構(gòu)造函數(shù)舉例(多繼承,含有內(nèi)嵌對象)
這是一個具有一般性特征的例子,有三個基類B1、B2和B3,其中B3只有一個默認的構(gòu)造函數(shù),其余兩個基類的成員只有一個帶有參數(shù)的構(gòu)造函數(shù)。類c由這三個基類經(jīng)過公有派生而來。派生類新增加了三個私有對象成員,分別是B1、B2和B3類的對象,如下
#include<iostream>
using namespace std;
class B1
{
public:
B1(int i){cout<<"constructing B1"<<i<<endl;}
};
class B2
{
public:
B2(int j){cout<<"constructing B2"<<j<<endl;}
};
class B3
{
public:
B3(){cout<<"constructing B3 *"<<endl;}
};
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){}
//注意基類名的個數(shù)與順序;成員對象名的個數(shù)與順序
private:
B1 memberB1;
B2 memberB2;
B3 memeberB3;
};
int main()
{
C obj(1,2,3,4);
}
因為基類及內(nèi)嵌對象成員都具有非默認形式的構(gòu)造函數(shù),所以派生類中需要聲明一個非默認形式(即帶參數(shù))的構(gòu)造函數(shù)。這個派生類構(gòu)造函數(shù)的主要功能就是初始化基類及內(nèi)嵌對象成員。需要注意的是:首先,這里并沒有列出全部基類和成員對象,由于B3類只有默認構(gòu)造函數(shù),不需要給它傳遞參數(shù),因此基類B3以及B3類成員對象memberB3就不必列出,但是系統(tǒng)還是會自動調(diào)用該類的默認構(gòu)造函數(shù)。其次,基類名和成員對象名的順序是隨意的。這個派生類的構(gòu)造函數(shù)的函數(shù)體為空,可見實際上只是起到了傳遞參數(shù)和調(diào)用基類及內(nèi)嵌對象的構(gòu)造函數(shù)的作用。
2、拷貝構(gòu)造函數(shù)
若建立派生類對象時調(diào)用默認拷貝構(gòu)造函數(shù),則編譯器將自動調(diào)用基類的拷貝構(gòu)造函數(shù)。
如果要為派生類編寫拷貝構(gòu)造函數(shù),則需要為基類相應(yīng)的拷貝構(gòu)造函數(shù)傳遞參數(shù)。如:C類是B類的派生類,C類的拷貝構(gòu)造函數(shù)形式如下:
C::C(C &c1):B(c1)
{...}
這里B的拷貝構(gòu)造函數(shù)的引用使用c1,這是由于類型兼容規(guī)則的原因,可以用派生類的引用去初始化基類的引用。
3、析構(gòu)函數(shù)
派生類的析構(gòu)函數(shù)的功能是在該類對象消亡之前進行一些必要的清理工作。它沒有類型也沒有參數(shù)。
派生類析構(gòu)函數(shù)的聲明方法與沒有繼承關(guān)系的類中析構(gòu)函數(shù)的聲明方法完全相同,只要在函數(shù)體中負責把派生類新增的非對象成員的清理工作做好就夠了,系統(tǒng)會自己調(diào)用基類及對象成員的析構(gòu)函數(shù)來對基類及對象成員進行清理。但他的執(zhí)行次序和構(gòu)造函數(shù)正好嚴格相反,首先對派生類新增普通成員進行清理,然后對派生類新增的對象成員進行清理;最后對所有從基類繼承來的成員進行清理。這些清理工作分別是執(zhí)行派生類析構(gòu)函數(shù)體,調(diào)用派生類對象成員所在類的析構(gòu)函數(shù)和調(diào)用基類析構(gòu)函數(shù)。
eg:派生類析構(gòu)函數(shù)舉例(多繼承、含有嵌入對象)
#include<iostream>
using namespace std;
class B1
{
public:
B1(int i){cout<<"constructing B1"<<i<<endl;}//B1的構(gòu)造函數(shù)
~B1(){cout<<"destructing B1"<<endl;}//B1的析構(gòu)函數(shù)
};
class B2
{
public:
B2(int j){cout<<"constructing B2"<<j<<endl;}//B2的構(gòu)造函數(shù)
~B2(){cout<<"destructing B2"<<endl;}//B2的析構(gòu)函數(shù)
};
class B3
{
public:
B3(){cout<<"constructing B3 *"<<endl;}//B3的構(gòu)造函數(shù)
~B3(){cout<<"destructing B3"<<endl;}//B3的析構(gòu)函數(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){}//派生類的構(gòu)造函數(shù)定義
private:
B1 memeberB1;
B2 memberB2;
B3 memberB3;
};
int main()
{
C obj(1,2,3,4);
}
結(jié)果如下
程序中,我們給三個基類分別加入了析構(gòu)函數(shù),派生類沒有做任何改動,仍然使用的是由系統(tǒng)提供的默認析構(gòu)函數(shù)。主函數(shù)也保持原樣。程序在執(zhí)行時,首先執(zhí)行派生類的構(gòu)造函數(shù),然后執(zhí)行派生類的析構(gòu)函數(shù)。派生類默認的析構(gòu)函數(shù)有分別調(diào)用了成員對象及基類的析構(gòu)函數(shù)。
?
轉(zhuǎn)載于:https://www.cnblogs.com/gary-guo/p/6233652.html
總結(jié)
以上是生活随笔為你收集整理的5、继承与派生4-派生类的构造和析构函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue.js几行实现的简单的todo l
- 下一篇: bind绑定参数