溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

繼承&派生

發(fā)布時間:2020-07-06 05:33:18 來源:網(wǎng)絡(luò) 閱讀:992 作者:我是你帆哥 欄目:編程語言

一、什么是繼承和派生

   封裝、繼承、多態(tài)是C++的三個重要的特性。在面向?qū)ο蟮募夹g(shù)中強調(diào)軟件的可重用性,而繼承機制就是用來解決軟件的重用問題。在C++中,所謂“繼承”就是在一個已經(jīng)存在的類的基礎(chǔ)上建立一個新的類。已經(jīng)存在的類成為基類或父類,新建立的類稱為派生類或子類。

   一個類從一個已有的類那里獲得已有的特性,這種現(xiàn)象稱為類的繼承。通過繼承,一個新建的子類從父類那里獲得父類的特性。從另一角度說,從已有的類(父類)產(chǎn)生一個新的類(子類),稱為類的派生。派生類繼承類基的所有數(shù)據(jù)成員和成員函數(shù),并可以對成員做出必要的調(diào)整。一個基類可以派生出多個派生類,每一個派生類又能作為基類再派生出新的派生類。因此基類和派生類是相對而言的。類的每一次派生都繼承了其基類的基本特征,同時又根據(jù)需要做出新的調(diào)整。一個派生類只從一個基類派生,這種稱為單繼承。一個派生類也有從兩個或多個基類,這種稱為多繼承。關(guān)于基類和派生類的關(guān)系可以理解為:基類是派生類的抽象,派生類是基類的具體化。


二、派生類的聲明方式

聲明一個單繼承的派生類的一般形式:

   class 派生類名:繼承方式 基類名

   {

         派生類新增加的成員

   };

  其中繼承方式有三種:public(公用的),protected(受保護(hù)的),private(私有的)。此項如果不寫則默認(rèn)為private(私有的)。

例:假設(shè)已經(jīng)聲明了一個基類Time,在此基礎(chǔ)上通過單繼承聲明一個派生類Date

classDate:publicTime                              //公用繼承

{

public:

                voiddisplay()

                {

                                cout << _year << _month << _day << endl;

                }

private:

                int_year;

                int_month;

                int_day;

};


三、派生類的構(gòu)成

   派生類的成員包括從基類繼承過來的成員和自己增加的成員兩大部分。但是并不是說把基類的成員和派生類增加的成員簡單的加在一起就成為了派生類。構(gòu)造一個派生類包括以下3個部分:

1、從基類接受成員

   派生類把基類全部成員(不包括構(gòu)造和析構(gòu)函數(shù))接受過來。不能選擇接受一部分而舍棄另一部分,這是不可選擇的。因此如果不能合理的選擇基類的話,會造成數(shù)據(jù)的冗余。

2、調(diào)整從基類接收的成員

   雖然接受基類成員是不可選擇的,但是可與對這些成員做出調(diào)整,例如同繼承方式改變基類成員在派生類中的訪問屬性。此外,還可以在派生類中聲明一個與基類成員同名的成員,則派生類中的新成員會覆蓋基類的同名成員。要注意,如果是成員函數(shù)的話,不僅要求函數(shù)名相同,還要求函數(shù)的參數(shù)列表也相同。

3、在派生類中增加新的成員

   基類只是提供了最基本的功能,而另有些功能未實現(xiàn),所以就需要在聲明派生類時加入某些具體的功能,形成適用于某一特定應(yīng)用的派生類。此外,在聲明派生類時,一般還有定義適用于派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。


四、派生類成員的訪問屬性

1、基類成員函數(shù)只能訪問基類成員

2、派生類成員函數(shù)可以訪問派生類自己增加的成員

3、基類的成員函數(shù)不能訪問派生類新增加的成員。

4、派生類成員函數(shù)在類內(nèi)或類外訪問基類的成員,這種情況比較復(fù)雜,它不僅取決于基類成員在基類中的訪問屬性,還要考慮派生類所聲明的對基類的繼承方式。

繼承&派生


繼承&派生

通過上表可以看出,在派生類中有4中不同的訪問屬性:

1、公用的,在派生類內(nèi)和派生類外都可以訪問。

2、受保護(hù)的,派生類內(nèi)可以訪問,派生類外不可以訪問。

3、私有的,只能在派生類內(nèi)進(jìn)行訪問。

4、不可訪問的,或者說不能直接訪問的,可以通過基類成員函數(shù)進(jìn)行間接訪問。


五、派生類的構(gòu)造函數(shù)

  因為基類的構(gòu)造函數(shù)和析構(gòu)不能通過繼承得到,因此,對繼承過來的基類成員的初始化工作也要由派生類的構(gòu)造函數(shù)承擔(dān),所以就要在執(zhí)行派生類的構(gòu)造函數(shù)時,調(diào)用基類的構(gòu)造函數(shù)。其一般形式為:

    派生類構(gòu)造函數(shù)名(總參數(shù)列表):基類構(gòu)造函數(shù)名(參數(shù)列表)

   {派生類中新增加數(shù)據(jù)成員初始化語句}


   基類成員的初始化要通過初始化列表進(jìn)行初始化??倕?shù)列表中包含了基類構(gòu)造函數(shù)所需要的參數(shù)和對派生類自增的數(shù)據(jù)成員初始化所需要的參數(shù)。而基類構(gòu)造函數(shù)名后面的參數(shù)列表中只有參數(shù)名而不包括參數(shù)類型,因為在這里是調(diào)用基類的構(gòu)造函數(shù),這些參數(shù)是實參。

例:

classTime

{

public:

                Time(inthour= 0,intminute= 0,intsec= 0) :_hour(hour)

                                , _minute(minute)

                                , _sec(sec)

                {

                }

private:

                int_hour;

                int_minute;

                int_sec;

};



classDate:publicTime

{

public:

                Date(inthour= 0,intminute= 0,intsec= 0,intyear= 0,intmonth= 0,intday= 0) :Time(hour,minute,sec)                            //調(diào)用基類的構(gòu)造函數(shù)對基類成員進(jìn)行初始化

                {

                                _year =year;

                                _month =month;

                                _day =day;

                }

private:

                int_year;

                int_month;

                int_day;

};

有子對象的派生類,對子對象初始化也是同樣的方法。


所以派生類構(gòu)造函數(shù)應(yīng)該包含3個部分:

1、對基類數(shù)據(jù)成員初始化

2、對子對象初始化

3、對派生類數(shù)據(jù)成員初始化


   系統(tǒng)時自動調(diào)用基類的構(gòu)造函數(shù)的,將派生類的構(gòu)造函數(shù)寫成上面那種方式只是為了給基類的構(gòu)造函數(shù)傳參而已,假如不寫成上面那種形式,系統(tǒng)還是會調(diào)用基類的默認(rèn)構(gòu)造函數(shù)的(子對象也是相同的道理)。系統(tǒng)先調(diào)用基類的構(gòu)造函數(shù)再執(zhí)行派生類的構(gòu)造函數(shù)。


六、派生類中的析構(gòu)函數(shù)

   我們只需要定義派生類中新增成員的構(gòu)造函數(shù)即可。基類的析構(gòu)函數(shù)和子對象的析構(gòu)函數(shù)是系統(tǒng)自動調(diào)用的。調(diào)用析構(gòu)函數(shù)的順序與調(diào)用構(gòu)造函數(shù)的順序相反,先執(zhí)行派生類的析構(gòu)函數(shù)再調(diào)用基類的析構(gòu)函數(shù)。


七、多重繼承

多重繼承:運行一個派生類同時繼承多個基類。

1、聲明多重繼承的方法

  例:如果已經(jīng)聲明了類A、類B、類C,可以聲明多重繼承的派生類D:

    class D:private A,protected B,public C

    { 類D新增的成員};

  D是多重繼承的派生類,它以私有繼承方式繼承A類,以保護(hù)繼承的方式繼承B類,以公用繼承的方式繼承C類。


2、多重繼承派生類的構(gòu)造函數(shù)

   多重繼承派生類的構(gòu)造函數(shù)形式與單繼承的構(gòu)造函數(shù)形式基本相同,只是在初始化表中包含多個基類構(gòu)造函數(shù)。如:

    派生類構(gòu)造函數(shù)名(總參數(shù)列表):基類1構(gòu)造函數(shù)(參數(shù)列表),基類2構(gòu)造函數(shù)(參數(shù)列表)...

       {派生類中新增數(shù)據(jù)成員初始化語句 }; 


3、多重繼承引發(fā)的問題

多重繼承會引發(fā)二義性問題,即繼承的成員同名,這時引用的話會產(chǎn)生二義性而發(fā)生錯誤。

  例:如果類A和類B中都有數(shù)據(jù)成員name和成員函數(shù)display。如果類C是類A和類B的直接派生類。

  如果在main函數(shù)中有:

        C c1;

        c1.name;

        c1.display();

   因為類A和類B都有數(shù)據(jù)成員name和成員函數(shù)display,系統(tǒng)無法判別要訪問的是哪個基類的成員,因此編譯出錯。要解決      這個問題,可以用基類名來限制作用域:

        c1.A::name;

        c1.A::display();     //這樣就表示引用的是類A中的成員。


八、虛基類

假如一個派生類有多個直接基類,而這些直接基類又有一個共同的基類。如圖:

繼承&派生

繼承&派生

   那么就會出現(xiàn)一個問題,在類E中會保存3份類A的成員,如果人們只需要一份類A的成員,那么這種情況下就會占用較多的內(nèi)存空間,還增加訪問的難度。而在實際中人們往往只需要一份類A的成員。為了解決這個問題,C++中提供了虛基類的方法,使得在繼承間接共同基類時只保留一份成員。

現(xiàn)在將類A聲明為虛基類:

class A

{...};

class B:virtual public A    //A是B的虛基類

{...};

class C:virtual public A    //A是C的虛基類

{...};

class D:virtual public A    //A是D的虛基類

{...};

注意:虛基類并不是在聲明基類時聲明的,而是在聲明派生類時,指定繼承方式時聲明的。



聲明虛基類的一般方法如下:

class 派生類名:virtual 繼承方式 基類名


   經(jīng)過虛基類的聲明后,當(dāng)基類通過多條派生路徑被一個派生類繼承時,該派生類值繼承該派生類一次,即基類成員派生類只保留一次。


1、虛基類的初始化

class A

{

A(int i=0){}

...};


class B:virtual public A    //A是B的虛基類

{

B(int j=2):A(j){}

...};


class C:virtual public A    //A是C的虛基類

{

 C(int k=3):A(k)()

...};


class D:virtual public A    //A是D的虛基類

{

D(int n=4):A(n){}

...};


class E:public B,public C,public D

{

E(int i=0,int j=0,int k=0,int n=0):A(i),B(j),C(k),D(n){}

...};


注意:

   在定義類E的構(gòu)造函數(shù)時,與以往使用的方法有所不同,由于虛基類在派生類中只有一份數(shù)據(jù)成員,所以這份數(shù)據(jù)成員必須由派生類之間給出。規(guī)定:在最后的派生類中不僅要負(fù)責(zé)對其之間基類進(jìn)行初始化,還有負(fù)責(zé)對虛基類進(jìn)行初始化。C++編譯系統(tǒng)只執(zhí)行最后的派生類對虛基類的構(gòu)造函數(shù)的調(diào)用,而忽略虛基類的其他派生類對虛基類構(gòu)造函數(shù)的調(diào)用。


九、基類與派生類的轉(zhuǎn)換

   派生類是繼承了基類的數(shù)據(jù)成員,那么基類對象與派生類對象之間是否存在賦值關(guān)系,可否進(jìn)行類型的轉(zhuǎn)換???

   答案是可以的?;悓ο笈c派生類對象之間 有賦值兼容的關(guān)系,由于派生類中包含從基類中繼承的成員,因此可以將派生類的值賦給基類對象,在使用基類對象的時候可以用派生類對象替代。但是注意,這種關(guān)系是單向的,不可逆的。


具體有以下4個方面:

1、派生類對象可以向基類對象賦值,這種關(guān)系是單向的。

2、派生類對象可以代替基類對象向基類對象的引用進(jìn)行賦值或初始化。

3、如果函數(shù)的參數(shù)是基類對象的或基類對象的引用,相應(yīng)的實參可以是派生類的對象。

4、派生類的地址可以賦給指向基類對象的指針。即指向基類的指針可以指向派生類的對象。不過,指向的是派生類對象中從基類繼承的部分。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI