C 多型性(續)

2021-09-06 10:04:11 字數 2850 閱讀 5482

多型性可以簡單地概括為「乙個介面,多種方法」,程式在執行時才決定呼叫的函式,它是物件導向程式設計領域的核心概念。c++多型性是通過虛函式來實現的,虛函式允許子類重新定義成員函式,而子類重新定義父類的做法稱為覆蓋(override),或者稱為重寫。(這裡我覺得要補充,重寫的話可以有兩種,直接重寫成員函式和重寫虛函式,只有重寫了虛函式的才能算作是體現了c++多型性)。而過載則是允許有多個同名的函式,而這些函式的引數列表不同,允許引數個數不同,引數型別不同,或者兩者都不同。

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

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

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

#includeusing

namespace

std;

class

a

virtual

void

fun()

};class b : public

a

void

fun()

};int main(void

)

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

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

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

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

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

//

小結:1、有virtual才可能發生多型現象

//2、不發生多型(無virtual)呼叫就按原型別呼叫

#includeusing

namespace

std;

class

base

void g(float

x)

void h(float

x)

};class derived : public

base

void g(int

x)

void h(float

x)

};int main(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++純虛函式

一、定義

virtual void funtion()=0

二、引入原因

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

三、相似概念

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

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

覆蓋(override)

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

不能定義抽象類的物件。

C 多型性(續)

多型性可以簡單地概括為 乙個介面,多種方法 程式在執行時才決定呼叫的函式,它是物件導向程式設計領域的核心概念。c 多型性是通過虛函式來實現的,虛函式允許子類重新定義成員函式,而子類重新定義父類的做法稱為覆蓋 override 或者稱為重寫。這裡我覺得要補充,重寫的話可以有兩種,直接重寫成員函式和重寫...

C 的多型性

c 的多型性 1.多型性的概念 多型性是指用乙個名字定義不同的函式,這函式執行不同但又類似的操作,從而實現 乙個介面,多種方法 多型性的實現與靜態聯編 動態聯編有關。靜態聯編支援的多型性稱為編譯時的多型性,也稱靜態多型性,它是通過函式過載和運算子過載實現的。動態聯編支援的多型性稱為執行時的多型性,也...

有關C 多型性

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