請大神看我對虛函數表和虛基類表的理解對不對?
01-27
《深入理解c++對象模型》一書中已經介紹了實現的一些細節問題,但是介紹的比較多,冗餘不高,而且也說了有些只是對功能要求,而對實現細節不要求。
下面列出我其中幾個關鍵概念的理解,不知道對不對,請大神們指正:(其實是因為直接提問大神們覺得太沒誠意都懶得答~)關鍵的概念有:類(與函數綁定),對象(與自己的數據綁定),虛函數,虛基類的數據,虛函數表,虛基類表,this 指針。
【 this 指針 】 相當於所有非 static 函數,都有個隱含的 class class_name * this 的參數。【 虛函數繼承 】
1. 普通函數:編譯時已經確定的固定地址,直接調用。2. 虛擬函數: 1)存在一個「虛函數表」里,通過虛函數指針+偏移,間接調用。 2)某個基類對應的「虛函數表」一個類(基類,各個派生類)各有一個實例。3)每個對象(基類對象,派生類對象)中,有一個「虛函數表指針」,在派生類中這個基類的數據布局是編譯時靜態確定的,所以不用額外數據來記錄基類位置。
4)在子-&>父的指針轉換,其實相當於調用了一個"函數"而不僅僅是賦值,因為編譯時已經知道了對應關係,所以直接+-相應的指針偏移就可以得到其基類的對象。 5)基類其實主要規定了一個對象數據的內存布局,和虛表的結構。 6)如果需要動態類型轉換,因為虛表(和這個表中的函數)是和具體的類(基類或派生類)綁定的,而且是在編譯時已經確定了的。假設有個虛函數能夠返回這個類的信息(type-id 等),那麼就能夠利用這個信息來進行動態轉換(實際可能不是虛函數,可能只是一個指針指向一些固定的信息,邏輯相同)。即:dynamic_cast -&> 引用對象虛表項(包含 type-id 的信息) -&> 表項和類是綁定的,且編譯時已確定 -&> 基類只是規定了布局,而每個具體的對象引用的實例不一樣,每個實例有不同的內容所以可以確定其動態類型。【 虛基類 】A 是虛基類; B,C 虛擬繼承 A; D 繼承 B,C。
1. 虛基類指針存在的必要性是因為:A在B/C的相對位置是不固定的,因為在D中A只有1份實例,至少B/C中有一個相對布局要破壞。2. 但是在每個具體的類中,其虛基類的布局是確定的,也就是說是和類綁定的,而不同的對象的虛基類數據內存布局可能不一樣。每個類中要有信息記錄這個相對位置。3. 在多態時一個對象不一定是哪種類的實例,所以不能在編譯期確定其虛基類布局,必須有一個指針(或變數)來記錄這個相對偏移。可以通過在每個對象中加入一個「虛基類指針」來記錄位置,或把這個信息放入「虛函數表」中來記錄這個位置。(這也是為什麼G++中只有虛函數,類空間+1個指針長,只有虛基類+1個指針長,都有還是只+1個指針長度)上面是我的理解,但是一些資料里又沒直接寫出來的一些理解。不敢確定理解的對不對,希望大牛們指正~
我覺得關於虛函數表的問題,只需要了解一下VC++編譯32位程序的時候,那個(並不是所有情況都會有這麼大)16個位元組的類成員函數指針都是個什麼布局,就精通了。
當年我是用的vczh的方法:各種情況你都寫一個例子, 然後去看彙編(如果是vc, 那直接看對應的彙編單步就好了).然後啥都理解了.
看書不如動手.
OpenRCE看看這篇文章,vs編譯器下c++內存布局
推薦閱讀:
※C++ 有哪些經常用到的設計模式?
※如何用C實現C++類裡面的成員?
※socket拋出Cant assign requested address,問題所在以及解決方法?
※C++序列化json字元串對Unicode有哪些特殊處理?
※今天面試C++,機試面試官看完代碼說代碼結構混亂?