c++定義基類和派生類


轉自:https://www.cnblogs.com/mu-ye/p/7756724.html

更多內容見http://www.cnblogs.com/mu-ye/p/7754368.html

以下介紹在定義有繼承關系的類時可能用到的基本性質:

定義基類

     基類通常都應該定義個虛析構函數,即使該函數不執行任何操作也是如此。

     成員函數與繼承:

     C++語言中,基類必須將它的兩種成員函數分離開來:一種是基類希望派生類直接繼承不需要改變的函數,另一種是基類希望其派生類進行覆蓋的函數。對於后者,基類通常將其定義為虛函數,當我們使用引用或指針調用虛函數時,該調用將被動態綁定。

     任何構造函數之外的非靜態函數都可以是虛函數。

     關鍵字virtual只能出現在類內部的函數聲明中而不能用於類外部的函數定義。

     如果基類把一個函數定義為虛函數,則該函數在派生類中隱式地也是虛函數。

     訪問控制與繼承:

     派生類能訪問共有成員,而不能訪問私有成員。不過在某些時候基類中還有這樣一種成員,基類希望它的派生類有權訪問該成員,同時禁止其他用戶訪問。我們用受保護的訪問運算符說明這樣的成員。    

 

定義派生類

    派生類必須通過使用派生類列表明確指出它是從哪個(哪些)基類派生而來的。每個基類前面可以有以下三種訪問說明符中的一個:public、protected和private。

    訪問說明符的作用是控制派生類從基類繼承而來的成員對派生類用戶是否可見。

    大多數類都只繼承自一個類,這種形式的繼承被稱作“單繼承”。這里主要介紹單繼承。

    1、派生類中的虛函數:

       派生類經常(但不總是)覆蓋它繼承的虛函數。如果派生類沒有覆蓋其基類中的某個函數,則該虛函數的行為類似於其他的普通成員,派生類會直接繼承其在基類中的版本。

       C++11新標准允許派生類顯示地注明它使用某個成員函數覆蓋了它繼承的虛函數。

    2、派生類對象及派生類向基類的類型轉換:

       一個派生類對象包含多個組成部分:一個含有派生類自己定義的(非靜態)成員的子對象,以及一個與該派生類繼承的基類對應的子對象,如果有多個基類,那么這樣的子對象也有多個。

       因為在派生類對象中含有與其基類對應的組成部分,所以我們能把派生類對象當做基類來使用,而且我們也能將基類的指針或引用綁定到派生類對象中的基類部分上。這種轉化通常稱為派生類到基類的類型轉換。

       在派生類對象中含有與基類對應的組成部分,這一事實是繼承的關鍵所在。

    3、派生類構造函數

       盡管派生類對象中含有從基類繼承而來的成員,但是派生類並不能直接初始化這些成員。和其他創建了基類對象的代碼一樣,派生類也必須使用基類的構造函數來初始化它的基類部分。(note:每個類控制它自己的成員初始化過程)

       除非我們特別指出,否則派生類對象的基類部分會像數據成員一樣執行默認初始化。如果想使用其他的基類構造函數,我們需要以類名加圓括號內的實參列表的形式為構造函數提供初始值。

       首先初始化基類的部分,然后按照聲明的順序依次初始化派生類的成員。

    4、派生類使用基類的成員

       派生類可以訪問基類的公有成員和受保護成員。

       派生類的作用域嵌套在基類的作用域之內。因此,對於一個派生類的一個成員來說,它使用派生類成員的方式與使用基類成員的方式並沒有什么不同。

       關鍵概念:遵循基類的接口。必須明確一點:每個類負責定義各自的接口。要想與類的對交互必須使用該類的接口,即使這個對象是派生類的基類部分也是如此。派生類應遵循基類的接口。

    5、繼承與靜態成員

       如果基類定義了一個靜態成員,則在整個繼承體系中只存在該成員的唯一定義。不論從基類中派生出多少個派生類,對於每個靜態成員來說只存在唯一的實例。

       靜態成員遵循通用的訪問控制規則。

    6、派生類的聲明

       派生類的聲明與其他類差別不大,聲明中含有類名但是不包含派生類列表。

       一條聲明語句的目的是另程序知曉某個名字的存在以及該名字表示一個什么樣的實體。

    7、被用作基類的類

       如果我們想用某個類作為基類,則該類必須已經定義而非僅僅聲明。

       這一規定的原因顯而易見:派生類中包含並且可以使用它從基類繼承而來的成員,為了使用這些成員,派生類當然要知道它們是什么。因此該規定還有一層隱藏的意思,即一個類不能派生它本身。

       一個類是基類,同時它也可以是一個派生類。 所以基類有直接基類和間接基類。最終的派生類將包含它的直接基類的子對象以及每個間接基類的子對象。

    8、防止繼承的發生

       有時我們會定義這樣一種類,我們不希望其他類繼承它,或者不想考慮它是否適合作為一個基類。為了實現這一目的,C+11提供了一種防止繼承發生的方法,即在類名后跟一個關鍵字final。

   

類型轉換與繼承

    理解基類和派生類之間的類型轉換是理解C++語言面向對象編程的關鍵。

    存在繼承關系的類是一個重要的例外:我們可以將基類的指針和引用綁定到派生類對象上。

    可以將基類引用和指針綁定到派生類對象上有一層極為重要含義:當使用基類引用或指針時,實際上我們並不清楚該引用(或指針)所綁定對象的真實類型。智能指針類也支持派生類向基類的類型轉換。

    1、靜態類型和動態類型

       舉例:函數的基類引用形參是靜態類型,它的動態類型依賴於其綁定的實參,動態類型直到在運行時調用該函數時才會知道。

       基類的指針或引用的靜態類型可能與其動態類型不一致。

       如果表達式既不是引用也不是指針,則它的動態類型永遠與靜態類型一致。

    2、在對象之間不存在類型轉換

       派生類向基類的自動類型轉換只對引用或指針類型有效,在派生類類型和基類類型之間不存在這樣的轉換。很多時候我們確實將派生類對象轉換成它的基類類型,但是這種轉換的實際發生過程往往與我們期望的有所差別。

       請注意,當我們初始化或賦值一個類類型的對象時,實際上是在調用某個函數。當執行初始化時,我們調用構造函數;而當執行賦值操作時,我們調用賦值運算符。這些成員通常都包含一個參數,該參數的類型是類類型的const版本的引用。

       因為這些成員接受引用作為參數,所以派生類向基類的類型轉化允許我們給基類的拷貝/移動操作傳遞一個派生類對象。這些操作不是虛函數。當我們給基類的構造函數傳遞一個派生類對象時,實際運行的構造函數是基類中定義的那個,顯然該構造函數只能處理基類自己的成員。類似的,如果我們將一個派生類對象賦值給一個基類對象,則實際運行的賦值運算符也是基類中定義的那個,該運算符同樣只能處理基類自己的成員。在上述過程中會忽略派生類多於基類的部分,所以可以說這部分被切掉了。

       當我們用一個派生類對象為一個基類對象初始化或賦值時,只有該派生類對象中的基類部分會被拷貝、移動或賦值,它的派生類部分將會被忽略掉。

 

關鍵概念:存在繼承關系的類型之間的轉換規則

    1、從派生類向基類的類型轉換只對指針或引用類型有效。

    2、基類向派生類不存在隱式類型轉換。

    3、和任何其他成員一樣,派生類向基類的類型轉換也可能會由於訪問受限而變得不可行。

    盡管自動類型轉換只對指針或引用類型有效,但是繼承體系中的大多數類仍然(顯示或隱式低)定義了拷貝控制成員。因此,我們通常能夠將一個派生類對象拷貝、移動或賦值給一個基類對象。不過需要注意到是,這種操作只處理派生類對象的基類部分。


免責聲明!

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



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