為了實現虛函式,c++ 使用了虛函式表來達到延遲繫結的目的。虛函式表在動態/延遲繫結行為中用於查詢呼叫的函式。
儘管要描述清楚虛函式表的機制會多費點口舌,但其實其本身還是比較簡單的。
首先,每個包含虛函式的類(或者繼承自的類包含了虛函式)都有乙個自己的虛函式表。這個表是乙個在編譯時確定的靜態陣列。虛函式表包含了指向每個虛函式的函式指標以供類物件呼叫。
其次,編譯器還在基類中定義了乙個隱藏指標,我們稱為 *__vptr,*__vptr 是在類例項建立時自動設定的,以指向類的虛函式表。*__vptr 是乙個真正的指標,這和 *this 指標不同,*this 指標實際是乙個函式引數,使編譯器來達到自引用的目的。
結果就是,每個類物件都會多分配乙個指標的大小,並且 *__vptr 是被派生類繼承的。
如果你不清楚這些元件是怎麼配合運作的,看下面的例子:
class base
; virtual void function2() {};};
class d1: public base;};
class d2: public base
;};因為這裡有 3 個類,編譯器會建立 3 個虛函式表。
然後編譯器會在使用了虛函式的最上層基類中定義乙個隱藏指標。儘管這個過www.cppcns.com程編譯器會自動處理,但我們還是通過下面的例子來說明指標新增的位置:
class base
; virtual void function2() {};};
class d1: public base;};
class d2: public base
;};*__vptr 在類物件建立的時候會設定成指向類的虛函式表。例如,型別 base 被例項化的時候,*__vptr 就指向 base 的虛函式表。型別 d1 或者 d2 被例項化的時候,*__vptr 就指向 d1 或者 d2 的虛函式表。
現在我們來看下虛函式表是怎麼建立的。因為示例中每個類僅有 2 個虛函式,所以每個虛函式表會存放兩個函式指標(分別指向 function1() 和 function2())。
base 物件的虛函式表最簡單。base 物件只能訪問 base 型別的成員,不能訪問 d1 或者 d2 的函式。所以 base 的虛函式表中的兩個指標分別指向 base::function1() 和 base::function2()。
d1 的虛函式表稍複雜點,d1 物件能夠訪問 d1 以及 base 的成員。d1 重寫了 function1(),但沒有重寫 function2(),所以 d1 的虛函式表中的兩個指標分別指向 d1::function1() 和 base::function2()。
d2 的虛函式表同理 程式設計客棧d1,包含了分別指向 base::function1() 和 d2::function2() 的指標。
考慮如果建立 d1 物件時會發生什麼:
int main()
因為 d1 是 d1 型別物件,d1 有它自己的 *__vptr 指向 d1 型別的虛函式表。
現在建立乙個 base 型別指標 *dptr 指向 d1:
int main()
重點:因為 dptr 是 base 型別指標,它只指向 d1 物件的 base 型別部分(即,指向 d1 物件中的 base 子物件),而 *__vptr 也在 base 型別部分。所以 dptr 可以訪問 base 型別部分中的 *__vptr。同時,這裡注意,dptr->__vptr 指向的是 d1 的虛函式表,這是在 d1 初始化時就確定的。所以結果,儘管 dptr 程式設計客棧是 base 型別指標,但它能夠訪問 d1 的虛函式表。
因此,當有呼叫 dptr->function1() 時,發生了什麼?
int main()
首先,程式識別到 function1() 是乙個虛函式。
其次,程式使用 dptr->__vptr 獲取到了 d1 的虛函式表。
然後,它在 d1 的虛函式表中尋找可以呼叫的 function1() 版本,這裡是 d1::function1()。
因此,dptr->function1() 實際呼叫了 d1::function1()。
通過虛函式表,編譯器和程式能夠確定呼叫什麼版本的虛函式,儘管使用的是指向/引用基類的指標或者引用。
呼叫虛函式會比呼叫非虛函式更慢,有以下幾個原因:
結果就是必須進行三次操作才能完成對函式的呼叫。但是對於現代計算機系統,這些額外操作www.cppcns.com增加的時間幾乎可以忽略不計。
另外,每個使用虛函式表的類都有 *__vptr 指標,從而每個類物件都會多乙個指標的空間。虛函式很強大,但是它確實產生了效能開銷。
C 虛函式表及虛函式執行原理詳解
為了實現虛函式,c 使用了虛函式表來達到延遲繫結的目的。虛函式表在動態 延遲繫結行為中用於查詢呼叫的函式。儘管要描述清楚虛函式表的機制會多費點口舌,但其實其本身還是比較簡單的。首先,每個包含虛函式的類 或者繼承自的類包含了虛函式 都有乙個自己的虛函式表。這個表是乙個在編譯時確定的靜態陣列。虛函式表包...
c 中的虛函式及虛函式表
有關鍵字virtual修飾的成員函式,為了實現多型。1.虛函式表用來存放虛函式的位址,也稱虛表。2.乙個含有虛函式的類中至少有乙個虛表。3.虛表指標 二級指標,虛函式指標的指標,存放在物件模型頭部,32位系統中佔4個位元組,在64位系統中佔8個位元組。虛表指標中存放著虛表的首位址。可以通過物件例項化...
虛函式及虛函式表
虛函式及虛函式表 首先,我們要分清三大概念 過載 重寫 覆蓋 和重定義 一.函式過載 1 在相同的作用域內 無繼承關係,只在乙個類內進行宣告 2 進行多個函式宣告 3 多個函式的函式名相同,引數列表不同 可以是型別不同 引數型別不同 傳參順序不同 4 函式的返回值型別可以相同,可以不同。不能僅依靠函...