淺談虛擬函式表與位元組對齊

weixin_34402408發表於2016-06-06

一、虛擬函式的工作原理

虛擬函式的實現要求物件攜帶額外的資訊,這些資訊用於在執行時確定該物件應該呼叫哪一個虛擬函式。典型情況下,這一資訊具有一種被稱為

vptr(virtual table pointer,虛擬函式表指標)的指標的形式。vptr 指向一個被稱為 vtbl(virtual

table,虛擬函式表)的函式指標陣列,每一個包含虛擬函式的類都關聯到

vtbl。當一個物件呼叫了虛擬函式,實際的被呼叫函式通過下面的步驟確定:找到物件的

vptr 指向的 vtbl,然後在 vtbl 中尋找合適的函式指標。

虛擬函式的地址翻譯取決於物件的記憶體地址,而不取決於資料型別(編譯器對函式呼叫的合法性檢查取決於資料型別)。如果類定義了虛擬函式,該類及其派生類就要

生成一張虛擬函式表,即vtable。而在類的物件地址空間中儲存一個該虛表的入口,佔4個位元組,這個入口地址是在構造物件時由編譯器寫入的。所以,由於

物件的記憶體空間包含了虛表入口,編譯器能夠由這個入口找到恰當的虛擬函式,這個函式的地址不再由資料型別決定了。故對於一個父類的物件指標,呼叫虛擬函式,

如果給他賦父類物件的指標,那麼他就呼叫父類中的函式,如果給他賦子類物件的指標,他就呼叫子類中的函式(取決於物件的記憶體地址)。


二、(虛)繼承類的記憶體佔用大小

首先,平時所宣告的類只是一種型別定義,它本身是沒有大小可言的。 因此,如果用sizeof運算子對一個型別名操作,那得到的是具有該型別實體的大小。

計算一個類物件的大小時的規律:

1、空類、單一繼承的空類、多重繼承的空類所佔空間大小為:1(位元組,下同);

2、一個類中,虛擬函式本身、成員函式(包括靜態與非靜態)和靜態資料成員都是不佔用類物件的儲存空間的;

3、因此一個物件的大小≥所有非靜態成員大小的總和;

4、當類中宣告瞭虛擬函式(不管是1個還是多個),那麼在例項化物件時,編譯器會自動在物件裡安插一個指標vPtr指向虛擬函式表VTable;

5、虛承繼的情況:由於涉及到虛擬函式表和虛基表,會同時增加一個(多重虛繼承下對應多個)vfPtr指標指向虛擬函式表vfTable和一個vbPtr指標指向虛基表vbTable,這兩者所佔的空間大小為:8(或8乘以多繼承時父類的個數);

6、在考慮以上內容所佔空間的大小時,還要注意編譯器下的“補齊”padding的影響,即編譯器會插入多餘的位元組補齊;

7、類物件的大小=各非靜態資料成員(包括父類的非靜態資料成員但都不包括所有的成員函式)的總和+ vfptr指標(多繼承下可能不止一個)+vbptr指標(多繼承下可能不止一個)+編譯器額外增加的位元組。


三,位元組對齊


寫出一個含有資料成員的類,然後sizeof  ,sizeof的結果總要比資料成員的總長度大,這就是因為位元組對齊。

我們知道在一個沒有虛擬函式的類中,其物件大小就是其資料成員的長度,當我們sizeof這個類的物件的時候,其值往往比我們悽婉的要大,比如,我們有一個類擁有一個int 和一個char型別的資料成員

class{

int no;

char key;

}

然後sizeof這個類的物件,我們會發現結果是8而不是我們想的5.這就是因為位元組對齊。對齊和不對齊,是在時間和空間上的一個權衡。為了提高效率,計算機從記憶體中取資料是按照一個固定長度的。以32位機為例,它每次取32個位,也就是4個位元組(每位元組8個位,計算機基礎知識,別說不知道)。位元組對齊有什麼好處?以int型資料為例,如果它在記憶體中存放的位置按4位元組對齊,也就是說1個int的資料全部落在計算機一次取數的區間內,那麼只需要取一次就可以了。這樣效率就得到了提高。




推薦文章:http://www.tuicool.com/articles/Jrq6bai (物件記憶體佈局)

C語言記憶體位元組對齊小結 - andy572633的專欄 - 部落格頻道 - CSDN.NET (c語言記憶體位元組對齊)

相關文章