類的繼承與派生

類的繼承與派生

類的繼承就是新類由已經(jīng)存在的類獲得已有特性,類的派生是由已經(jīng)存在的類產(chǎn)生新類的過程。已有類叫做基類,產(chǎn)生的新類叫做派生類。

派生類的聲明?
class Clild: public Parent1,pravite Parent2
{
public:
Child();
~Child();
}

一個派生類可以有多個基類,叫做多繼承;否則為單繼承。直接派生出某個類的基類叫做這個類的直接基類,基類的基類或更高層的基類叫做派生類的間接基類。
? 派生類從基類繼承的過程可以分為三個步驟:吸收基類成員,修改基類成員和添加新成員。
? 繼承方式限定了派生類訪問從基類繼承來的成員的方式,指出了派生類成員或類外的對象對基類繼承來的成員的訪問權限。?繼承方式有:公有繼承、保護繼承和私有繼承。其中公有繼承最常用。
○ 共有繼承時,派生類對基類中的公有成員和保護成員的訪問屬性都不變,而對基類的私有成員則不能訪問。(類的對象也屬于類外的,不能訪問保護成員)
○ 保護繼承時,基類的公有成員和保護成員被派生類繼承后變成派生類的保護成員,而基類的私有成員在派生類紅不能訪問。
○ 私有繼承時,基類的公有成員和保護成員被派生類繼承后變成派生類的私有成員,而基類的私有成員在派生類中不能訪問。

    #include <iostream>
    using namespace std;
    class Base            // 基類Base的聲明
     {
     public:               // 公有成員函數(shù)
             void SetTwo(int a, int b)  { x=a; y=b; }
             int GetX()   { return x; }
             int GetY()   { return y; }
    private:              // 私有數(shù)據(jù)成員
             int x;
             int y;
    };
    class Child : private Base    // 派生類的聲明,繼承方式為私有繼承
    {
    public:                      // 新增公有成員函數(shù)
            void SetThree(int a, int b, int c)  { SetTwo(a, b); z=c; }
            int GetX()   { return Base::GetX(); }
            int GetY()   { return Base::GetY(); }
            int GetZ()   { return z; }
    private:                     // 新增私有數(shù)據(jù)成員
            int z;
    };
    int main()
    {
           Child child;           // 聲明Child類的對象
           child.SetThree(1, 2, 3); // 設置派生類的數(shù)據(jù)
           cout << "The data of child:"<<endl;
           cout << child.GetX() << "," << child.GetY() << "," << child.GetZ() << endl; 
           return 0;                                                         
    }

派生類的構造函數(shù)

基類的構造函數(shù)和析構函數(shù)派生類是不能繼承的,如果派生類需要對新成員初始化或者進行特定的清理工作,就需要就需要自己定義構造函數(shù)和析構函數(shù)了。從基類繼承的成員的初始化仍可通過基類的構造函數(shù)來完成。

派生類的數(shù)據(jù)成員包括從基類繼承來的數(shù)據(jù)成員和派生類新增的數(shù)據(jù)成員,還可能包括其他類的對象作為其數(shù)據(jù)成員,包括其他類的對象時實際上還間接包括了這些對象的數(shù)據(jù)成員。那么我們對派生類初始化時就需要對基類的數(shù)據(jù)成員、派生類新增數(shù)據(jù)成員和內(nèi)嵌的其他類對象的數(shù)據(jù)成員進行初始化。由于不能繼承基類的構造函數(shù),派生類就必須增加自己的構造函數(shù)。派生類的構造函數(shù)需要做的工作有,使用傳遞給派生類的參數(shù),調(diào)用基類的構造函數(shù)和內(nèi)嵌對象成員的構造函數(shù)來初始化它們的數(shù)據(jù)成員,再添加新語句初始化派生類新成員。派生類構造函數(shù)的語法形式為:

       派生類名::派生類名(參數(shù)表):基類名1(參數(shù)表1),...基類名m(參數(shù)名m),
                內(nèi)嵌對象名(內(nèi)嵌對象參數(shù)表1),...,內(nèi)嵌對象名n(內(nèi)嵌對象參數(shù)表n)
       {
                初始化派生類新成員的語句;
       }

基類的構造函數(shù)若有參數(shù),則派生類必須定義構造函數(shù),將傳入的參數(shù)再傳遞給基類的構造函數(shù),對基類進行初始化。若基類沒有定義構造函數(shù),則派生類也可以不定義構造函數(shù),都使用默認構造函數(shù),對于派生類的新增數(shù)據(jù)成員可以通過其他的公有函數(shù)成員來初始化。而如果基類同時定義了默認構造函數(shù)和帶參數(shù)的構造函數(shù),那么在派生類的構造函數(shù)中可以給出基類名及其參數(shù)表,也可以不顯式給出。

構造派生類的對象調(diào)用構造函數(shù)時的處理順序是:1.首先調(diào)用基類的構造函數(shù),若有多個基類,調(diào)用順序按照它們在派生類聲明時從左到右出現(xiàn)的順序;2.如果有內(nèi)嵌對象成員,則調(diào)用內(nèi)嵌對象成員的構造函數(shù),若為多個內(nèi)嵌對象,則按照它們在派生類中聲明的順序調(diào)用,如果無內(nèi)嵌對象則跳過這一步;3.調(diào)用派生類構造函數(shù)中的語句。

這里需要說明的是,基類和內(nèi)嵌對象成員的構造函數(shù)的調(diào)用順序和它們在派生類構造函數(shù)中出現(xiàn)的順序無關。
#include <iostream>
using namespace std;
class Base1 // 基類Base1,只有默認構造函數(shù)
{
public:
Base1() { cout<<"Base1 construct"<<endl; }
};
class Base2 // 基類Base2,只有帶參數(shù)的構造函數(shù)
{
public:
Base2(int x) { cout<<"Base2 construct "<<x<<endl; }
};
class Base3 // 基類Base3,只有帶參數(shù)的構造函數(shù)
{
public:
Base3(int y) { cout<<"Base3 construct "<<y<<endl; }
};
class Child : public Base2, public Base1, public Base3 // 派生類Child
{
public:
Child(int i,int j,int k,int m):Base2(i),b3(j),b2(k),Base3(m) { }
private: // 派生類的內(nèi)嵌對象成員
Base1 b1;
Base2 b2;
Base3 b3;
};
int main()
{
Child child(3,4,5,6);
return 0;
}
程序運行結果為:

       Base2 construct 3
       Base1 construct
       Base3 construct 6
       Base1 construct
       Base2 construct 5
       Base3 construct 4

派生類的析構函數(shù)

派生類的析構函數(shù)一般只需要在其函數(shù)體中清理新增成員就可以了,對于繼承的基類成員和派生類內(nèi)嵌對象成員的清理,則一般由系統(tǒng)自動調(diào)用基類和對象成員的析構函數(shù)來完成。這個執(zhí)行過程的順序正好和派生類構造函數(shù)相反:1.執(zhí)行析構函數(shù)語句清理派生類的新增成員;2.調(diào)用內(nèi)嵌對象成員所屬類的析構函數(shù)清理派生類內(nèi)嵌對象成員,各個對象成員的清理順序與其在構造函數(shù)中的構造順序相反;3.調(diào)用基類的析構函數(shù)清理繼承的基類成員,如果是多繼承則各個基類的清理順序也與其在構造函數(shù)中的構造順序相反??偲饋硪痪湓?,析構函數(shù)執(zhí)行時所有成員或?qū)ο蟮那謇眄樞蚺c構造函數(shù)的構造順序剛好完全相反。

作用域分辨符

我們可以通過基類名和作用域分辨符來訪問基類中的同名成員。作用域分辨符就是“::”,在派生類內(nèi)部訪問基類同名成員的語法形式是:

       基類名::數(shù)據(jù)成員名;           // 數(shù)據(jù)成員
       基類名::函數(shù)成員名(參數(shù)表);   // 函數(shù)成員

如果是在派生類外通過派生類對象訪問的話,前面還要加上“派生類對象名.”:

       派生類對象名.基類名::數(shù)據(jù)成員名;                  // 數(shù)據(jù)成員
       派生類對象名.基類名::函數(shù)成員名(參數(shù)表);   // 函數(shù)成員

這里的基類名就限定了后面的成員屬于哪個類。

賦值兼容規(guī)則

賦值兼容規(guī)則就是指在基類對象可以使用的地方都可以用公有派生類對象來代替。
那么根據(jù)賦值兼容規(guī)則,可以使用類Base對象的地方都可以使用類Child的對象來代替。這里的代替有三種:
a. 派生類的對象可以賦值給基類的對象。也就是將派生類對象從基類繼承的成員的值分別賦值給基類對象相應的成員。例如:? base = child;
b. 派生類對象的地址可以賦值給基類類型的指針。例如:? pBase = &child;
c. 派生類對象可以用來初始化基類的引用。例如:? Base &b = child;
公有派生類對象可以代替基類對象使用,但是我們只能使用它從基類繼承的成員,而無法使用它的新添成員。
#include <iostream>
using namespace std;
class Base // 基類Base的聲明
{
public:
void show() { cout << "Base::show()" << endl; } // 公有成員函數(shù)show
};
class Child0 : public Base // 類Base的公有派生類Child0的聲明
{
public:
void show() { cout << "Child0::show()" << endl; } // 公有成員函數(shù)show
};
class Child1 : public Child0 // 類Child0的公有派生類Child1的聲明
{
public:
void show() { cout << "Child1::show()" << endl; } // 公有成員函數(shù)show
};
void CallShow(Base *pBase) // 一般函數(shù),參數(shù)為基類指針
{
pBase->show();
}
int main()
{
Base base; // 聲明Base類的對象
Base *pBase; // 聲明Base類的指針
Child0 ch0; // 聲明Child0類的對象
Child1 ch1; // 聲明Child1類的對象
pBase = &base; // 將Base類對象base的地址賦值給Base類指針pBase
CallShow(pBase);
pBase = &ch0; // 將Child0類對象ch0的地址賦值給Base類指針pBase
CallShow(pBase);
pBase = &ch1; // 將Child1類對象ch1的地址賦值給Base類指針pBase
CallShow(pBase);
return 0;
}

虛函數(shù)

虛函數(shù)是非靜態(tài)的成員函數(shù),一定不能是靜態(tài)(static)的成員函數(shù)。
一般的虛函數(shù)聲明形式為:
virtual 函數(shù)類型 函數(shù)名(形參表)
{
函數(shù)體
}

虛函數(shù)就是在類的聲明中用關鍵字virtual限定的成員函數(shù)。以上聲明形式是成員函數(shù)的實現(xiàn)也在類的聲明中的情況。如果成員函數(shù)的實現(xiàn)在類的聲明外給出時,則虛函數(shù)的聲明只能出現(xiàn)在類的成員函數(shù)聲明中,而不能在成員函數(shù)實現(xiàn)時出現(xiàn),簡而言之,只能在此成員函數(shù)的聲明前加virtual修飾,而不能在它的實現(xiàn)前加。

析構函數(shù)用于在類的對象消亡時做一些清理工作,我們在基類中將析構函數(shù)聲明為虛函數(shù)后,其所有派生類的析構函數(shù)也都是虛函數(shù),使用指針引用時可以動態(tài)綁定,實現(xiàn)運行時多態(tài),通過基類類型的指針就可以調(diào)用派生類的析構函數(shù)對派生類的對象做清理工作。

前面講過,析構函數(shù)沒有返回值類型,沒有參數(shù)表,所以虛析構函數(shù)的聲明也比較簡單,形式如下:
virtual ~類名();

純虛函數(shù)

即使有的虛函數(shù)在基類中不需要做任何工作,我們也要寫出一個空的函數(shù)體,這時這個函數(shù)體沒有什么意義,重要的是此虛函數(shù)的原型聲明。C++為我們提供了純虛函數(shù),讓我們在這種情況下不用寫函數(shù)實現(xiàn),只給出函數(shù)原型作為整個類族的統(tǒng)一接口就可以了,函數(shù)的實現(xiàn)可以在派生類中給出。

純虛函數(shù)是在基類中聲明的,聲明形式為:

 virtual 函數(shù)類型 函數(shù)名(參數(shù)表) = 0;

大家可以看到,純虛函數(shù)的聲明形式與一般虛函數(shù)類似,只是最后加了個“=0”。純虛函數(shù)這樣聲明以后,在基類中就不再給出它的實現(xiàn)了,各個派生類可以根據(jù)自己的功能需要定義其實現(xiàn)。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容