虛指標 虛表及記憶體布局

2021-10-07 21:07:43 字數 1805 閱讀 8321

首先要清楚,所謂指標其實質就是乙個記憶體位址值,形如0x12345678;

其次,要知道,函式名本身就是乙個位址;

虛指標:其實就是乙個位址值,以該位址為起始位址的一片記憶體單元存放著各虛函式的入口位址,這一片記憶體單元合起來就稱為虛函式表(想象一下:一片記憶體單元存著許多函式位址,想執行哪個虛函式就來這片記憶體單元查詢該虛函式的入口位址,就像查表一樣,故稱虛函式表)。經過以上解釋,可以發現,所謂虛指標,就是個指向指標的指標。

我們在程式一般可以通過兩種方式生成乙個變數(注意這裡的變數是廣義的變數):一種是通過型別來生成(如 int a;derived d);一種是通過new來申請記憶體並生成(如 base * p = new derived())。要知道的是,兩種方式生成的變數在記憶體中是存放在不同的地方的:前一種方式生成的變數是存放在棧(stack)中的,而後一種方式生成的變數是存放在堆(heap)中的。棧是向下生長的(向位址減小的方向生長),也就是說晚生成的變數所在的位址比早生成的變數的位址要小(舉例:int a;derived d;因d生成時間晚於a,故 &a > &d);堆則相反,是向上生長的。稍後會在第三部分結合**來理解。

有了以上的基礎,結合**來加深理解虛函式的相關概念就比較深刻了。(只有理解了才能一輩子都忘不掉)

先看第部分(紅色部分):生成乙個派生類物件並初始化之。從**中可以看到,基類中除了三個虛函式之外別無他物,而繼承了基類之後,派生類除了父類的三個虛函式外,又宣告了兩個整型變數。因此,乙個派生類物件的大小應該應該由兩部分組成,一部分用來儲存虛函式的相關資訊,另一部分儲存整型變數。而子類儲存虛函式相關資訊的方式正式藉由虛指標來實現,因此不難理解,乙個派生類物件大小應該為:4 + 4*2 = 12;顯然第乙個4為虛指標的大小,第二個4為乙個整型變數的大小(注:32位機上記憶體單元的位址用4個位元組表示,類似的,64位機上位址為8位元組),也就得到乙個派生類物件的大小為12位元組這一結論。這點從執行結果中得以佐證(紅色矩形選中部分)。

再看第部分(綠色部分):不難發現:&d、&(d.a)、&(d.b)這三者依次差了四個位元組,記憶體布局如下圖所示:

我們知道虛指標的本質就是乙個位址值而已,在這個例子中就是0x00339b6c,在上圖已經標明,對照仔細看即可。

第三部分(藍色部分):在第二部分中我們已經得到了虛指標的值,而在前文已經分析過:虛指標其實就是指向指標的的指標,那麼很容易理解:對虛指標取其內容得到的便是另乙個指標,這個新的指標便是第乙個虛函式的入口位址,在這個例子中也就是函式base::f的入口位址,也就是0x003313b1。而對虛指標加一之後再取內容也就得到了base::g的入口位址,也就是0x003312da(為什麼是加一呢?因為我們知道乙個位址佔4個位元組,而虛指標正是整形指標,加一操作相當於步進4個位元組)。同理,虛指標加二並取內容也就得到了base::h的入口位址,也就是0x00331262。至此,我們得到了三個虛函式的入口位址,那麼得到的位址是否正確?顯然接下來需要驗證。

虛表 虛指標

虛函式在c 中的實現機制就是用虛表和虛指標,但是具體是怎樣的呢?從more effecive c 其中一篇文章裡面可以知道 是每個類用了乙個虛表,每個類的物件用了乙個虛指標。具體的用法如下 cpp view plain copy class a class b public a a,b的實現省略 因...

虛函式,虛表,虛表指標

分享一篇文章,詳細解釋了為什麼通過基類指標指向基類物件或派生類物件,就可以呼叫相應類的虛函式。自 一 概述 為了實現c 的多型,c 使用了一種動態繫結的技術。這個技術的核心是虛函式表 下文簡稱虛表 本文介紹虛函式表是如何實現動態繫結的。二 類的虛表 每個包含了虛函式的類都包含乙個虛表。我們知道,當乙...

虛繼承 虛表 虛指標

c 實現多型的方法 其實很多人都知道,虛函式在c 中的實現機制就是用虛表和虛指標,但是具體是怎樣的呢?從more effecive c 其中一篇文章裡面可以知道 是每個類用了乙個虛表,每個類的物件用了乙個虛指標。具體的用法如下 class a class b public a a,b的實現省略 因為...