1、C++對象在內存中的布局
在vs2013+win10環(huán)境下,數(shù)據(jù)的對齊為8個字節(jié)。
當某個基類有虛函數(shù)時,這個類生成一個表格,稱為虛表(virtual table,簡稱vtbl)。虛表中存放著一堆指針,這些指針指向該類每一個虛函數(shù)。虛表中的函數(shù)地址將按聲明時的順序排列。每個類對象都擁有一個虛表指針(vptr),由編譯器為其生成。虛表指針的設定與重置皆由類的復制控制(也即是構造函數(shù)、析構函數(shù)、賦值操作符)來完成。vptr的位置為編譯器決定,傳統(tǒng)上它被放在所有顯示聲明的成員之后,不過現(xiàn)在許多編譯器把vptr放在一個類對象的最前端。另外,虛函數(shù)表的前面設置了一個指向type_info的指針,用以支持RTTI(Run Time Type Identification,運行時類型識別)。RTTI是為多態(tài)而生成的信息,包括對象繼承關系,對象本身的描述等,只有具有虛函數(shù)的對象在會生成。對象的數(shù)據(jù)則接著vprt,對齊方式為8個字節(jié)。
當該類為子類時,對象的首地址存放vptr,若子類重寫(overwrite)了父類的虛函數(shù),則子類虛函數(shù)將覆蓋父類虛表中對應的函數(shù);若子類并無overwrite父類虛函數(shù),而是聲明了自己新的虛函數(shù),則該虛函數(shù)地址將擴充到父類虛函數(shù)表最后(在vs中無法通過監(jiān)視看到擴充的結果,不過我們通過取地址的方法可以做到,子類新的虛函數(shù)確實在父類子物體的虛函數(shù)表末端)。接著是基類的數(shù)據(jù),最后是子類的自己定義的數(shù)據(jù)。
取址的方式如下:
cout << "虛函數(shù)表第一個函數(shù)的地址:" << (int *)*((int*)(&p)) << endl;
cout << "析構函數(shù)的地址:" << (int* )*(int *)*((int*)(&p)) << endl;
cout << "虛函數(shù)表中,第二個虛函數(shù)即print()的地址:" << ((int*)*(int*)(&p) + 1) << endl;