C 的繼承與多型 詳解2

2021-09-18 00:01:16 字數 4170 閱讀 1955

什麼叫多型:

**多型是指同樣的訊息被不同的物件接收時導致不同的行為。**所謂的訊息是指對類成員函式的呼叫,不同的行為是指不同的實現,也就是呼叫了不同的函式。

多型可以分為四類:過載多型,強制多型,包含多型,引數多型。前兩種稱為專用多型,後兩種稱為通用多型。函式過載,運算子過載屬於過載多型。強制型別轉換屬於強制多型。

包含多型是類族中定義不同類中同名成員函式的多型行為,主要通過虛函式來實現。引數多型與類模板相關聯,在使用時必須賦予實際的型別才可以例項化。

本章重點介紹過載和包含多型。虛函式是實現包含多型的基本機制。

多型從實現的角度可以劃分為兩類:編譯時多型和執行時多型前者在編譯的過程中確定了同名操作的具體操作物件,而後者則實在程式執行的過程中動態的確定操作所針對的具體物件。這種確定操作物件的過程就是繫結,繫結是指電腦程式自身彼此關聯的過程,也就是把乙個識別符號名和乙個儲存位址聯絡在一起的過程。靜態繫結和動態繫結分別對應著多型的兩種實現形式。

繫結工作在編譯階段完成的情況稱為靜態繫結,有些多型型別,其同名操作的具體物件能夠在編譯連線階段確定,通過靜態繫結解決,如過載,強制,引數多型。繫結工作在程式執行階段完成的情況成為動態繫結包含多型操作物件的確定就是通過動態繫結確定的。

待補充虛函式是動態繫結(包含多型)的基礎,虛函式必須是非靜態成員函式。虛函式經過派生後在類族中就可以實現執行過程中的多型。

根據型別相容性規則,可以使用派生類的物件代替基類物件,如果用基類型別的指標指向派生類的物件,就可以通過這個指標來訪問該物件,但問題是訪問到的只是從基類繼承來的同名成員。如果需要通過基類的指標指向派生類的物件來訪問派生類中某個與基類同名的成員,那麼首先在基類中將這個同名函式宣告為虛函式。這樣,通過基類型別的指標,就可以使不同派生類的不同物件產生不同的行為,就實現了包含多型。

virtual 函式型別 函式名(形參表)
虛函式宣告只能出現在類定義的函式原型中,而不能在成員函式實現的時候。

執行過程中的多型要滿足三個條件:

(1) 類之間滿足賦值相容規則

(2) 要宣告虛函式

(3)要由成員函式來呼叫或者是通過指標,引用來訪問虛函式。如果是使用物件名來訪問虛函式,則繫結在編譯過程中就可以進行(靜態繫結),而無需在執行過程中進行。

習慣:虛函式一般不宣告為內聯函式,因為對虛函式的呼叫需要動態繫結,而對內聯函式的處理是靜態的,所以虛函式一般不能以內聯函式處理。但將虛函式宣告為內聯函式也不會引起錯誤。

虛函式**示例

#include

using

namespace std;

class

base1

;void base1::

display()

const

class

base2

:public base1

;void base2::

display()

const

class

derived

:public base2

;void derived::

display()

const

void

fun(base1 *ptr)

intmain()

執行結果:

base1::

display()

base2::

display()

derived::

display()

注意與型別相容性規則中的**示例對比。

程式中類base1,base2和derived屬於同乙個類族,而且是通過公有派生而來,因此滿足型別相容性規則。同時基類base1的成員函式display()宣告為虛函式,程式後中使用物件指標來訪問函式成員,這樣繫結過程就是在執行中完成,實現了執行中多型。通過基類型別的指標就可以訪問到真正指向的物件的成員函式,這樣能夠對同一類族中的物件進行統一處理,抽象程度更高,程式更簡潔高效

在本程式中,派生類沒有顯式給出虛函式宣告,這是系統遵循以下規則來判斷派生類的乙個函式成員是不是虛函式:

• 該函式是否與基類的虛函式有相同的名稱

• 該函式是否與基類的虛函式有相同的引數個數,及相同的對應引數型別

• 該函式是否與基類的虛函式有相同的返回值型別或者滿足賦值相容規則的指標、引用型別的返回值型別

如果從名稱,引數,返回值型別3各方面檢查後,派生類的函式滿足了上述條件,就會自動確定為虛函式。這時,派生類的虛函式覆蓋了基類的虛函式。不僅如此,派生類中的虛函式還會隱藏基類中同名函式的所有其他過載形式

注意:使用派生類物件的指標仍然可以呼叫基類中被派生類覆蓋的成員,方法是使用:: 進行限定。例如:**ptr->base1::display(),**無論ptr所指向的動態型別是什麼,最終被呼叫的總是base1類的display()函式。

當基類構造函式呼叫虛函式時,不會呼叫派生類的虛函式,假設base類和derivd類中有虛函式virt(),在執行派生類derived的建構函式時,需要首先呼叫base類的建構函式。如果base:: base()呼叫了虛函式virt,則被呼叫的是base::virt()而不是derived::virt(),這是因為當基類被構造時,物件還不是乙個派生類的物件。同樣,當基類被析構時,物件已經不是乙個派生類物件了,所以如果base::~base()呼叫了virt()則別呼叫的是base::virt()而不是derived::virt()。

對於在基類中無法實現的函式,能否在基類中只說明函式原型用來規定整個類族的統一介面形式,而在派生類中給出具體的實現呢?c++提供了純虛函式來實現這一功能。

純虛函式是乙個在基類中宣告的虛函式,它在基類中沒有定義具體的操作內容,要求各派生類根據實際需要給出各自的定義。純虛函式的宣告形式:

virtual 函式型別 函式名(參數列)=

0;

純虛函式的函式體由派生類給出。

細節:基類中仍然允許對純虛函式給出實現,但即使給出實現,也必須由派生類覆蓋,否則無法例項化。如果將析構函式宣告為純虛函式,就必須給出具體的實現,因為派生類的析構函式執行完後,需要呼叫基類的析構函式(純虛函式)。

帶有純虛函式的類是抽象類。抽象類的主要作用是通過它為乙個類族建立乙個公共的介面,使他們能夠更有效的發揮多型特性。**派生類必須給出基類中全部純虛函式的實現,才可以被例項化,否則派生類依舊是抽象類。**抽象類不能被例項化,即不能定義乙個抽象類的物件,但可以定義乙個抽象類的指標和引用。通過指標和引用,就可以指向並訪問派生類的物件,進而訪問派生類的成員,這種訪問是具有多型特徵的。

純虛函式與抽象類**示例:

#include

using

namespace std;

class

base1

;class

base2

:public base1

;void base2::

display()

const

class

derived

:public base2

;void derived::

display()

const

void

fun(base1 *ptr)

intmain()

執行結果:

base2::

display()

derived::

display

()

程式中派生類的虛函式並沒有用關鍵字vitrtual 顯示說明,因為他們與基類的純虛函式具有相同的名稱,引數及返回值型別,由系統自動確定其為虛函式。當然,在派生類的display函式原型宣告中使用virtual也是對的。

C 繼承與多型詳解

一 前言 c 提供了比修改 更好的方法來擴充套件和修改類,這種方法叫做類繼承,它能夠從已有的類中派生出新的類,通過繼承派生出的類通常比設計新類要容易的多,下面是可以通過 繼承完成的一些工作 二 繼承解釋 繼承是類的重要特性。a類繼承b類,我稱b類為 基類 a為 子類 或者 派生類 派生類繼承了基類之...

C 實驗 2 繼承與多型

c 實驗 2 繼承與多型 一 實驗目的和要求 1.學習定義和使用類的繼承關係,定義派生類 2.熟悉不同繼承方式下對基類成員的訪問控制 3.掌握在派生類中初始化基類成員的方法 4.掌握使用虛函式實現動態多樣性。要求 認真除錯程式,認真書寫實驗報告,並對結果作分析。二 實驗內容 1.定義乙個人員類per...

C 的繼承與多型

概念介紹 繼承 為了 的重用,保留基類的原本結構,並新增派生類的部分,同時可能覆蓋 overide 基類的某些成員。多型 一種將不同的特殊行為和單個泛化記號相關聯的能力,分為靜態多型和動態多型。繼承 乙個派生類可以通過繼承獲得基類的所有成員,而無需再次定義它們。分為public protected和...