類的繼承和派生


1、c++類的繼承和派生機制

繼承指的是從先輩出得到屬性和行為的特征,也就是新類從已有的類那里得到已有的特性,反過來看,從已有類產生新類的過程就是類的派生。因此類的繼承和派生是一個成對出現的概念,原來的類稱為基類或者父類,產生的新類稱為派生類或者子類,派生類同樣可以作為基類派生新的類,這樣就可以建立一個具有共同特性的對象家族,實現代碼的重用。派生新類的過程一般包括,吸收父類的成員,調整父類的成員,添加新的成員。

2、派生類的定義:

class 派生類名稱:繼承方式   第一個基類名,繼承方式   第二個基類名稱,...,繼承方式   第n個基類名稱

{

派生類成員聲明;

};

例:

class Linequ: public Matrix       //公有派生類Linequ定義
{
public:
    Linequ(int dims=2);            //構造函數
    ~Linequ();                    //析構函數
    void setLinequ(double *a,double *b);//方程賦值
    void printL();                  //顯示方程
    int Solve();                    //全選主元高斯消去法求解方程
    void showX();                   //顯示方程的解
private:                            //私有數據
    double *sums;                   //方程右端項
    double *solu;                   //方程的解
};

其中

Linequ是派生類的名稱;public是繼承方式,繼承方式主要的作用是控制從基類繼承的成員的訪問屬性(另外還有 private 和protected兩種繼承方式,此處未使用)父類是Matrix;花括號{}里面的內容是派生類的成員聲明;

      這里需要注意的是一個派生類也可以同時繼承多個基類,這叫做多繼承,像上面的代碼例子是只繼承類一個Matrix基類,就是單繼承的。另外派生出來的新類也可以繼續作為基類再次派生新類。

3、派生類生成的過程

    派生類主要有三個步驟,吸收父類的成員,調整父類的成員,添加新的成員。

    吸收父類成員

    就是將基類中的成員,除了構造函數和析構函數之外,全都接收到派生類中,因此構造函數和析構函數是不能被繼承的。

   調整基類成員包括兩個方面,

    一個是基類成員的訪問控制問題,主要依靠派生列定義時的繼承方式來控制;第二個是對基類數據成員或函數成員的隱藏,隱藏的方式就是在新類中聲明一               個和基類中數據或者       函數同名的成員,這樣派生類中的該成員就實現了對基類數據成員或函數成員的隱藏。如果在派生類中或者通過派生類的對象,直接使用成員名就只能訪問到派               生類中聲明的同       名函數,無法基類中的數據成員或函數成員,從而實現了對基類成員的隱藏。

   添加新成員是繼承和派生機制的核心

    因為根據實際情況給派生類添加新的適當的數據和成員,就可以實現新的功能,例如派生類沒有繼承基類的構造函數和析構函數,所以就要在派生               列中加入新的構造函數和析構       函數來完成初始化和掃尾工作。

4、派生類的訪問控制

    派生類的訪問控制是通過類的繼承方式實現的,類的繼承方式主要有public(公有繼承),protected(保護繼承),private(私有繼承)。按照這三種繼承方式,從基類繼承的基類成員在     派生類中的訪問屬性也是不同的,這里的訪問屬性不同主要是從兩方面來說的,首先是派生類中的新增成員對從基類繼承的成員的訪問,其次是派生類外部,即通過派生類聲明的對象訪問從     基類繼承的成員函數。

    第一:公有繼承 方式

    當類的繼承為公有繼承方式時,基類的公有和保護成員的訪問成員在派生類中仍然作為派生類的公有成員和保護成員,派生類的其他成員可以直接訪問。在類之外只能通過派生類的對象訪問    從基類繼承的公有成員。但是無論是派生類的成員還是派生類的對象都無法直接訪問基類的私有成員。

   第二:私有繼承方式

   當類的繼承為私有繼承時,基類的公有和保護成員被繼承后作為派生類的私有成員,派生類的其他成員可以直接訪問。但是類外部的派生類對象無法直接訪問它們。但是為了在私有繼承的情    況下保證基類的一部分外部接口特征能夠在派生類中存在,可以在派生類中聲明基類的同名函數,利用派生類對基類的訪問能力,把基類的成員函數功能搬過來,同時我們也要知道,根據同    名隱藏原則,派生類在調用時調用的肯定是派生類的同名函數。

   第三:保護繼承方式

   當類的繼承為保護繼承時,訪問控制屬性同私有繼承方式相同,但是如果派生類作為新的基類,繼續派生時,私有繼承和保護繼承就有區別啦!例如B類以私有繼承的方式繼承了A類,B類又    派生了C類,那么C類的成員和對象都不能訪問從A類中繼承的成員。如果B類是以保護繼承的方式繼承了A類,那么A類中的公有和保護成員在B類中就是保護成員,若是B類再派生出C類,那    么A類中的公有和保護成員就被C類間接繼承后,有可能是保護的或者私有的(是B到C的派生方式決定),因此C類中的成員可能訪問從A中繼承的成員。好繞呀!

   從繼承的訪問權限可以看出,如果類A中含有保護成員member_of_protected,那么對於這個類A定義的對象a來講,A類中的保護成員member_of_protected和私有成員                        member_of_privated是不可訪問的。但是如果A類派生了子類AA,那么對於子類AA來說,公有成員和保護成員具有相同的訪問權限。也就是A類中保護成員可能被它的派生類訪問,但是      一定不可能被程序中的普通函數或者與A類平行的其他類訪問。這樣就實現了成員的隱藏和共享,實現了代碼的高效利用。  

 4、類型兼容規則

    類型兼容性規則指的是在任何需要基類的對象的地方,都可以使用公有派生類的對象來替代。派生類的對象可以賦值給基類的對象 ,可以初始化基類的引用,派生對象的地址可以賦值給指       向基類的指針。這個的具體應用據說在多態特性中,等學到多態在具體描述~~~~~(偷個懶~~~~)      

5、派生類的構造函數和析構函數

    構造函數

    因為基類的構造函數和析構函數是不能被繼承的,所以在派生類中,如果要對派生類新增的成員進行初始化,就必須為派生類添加新的構造函數和析構函數,另外需要注意的是,派生類的構     造函數只負責對派生類的新增成員函數記性初始化,對於所有從基類繼承下來的成員,其初始化工作還是由基類的構造函數完成的。同樣對派生類對象的清理工作也需要加入新的析構函數。     因為派生類的成員有所有基類的成員和派生類的新增成員,若是派生類中還內嵌了其他類對象,那么派生類的成員還會間接包括這些對象的成員,概括起來就是,構造派生類的對象時,需要     對基類的成員,新增成員和內嵌對象的成員進行初始化。

    派生類的構造函數語法為:

    派生類名::派生類名(參數總表):基類名1(參數表1),...,基類名n(參數表n),內嵌對象名1(內嵌對象參數表1),...,內嵌對象名m(內嵌對象參數表m)

    {

    派生類新增成員的初始化語句;

     }

    需要注意的是,雖然參數總表要求給出基類,新增類成員,內嵌成員對象的全部參數,但是實際使用時可以根據需要自行選擇給出,不一定都給出。當一個類同時繼承多個基類時,對於所有     需要給予參數初始化的基類,都要顯示給出基類的名稱和參數,對於使用默認構造函數的基類,可以不給出類名。同樣對於對象成員,如果使用默認構造函數,也不需要給出對象名和參數       表。對於單繼承的,只需要給出基類名稱就可以啦!

    如果基類聲明了但有形參數表的構造函數,派生類就應當聲明構造函數,提供一個將參數傳遞給基類構造函數的途徑,保證基類初始化時有必要的數據。

    在構造派生類構造函數的執行次序是:

     (1)調用基類構造函數,調用順序按照它們被繼承時聲明的順序(從左到右);(也就是按照“基類名1(參數表1),基類名2(參數表2),...,基類名n(參數表n)”這個順序!!)

     (2)調用內嵌成員對象的構造函數,調用順序按照它們在類中聲明的順序;

     (3)調用派生類的構造函數中的內容

     拷貝構造函數

     對於一個類,如果程序員沒有編寫拷貝構造函數,編譯系統就會自動生成一個默認的拷貝構造函數。如果編寫拷貝構造函數,那么需要給基類相應的拷貝構造函數傳遞參數,例如,C類是B類的派生類,C類的拷貝構造函數形式如下:

     C::C(C &c1):B(c1)

   {

     ...

   }

     析構函數

     派生類析構函數的聲明方法與沒有繼承關系的類中析構函數的聲明方法完全相同,但是執行次序和構造函數正好相反,首先對派生類新增普通成員清理,然后對派生類新增成員清理,最后        對所有基類繼承類的成員清理。

6、派生類成員的標志和訪問

     派生類成員分為四種:

      (1)不可訪問的成員

             從基類私有成員的繼承來的成員。

      (2)私有成員

             從基類繼承的成員和新增的成員

      (3)保護成員

              新增成員或者從基類繼承來的

       (4)公有成員

     作用域分辨符

       作用域分辨符是“::”,它的最用是限定訪問成成員所在的類的名稱,一般形式是:

               基類名::成員名;//數據成員

               基類名::成員名(參數名);//函數成員

      作用域分辨符唯一識別成員的過程,在類的派生結構層中,基類的成員和派生類新增成員都具有類作用域,兩者的最用范圍是相互包含的,派生類在內層。此時,如果派生類聲明了一個和       基類成員同名的新成員,派生的新成員就隱藏了外層同名成員,直接使用成員名只能訪問到派生類的成員,在沒有虛函數的情況下,若是派生類聲明了與基類成員函數同名的新函數,即使      函數的參數表不同,從基類繼承的同名函數的所有承載形式也都會被隱藏。如果要訪問被隱藏的成員,就需要使用作用域分辨符和基類名來限定。因此,“對象名.成員名”這種方式可以唯一     標識和訪問派生類的新增成員,基類的同名成員可以使用基類名和作用域分辨符訪問。因此在派生類即建立派生類對象的模塊中,派生類新增成員如果隱藏了基類的同名成員,這是使用“對       象名.成員名”的方式,就只能訪問到派生類的新增成員函數,對基類同名成員函數的訪問只能通過基類名和作用域分辨符來實現,也就是說,必須明確告訴系統要使用哪個基類的成員。

    總之原則是:

    派生的新類中如果有和它所繼承的基類中相同的成員,那么原來基類中的成員在這個派生類中就被隱藏,要想訪問基類中的這些隱藏成員就要用到作用域來     指定基類,繼承多個基類也是如此。

7、虛基類

    以前討論多繼承的都是所有基類之間沒有繼承關系,但是如果這個條件不滿足呢?如果某個派生類的部分或者全部直接基類是從另一個共同的基類派生而來,在這些直接基類中,從上一級中    繼承來的成員就擁有相同的名稱,因此派生類會產生同名現象,雖然可以通過作用域來限定,但是這樣多份相同的成員增加了內存的開銷,如何解決呢?我們可以通過虛基類來解決。

   虛基類就是從不同路徑繼承過來的額同名數據成員在內存中只有一個拷貝,同一個函數名也只用一個映射,虛基類的聲明語法:

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

     其中虛基類的關鍵字作用范圍只對緊跟其后的基類起作用。

     但是虛基類不是這么簡單的,用到再說吧!!

 

 

 

 

 

 

 

    

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM