三 虛函式表vtable
動態聯編過程跟我們猜測的大致相同。編譯器在執行過程中遇到virtual關鍵字的時候,將自動安裝動態聯編需要的機制,首先為這些包含virtual函式的類(注意不是類的例項)--即使是祖先類包含虛函式而本身沒有--建立一張虛函式表vtable。在這些虛函式表中,編譯器將依次按照函式宣告次序放置類的特定虛函式的位址。同時在每個帶有虛函式的類中放置乙個稱之為vpointer的指標,簡稱vptr,這個指標指向這個類的vtable。
關於虛函式表,有幾點必須宣告清楚:
1. 每乙個類別只能有乙個虛函式表,如果該類沒有虛函式,則不存在虛函式表。
2. c++編譯時候編譯器會在含有虛函式的類中加上乙個指向虛函式表的指標vptr。
3. 從乙個類別誕生的每乙個物件,將獲取該類別中的vptr指標,這個指標同樣指向類的vtable。
因此類、物件、vtable的層次結構可以用下圖表示。其中x類和y類的物件的指標 都指向了x,y的虛函式表,同時x,y類自身也包含了指向虛函式的指標。
為了方便問題說明,我們將2.cpp例子進行擴充套件,擴充套件程式如下。
15. #include 16. class shape在程式編譯期間,由於oneshape為shape型別的,因此它將檢查shape的虛函式表,發現vtable[0]為draw函式的位址,於是翻譯成p->vtable[0]。未來執行期間,p 實際上指向的是circle物件,因此真正呼叫的為circle->vtable[0]處的函式,即circle::draw。同樣對於adjust函式,c++ 編譯器也會去檢查shape的vtable,結果編譯器無法找到adjust函式,因此編譯無法通過。 對於circleshape,因為它是circleshape型別的,因此它將會檢查circle的vtable,得知vtable[2]處為adjust的位址,因此編譯器翻譯成call circleshape->vtable[2],真正執行時候circleshape為circle型別,因此它將繫結circle的vtable[2]處的函式即circle:: adjust()。 就這樣,編譯器借助虛函式表實現了動態聯編的過程,從而使多型的實現有了可能。因此說虛函式表是多型性的幕後功臣一點也不為過。
五 結束語
多型性的實現是乙個非常複雜的過程,上面的討論僅僅是針對簡單繼承而言,即基類只有乙個的情況,對於多重繼承,情況又會有所改變。本文僅是拋磚引玉,希望有興趣的朋友可以一起**。
解析動態聯編 上
文章摘要 多型性是c 最主要的特徵,多型性的實現得益於c 中的動態聯編技術。文章通過對動態聯編的關鍵技術虛函式表進行深入的剖析,解析的動態聯編的過程極其技術要領。關鍵字 多型性 動態聯編 vtable 虛函式 文章正文 一 從多型性談動態聯編的必要性 在 進入主題之前先介紹一下聯編的概念。聯編就是將...
解析動態聯編 轉貼
日期 2005 4 15 字型 大 中 小 文章摘要 多型性是c 最主要的特徵,多型性的實現得益於c 中的動態聯編技術。文章通過對動態聯編的關鍵技術虛函式表進行深入的剖析,解析的動態聯編的過程極其技術要領。關鍵字 多型性 動態聯編 vtable 虛函式 文章正文 一 從多型性談動態聯編的必要性 在進...
智慧型合約安全系列文章反彙編 下篇
上篇我們詳細分析了智慧型合約反彙編後的 內容,包括多個反彙編指令的含義,資料在棧中的儲存方式,並通過上下文關聯關係梳理 邏輯。本篇我們將繼續分析上篇遺留的反彙編 通過上篇學習我們已對反彙編指令在棧和記憶體儲存的有了一定了解,該篇我們將重點來分析反彙編指令表示的 邏輯。合約源 pragma solid...