C 多型的實現原理分析

2021-08-26 05:14:07 字數 1740 閱讀 7083

在物件導向開發中,多型是乙個很重要的特性。

什麼是多型呢?就是程式執行時,父類指標可以根據具體指向的子類物件,來執行不同的函式,表現為多型。

看完上面的實現原理,你可能會覺得有點懵,接下來我們就一點點分析和驗證上面的結論。

#include using namespace std;

class parent};

class child : public parent};

int main()

如上例**所示,當我們傳入父類物件時,將呼叫和執行父類的函式,當我們傳入子類物件時,將呼叫和執行子類的函式。而 c++ 編譯器的執行過程其實是這樣的:

父類的 fun() 是個虛函式,所以編譯器給父類物件自動新增了乙個 vptr 指標,指向父類的虛函式表,這個虛函式表裡存放了父類的 fun() 函式的函式指標

子類的 fun() 函式是重寫了父類的,即寫不寫 virtual 編譯器都會為其自動新增乙個 virtual,然後編譯器給子類物件自動新增了乙個 vptr 指標,指向子類的虛函式表,這個虛函式表裡存放了子類的 fun() 函式的函式指標

執行 p->fun() 時,編譯器檢測到 fun() 是乙個虛函式,所以不會靜態的將 parent 類的 fun() 方法直接編譯過來,而是是執行的時候,動態的根據 base 指向的物件,找到這個物件的 vptr 指標,然後找到這個物件的虛函式表,最後呼叫虛函式表裡對應的函式,實現多型

上面說了這麼多,那麼怎麼證明說的都是對的呢?vptr 指標真的存在麼?

其實要證明 vptr 的存在很簡單,我們只需要建立兩個相同的類,乙個類有虛函式,乙個類沒有虛函式,然後通過 sizeof() 方法列印出類物件的大小就行。如下:

#include using namespace std;

class parent1

// 非虛函式

};class parent2

// 虛函式

};int main()

執行結果:

4

8

可以看到,存在虛函式的類的物件,大小大了4個位元組,這正好是乙個指標物件的大小(指標物件的大小可能會根據執行環境而改變,32位的系統指標的大小是4個位元組),這說明編譯器確實給我們新增了這麼乙個指標物件 vptr。

看下面這個例子:

#include using namespace std;

class parent

virtual void fun()

};class child : public parent

void fun()

};void main()

執行程式會發現,建立子類物件時,會先建立父類物件,而父類的構造方法中呼叫虛函式,執行的並不是子類的 fun() 函式,而是父類自己的 fun() 函式,並沒有發生多型。

即答案是:父類的構造方法中呼叫虛函式,不會發生多型。這個和 vptr 的分步初始化有關。

從上例中我們看到,在父類中呼叫虛函式時,執行的還是父類的函式,沒有發生多型。這是因為當建立子類物件時,編譯器的執行順序其實是這樣的:

物件在建立時,由編譯器對 vptr 進行初始化

子類的構造會先呼叫父類的建構函式,這個時候 vptr 會先指向父類的虛函式表

子類構造的時候,vptr 會再指向子類的虛函式表

物件的建立完成後,vptr 最終的指向才確定 ​

C 多型實現原理分析

前言 虛函式執行速度要稍慢一些。為了實現多型性,每乙個派生類中均要儲存相應虛函式的入口位址表,函式的呼叫機制也是間接實現。所以多型性總是要付出一定代價,但通用性是乙個更高的目標。實驗環境 windows10 企業版 visual studio2017 15.8.1 引入虛函式後記憶體大小變 化 沒有...

C 基礎 多型的實現原理分析

多型的實現原理分析 virtual fun ptr 虛函式表指標 乙個類裡面不管有幾個虛函式,只有乙個虛函式表,只需將其加入表中即可,而指向這個表的指標只有乙個,即虛函式表指標 根據賦值相容規則,父類通過指標和引用子類物件後,只能訪問父類的方法,那為什麼將父類的函式寫為虛函式,子類重寫後,父類卻可以...

C 多型的實現原理

1.用virtual關鍵字申明的函式叫做虛函式,虛函式肯定是類的成員函式。2.存在虛函式的類都有乙個一維的虛函式表叫做虛表。類的物件有乙個指向虛表開始的虛指標。虛表是和類對應的,虛表指標是和物件對應的。3.多型性是乙個介面多種實現,是物件導向的核心。分為類的多型性和函式的多型性。4.多型用虛函式來實...