繼承&派生

1、什麼是繼承和派生ide

   封裝、繼承、多態是C++的三個重要的特性。在面嚮對象的技術中強調軟件的可重用性,而繼承機制就是用來解決軟件的重用問題。在C++中,所謂「繼承」就是在一個已經存在的類的基礎上創建一個新的類。已經存在的類成爲基類或父類,新創建的類稱爲派生類或子類。函數

   一個類從一個已有的類那裏得到已有的特性,這種現象稱爲類的繼承。經過繼承,一個新建的子類從父類那裏得到父類的特性。從另外一角度說,從已有的類(父類)產生一個新的類(子類),稱爲類的派生。派生類繼承類基的全部數據成員和成員函數,並能夠對成員作出必要的調整。一個基類能夠派生出多個派生類,每個派生類又能做爲基類再派生出新的派生類。所以基類和派生類是相對而言的。類的每一次派生都繼承了其基類的基本特徵,同時又根據須要作出新的調整。一個派生類只從一個基類派生,這種稱爲單繼承。一個派生類也有從兩個或多個基類,這種稱爲多繼承。關於基類和派生類的關係能夠理解爲:基類是派生類的抽象,派生類是基類的具體化。url


2、派生類的聲明方式spa

聲明一個單繼承的派生類的通常形式:指針

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

   {繼承

         派生類新增長的成員內存

   };作用域

  其中繼承方式有三種:public(公用的),protected(受保護的),private(私有的)。此項若是不寫則默認爲private(私有的)。it

例:假設已經聲明瞭一個基類Time,在此基礎上經過單繼承聲明一個派生類Date

classDate:publicTime                              //公用繼承

{

public:

                voiddisplay()

                {

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

                }

private:

                int_year;

                int_month;

                int_day;

};


3、派生類的構成

   派生類的成員包括從基類繼承過來的成員和本身增長的成員兩大部分。可是並非說把基類的成員和派生類增長的成員簡單的加在一塊兒就成爲了派生類。構造一個派生類包括如下3個部分:

一、從基類接受成員

   派生類把基類所有成員(不包括構造和析構函數)接受過來。不能選擇接受一部分而捨棄另外一部分,這是不可選擇的。所以若是不能合理的選擇基類的話,會形成數據的冗餘。

二、調整從基類接收的成員

   雖然接受基類成員是不可選擇的,可是可與對這些成員作出調整,例如同繼承方式改變基類成員在派生類中的訪問屬性。此外,還能夠在派生類中聲明一個與基類成員同名的成員,則派生類中的新成員會覆蓋基類的同名成員。要注意,若是是成員函數的話,不只要求函數名相同,還要求函數的參數列表也相同。

三、在派生類中增長新的成員

   基類只是提供了最基本的功能,而另有些功能未實現,因此就須要在聲明派生類時加入某些具體的功能,造成適用於某一特定應用的派生類。此外,在聲明派生類時,通常還有定義適用於派生類的構造函數和析構函數。


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

一、基類成員函數只能訪問基類成員

二、派生類成員函數能夠訪問派生類本身增長的成員

三、基類的成員函數不能訪問派生類新增長的成員。

四、派生類成員函數在類內或類外訪問基類的成員,這種狀況比較複雜,它不只取決於基類成員在基類中的訪問屬性,還要考慮派生類所聲明的對基類的繼承方式。



spacer.gif

經過上表能夠看出,在派生類中有4中不一樣的訪問屬性:

一、公用的,在派生類內和派生類外均可以訪問。

二、受保護的,派生類內能夠訪問,派生類外不能夠訪問。

三、私有的,只能在派生類內進行訪問。

四、不可訪問的,或者說不能直接訪問的,能夠經過基類成員函數進行間接訪問。


5、派生類的構造函數

  由於基類的構造函數和析構不能經過繼承獲得,所以,對繼承過來的基類成員的初始化工做也要由派生類的構造函數承擔,因此就要在執行派生類的構造函數時,調用基類的構造函數。其通常形式爲:

    派生類構造函數名(總參數列表):基類構造函數名(參數列表)

   {派生類中新增長數據成員初始化語句}


   基類成員的初始化要經過初始化列表進行初始化。總參數列表中包含了基類構造函數所須要的參數和對派生類自增的數據成員初始化所須要的參數。而基類構造函數名後面的參數列表中只有參數名而不包括參數類型,由於在這裏是調用基類的構造函數,這些參數是實參。

例:

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)                            //調用基類的構造函數對基類成員進行初始化

                {

                                _year =year;

                                _month =month;

                                _day =day;

                }

private:

                int_year;

                int_month;

                int_day;

};

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


因此派生類構造函數應該包含3個部分:

一、對基類數據成員初始化

二、對子對象初始化

三、對派生類數據成員初始化


   系統時自動調用基類的構造函數的,將派生類的構造函數寫成上面那種方式只是爲了給基類的構造函數傳參而已,假如不寫成上面那種形式,系統仍是會調用基類的默認構造函數的(子對象也是相同的道理)。系統先調用基類的構造函數再執行派生類的構造函數。


6、派生類中的析構函數

   咱們只須要定義派生類中新增成員的構造函數便可。基類的析構函數和子對象的析構函數是系統自動調用的。調用析構函數的順序與調用構造函數的順序相反,先執行派生類的析構函數再調用基類的析構函數。


7、多重繼承

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

一、聲明多重繼承的方法

  例:若是已經聲明瞭類A、類B、類C,能夠聲明多重繼承的派生類D:

    class D:private A,protected B,public C

    { 類D新增的成員};

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


二、多重繼承派生類的構造函數

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

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

       {派生類中新增數據成員初始化語句 }; 


三、多重繼承引起的問題

多重繼承會引起二義性問題,即繼承的成員同名,這時引用的話會產生二義性而發生錯誤。

  例:若是類A和類B中都有數據成員name和成員函數display。若是類C是類A和類B的直接派生類。

  若是在main函數中有:

        C c1;

        c1.name;

        c1.display();

   由於類A和類B都有數據成員name和成員函數display,系統沒法判別要訪問的是哪一個基類的成員,所以編譯出錯。要解決      這個問題,能夠用基類名來限制做用域:

        c1.A::name;

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


8、虛基類

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


spacer.gif

   那麼就會出現一個問題,在類E中會保存3份類A的成員,若是人們只須要一份類A的成員,那麼這種狀況下就會佔用較多的內存空間,還增長訪問的難度。而在實際中人們每每只須要一份類A的成員。爲了解決這個問題,C++中提供了虛基類的方法,使得在繼承間接共同基類時只保留一份成員。

如今將類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 繼承方式 基類名


   通過虛基類的聲明後,當基類經過多條派生路徑被一個派生類繼承時,該派生類值繼承該派生類一次,即基類成員派生類只保留一次。


一、虛基類的初始化

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的構造函數時,與以往使用的方法有所不一樣,因爲虛基類在派生類中只有一份數據成員,因此這份數據成員必須由派生類之間給出。規定:在最後的派生類中不只要負責對其之間基類進行初始化,還有負責對虛基類進行初始化。C++編譯系統只執行最後的派生類對虛基類的構造函數的調用,而忽略虛基類的其餘派生類對虛基類構造函數的調用。


9、基類與派生類的轉換

   派生類是繼承了基類的數據成員,那麼基類對象與派生類對象之間是否存在賦值關係,能否進行類型的轉換???

   答案是能夠的。基類對象與派生類對象之間 有賦值兼容的關係,因爲派生類中包含從基類中繼承的成員,所以能夠將派生類的值賦給基類對象,在使用基類對象的時候能夠用派生類對象替代。可是注意,這種關係是單向的,不可逆的。


具體有如下4個方面:

一、派生類對象能夠向基類對象賦值,這種關係是單向的。

二、派生類對象能夠代替基類對象向基類對象的引用進行賦值或初始化。

三、若是函數的參數是基類對象的或基類對象的引用,相應的實參能夠是派生類的對象。

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

相關文章
相關標籤/搜索