C 多型詳解

2021-06-19 00:37:05 字數 3949 閱讀 4249

c++

程式語言是一款應用廣泛,支援多種程式設計的計算機程式語言。下面詳細介紹其中c++多型性的一些基本知識,以方便大家在學習過程中對此能夠有乙個充分的掌握。

多型性可以簡單地概括為「乙個介面,多種方法」,程式在執行時才決定呼叫的函式,它是物件導向程式設計領域的核心概念。多型(polymorphisn),字面意思多種形狀。

c++多型性是通過虛函式來實現的,虛函式允許子類重新定義成員函式,而子類重新定義父類的做法稱為覆蓋(override),或者稱為重寫。(這裡我覺得要補充,重寫的話可以有兩種,直接重寫成員函式和重寫虛函式,只有重寫了虛函式的才能算作是體現了c++

多型性)而過載則是允許有多個同名的函式,而這些函式的引數列表不同,允許引數個數不同,引數型別不同,或者兩者都不同。編譯器會根據這些函式的不同列表,將同名的函式的名稱做修飾,從而生成一些不同名稱的預處理函式,來實現同名函式呼叫時的過載問題。但這並沒有體現多型性。(

注意:過載是在同一作用域內使用)

多型與非多型的實質區別就是函式位址是早繫結還是晚繫結。如果函式的呼叫,在編譯器編譯期間就可以確定函式的呼叫位址,並生產**,是靜態的,就是說位址是早繫結的。而如果函式呼叫的位址不能在編譯器期間確定,需要在執行時才確定,這就屬於晚繫結。

那麼多型的作用是什麼呢,封裝可以使得**模組化,繼承可以擴充套件已存在的**,他們的目的都是為了**重用。而多型的目的則是為了介面重用。也就是說,不論傳遞過來的究竟是那個類的物件,函式都能夠通過同乙個介面呼叫到適應各自物件的實現方法。

最常見的用法就是宣告基類的指標,利用該指標指向任意乙個子類物件,呼叫相應的虛函式,可以根據指向的子類的不同而實現不同的方法。如果沒有使用虛函式的話,即沒有利用c++多型性,則利用基類指標呼叫相應的函式的時候,將總被限制在基類函式本身,而無法呼叫到子類中被重寫過的函式。因為沒有多型性,函式呼叫的位址將是一定的,而固定的位址將始終呼叫到同乙個函式,這就無法實現乙個介面,多種方法的目的了。

筆試題目:

#include

usingnamespacestd;  

classa  

virtualvoidfun()  

};  

classb :publica  

voidfun()  

};  

intmain(void)    

第乙個p->foo()和p->fuu()都很好理解,本身是基類指標,指向的又是基類物件,呼叫的都是基類本身的函式,因此輸出結果就是1、2。

第二個輸出結果就是1、4。p->foo()和p->fuu()則是基類指標指向子類物件,正式體現多型的用法,p->foo()由於指標是個基類指標,指向是乙個固定偏移量的函式,因此此時指向的就只能是基類的foo()函式的**了,因此輸出的結果還是1。而p->fun()指標是基類指標,指向的fun是乙個虛函式,由於每個虛函式都有乙個虛函式列表,此時p呼叫fun()並不是直接呼叫函式,而是通過虛函式列表找到相應的函式的位址,因此根據指向的物件不同,函式位址也將不同,這裡將找到對應的子類的fun()函式的位址,因此輸出的結果也會是子類的結果4。

筆試的題目中還有乙個另類測試方法。即

b *ptr= (b *)&a;  ptr->foo();  ptr->fun();

問這兩呼叫的輸出結果。這是乙個用子類的指標去指向乙個強制轉換為子類位址的基類物件。結果,這兩句呼叫的輸出結果是3,2。

並不是很理解這種用法,從原理上來解釋,由於b是子類指標,雖然被賦予了基類物件位址,但是ptr->foo()在呼叫的時候,由於位址偏移量固定,偏移量是子類物件的偏移量,於是即使在指向了乙個基類物件的情況下,還是呼叫到了子類的函式,雖然可能從始到終都沒有子類物件的例項化出現。

而ptr->fun()的呼叫,可能還是因為c++多型性的原因,由於指向的是乙個基類物件,通過虛函式列表的引用,找到了基類中fun()函式的位址,因此呼叫了基類的函式。由此可見多型性的強大,可以適應各種變化,不論指標是基類的還是子類的,都能找到正確的實現方法。 //

小結:1

、有virtual

才可能發生多型現象

// 2

、不發生多型(無

virtual

)呼叫就按原型別呼叫

#include

usingnamespacestd;  

classbase  

voidg(floatx)  

voidh(floatx)  

};  

classderived :publicbase  

voidg(intx)  

voidh(floatx)  

};  

intmain(void)    

令人迷惑的隱藏規則

本來僅僅區別過載與覆蓋並不算困難,但是

c++的隱藏規則使問題複雜性陡然增加。

這裡「隱藏」是指派生類的函式遮蔽了與其同名的基類函式

,規則如下:(1

)如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無

virtual

關鍵字,基類的函式將被隱藏(注意別與過載混淆)。(2

)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有

virtual

關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)。

上面的程式中:(1

)函式derived::f(float)

覆蓋了base::f(float)。(

2)函式

derived::g(int)

隱藏了base::g(float)

,而不是過載。(3

)函式derived::h(float)

隱藏了base::h(float)

,而不是覆蓋。

附加概念:c++

純虛函式

一、定義

純虛函式是在基類中宣告的虛函式,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法。在基類中實現純虛函式的方法是在函式原型後加「=0」

virtual void funtion()=0

二、引入原因

1、為了方便使用多型特性,我們常常需要在基類中定義虛函式。

2、在很多情況下,基類本身生成物件是不合情理的。例如,動物作為乙個基類可以派生出老虎、孔雀等子類,但動物本身生成物件明顯不合常理。

為了解決上述問題,引入了純虛函式的概念,將函式定義為純虛函式(方法:virtual returntype function()= 0;),則編譯器要求在派生類中必須予以重寫以實現多型性。同時含有純虛函式的類稱為抽象類,它不能生成物件。這樣就很好地解決了上述兩個問題。

三、相似概念

1、多型性

指相同物件收到不同訊息或不同物件收到相同訊息時產生不同的實現動作。c++支援兩種多型性:編譯時多型性,執行時多型性。

a

、編譯時多型性:通過過載函式實現 

b、執行時多型性:通過虛函式實現。

2、虛函式

虛函式是在基類中被宣告為virtual,並在派生類中重新定義的成員函式,可實現成員函式的動態覆蓋(override)

3、抽象類

包含純虛函式的類稱為抽象類。由於抽象類包含了沒有定義的純虛函式,所以

不能定義抽象類的物件

C 多型詳解

多型是物件導向的程式設計的關鍵技術。多型 呼叫同乙個函式名,可以根據需要但實現不同的功能。多型體現在兩個方面,我們以前學過的編譯時的多型性 函式過載 和現在我們這一章將要學習的執行時的多型性 虛函式 執行時多型 執行時的多型性是指在程式執行之前,根據函式名和引數無法確定應該呼叫哪乙個函式,必須在程式...

C 多型詳解

前幾天在網上看到這樣的乙個問題 多型現在一般的用法,就是拿乙個父類的指標去呼叫子類中被重寫的方法。但我搞不懂為什麼要那麼做,我們直接在子類中寫乙個同名的成員函式,從而隱藏父類的函式不就行了麼?然後有人這樣回答 將父模擬喻為電腦的外設介面,子模擬喻為外設,現在我有行動硬碟 u盤以及 它們3個都是可以作...

C 多型詳解

前幾天在網上看到這樣的乙個問題 多型現在一般的用法,就是拿乙個父類的指標去呼叫子類中被重寫的方法。但我搞不懂為什麼要那麼做,我們直接在子類中寫乙個同名的成員函式,從而隱藏父類的函式不就行了麼?然後有人這樣回答 將父模擬喻為電腦的外設介面,子模擬喻為外設,現在我有行動硬碟 u盤以及 它們3個都是可以作...