多型與虛函式(虛表)

2021-08-10 23:03:48 字數 3669 閱讀 2771

前面我們已經說過繼承,今天我們來說說多型,多型是什麼呢?我們可以從以下幾個方面來看多型。

1、什麼是多型?

2、多型的分類?

3、動態多型實現的條件?

4、多型實現原理?

現在我們就要進入正文了!

1、什麼是多型?

多型:同一事物,在不同場景下可表現出不同的形態。

例如:1.'*' 的多種意思

a*b;//此時 '*'就是乘號的意思

int* p=&a;

*p=2;//此時 '*' 就是解引用的意思

2.廁所

如果男生來了就是男廁所,女生來了就是女廁所

3.其實多型我們也可以這樣理解:

見人說人話,見鬼說鬼話

2.多型的分類

靜態多型:發生在程式編譯期間,編譯器會根據函式實參的型別(可能會進行隱式的型別轉換)可推斷出要呼叫那個函式,如果有對應的函式就呼叫該函式,如果沒有就出現編譯錯誤
函式過載:

執行環境:vs2013,win10

#include

#include

using

namespace

std;

int add(int left, int right)

float add(float left, float right)

int main()

為什麼函式過載在編譯期間可以確定應該呼叫哪個函式?

答:因為在編譯期間,編譯器會進行引數型別的推斷

執行結果:

動態多型:在程式執行期間(非編譯期),編譯期間只會編譯程式,然後在執行期間才會決定呼叫那個函式.(在編譯期間,就只是進行單純的編譯,比如:定義的是基類,編譯的時候只會按表面定義的進行編譯,只有在執行期間才會根據傳參的不同,而選擇應該呼叫那個函式)
3、動態多型實現的條件

動態多型實現的條件共有兩個

1.基類中必須有虛函式,在派生類中必須要對基類中的虛函式進行重寫;

2.通過基類的指標或引用來呼叫虛函式(派生類一定要重寫基類的虛函式)

為什麼?

把函式定義為虛函式,是為了實現多型呼叫,虛函式呼叫時會查詢虛表

1.為什麼建構函式不能作為虛函式?

建構函式是建立物件的,如果建構函式是虛函式,呼叫建構函式時就需要查詢虛表,可是物件還沒構造完成,根本就不能查詢虛表

2.為什麼靜態成員函式不能作為虛函式?

不是類的成員函式,沒有this指標

3.建議:做好不要將賦值操作符過載定義為虛函式,為什麼?

不能把派生類物件賦值完整,會讓**不安全,邏輯混亂(因為可能會讓基類物件給子類物件賦值,不符合賦值相容規則)

賦值相容規則規定:子類物件可以給父類物件賦值,可是基類物件不能給子類物件賦值

4.為什麼友元函式不能定義為虛函式?

不是類的成員函式,沒有this指標

5.為什麼最好將基類中的析構函式作為虛函式?

如果不定義為虛函式,可能會使派生類中的資源清空不了。

6.為什麼不要在建構函式和析構函式裡調虛函式?

建構函式:

物件不完整,可能會出現未定義的行為(虛表是通過物件調的,有些物件沒有建立,使用此物件,可能會使程式崩潰)

析構函式:

物件不完整,已銷毀,再呼叫虛函式時,可能會查不到虛表(因為需要通過物件查詢虛表)

4、動態多型實現的原理

虛函式

1.必須是類的成員函式;

2.使用關鍵字virtual修飾;

注:某一函式在基類中定義為虛函式,在派生類中重寫時,可以不加關鍵字virtual,此時此函式也是虛函式,但是盡量加上關鍵字 virtual。

純虛函式

在類的成員函式(必須是虛函式)的形參列表後面寫上=0;則此函式就是純虛函式。

例如:class base

抽象類

包含純虛函式的類就是抽象類(也叫介面類),抽象類不能例項化物件,純虛函式在派生類中重新定義後,派生類才能例項化物件

抽象類可建立指標

抽象類的純虛函式在派生類中如果沒有被定義,則此派生類也是抽象類

因為:抽象類定義不完整。抽象類它只是乙個介面,不是乙個真正的類,只有在派生類中給出功能之後,才可以例項化物件,就比如說乙個廁所,它是乙個模糊的概念,但是如果乙個男生去廁所那它就是男廁所,這樣它就有它自己的功能了。

虛表解析

以下是乙個虛表

單繼承

基類虛表:虛函式是按照在類中的宣告順序排列的

派生類虛表:

1.先將基類虛表中的內容拷貝乙份(內容一樣,位址不一樣)

2.如果派生類對基類中的虛函式進行重寫,使用派生類的虛函式替換相同偏移量位置的基類虛函式

3.派生類中新增加的虛函式,按照其在派生類的宣告順序,將其放在上述的虛函式之後(即和基類共用乙份虛表,而且派生類中的虛函式儲存在基類虛表中基類的虛函式之後)

多繼承

如果派生類的多個基類中均有虛函式,將派生類自己新增加的虛函式放在第乙個「基類虛表」之後(其中細節的實現跟單繼承一樣,就是說基類的虛表和派生類在基類虛表中儲存虛函式的實現與單繼承一樣)

第乙個虛表:按繼承先後順序的第乙個,

例如:class d:public c1,public c2//此時c1就是第乙個基類

c1和c2是派生類的基類

菱形繼承

菱形虛擬繼承派生類的虛表:

1.用來覆蓋基類的虛函式;

2.放派生類新增加的虛函式(如果有虛函式,就會新增虛表,否則不會)

同乙個類的多個物件共用乙份虛表

乙個類只會維護乙個虛表

多型的缺點

降低效率

例如:調某函式時,普通函式是直接呼叫

虛函式---

->查詢虛表的位址,然後再查詢虛函式的位址,這樣會增加程式呼叫時間,降低效率。

C 虛函式 純虛函式 多型與虛表機制詳解

在類的定義中,前面有virtual關鍵字的成員函式就是虛函式。注 派生類中的成員函式 與 基類中虛函式同名且同引數的函式,不加virtual也自動成為虛函式。沒有函式體的虛函式稱作純虛函式,包含純虛函式的類叫抽象類。注 class a int main 多型的實現是通過虛函式。多型的作用是增強程式的...

虛函式與多型

前三者為靜態繫結,虛函式為動態繫結 動態繫結 只有通過基類指標或引用呼叫虛函式才能引發動態繫結 虛函式不能被宣告為靜態 include using namespace std class base virtual void fun2 void fun3 class derived public ba...

虛函式與多型

多型性 呼叫同乙個函式名,可以根據需要實現不同的功能。虛函式 可以在程式執行時通過呼叫相同的函式名而實現不同功能的函式稱為虛函式。編譯時的多型性 函式過載 執行時的多型性 虛函式 執行時的多型性是指在程式執行之前,根據函式名和引數無法確定應該呼叫哪乙個函式,必須在程式的執行過程中,根據具體的執 況來...