首先需要明確的是,對(duì)象模型不屬于C++標(biāo)準(zhǔn)的一部分帽撑,如何實(shí)現(xiàn)由編譯器廠商決定现诀,不過(guò)目前主流廠商的編譯器實(shí)現(xiàn)的都類(lèi)似夷磕,有一些場(chǎng)景使用了經(jīng)過(guò)裁剪的C++,和這兒談?wù)摰膶?duì)象模型可能完全不同仔沿。編譯器的內(nèi)存對(duì)齊對(duì)于談?wù)搶?duì)象模型來(lái)說(shuō)沒(méi)有幫助坐桩,因此禁用。不考慮虛繼承封锉,多繼承绵跷,多級(jí)繼承的情況。
測(cè)試平臺(tái)為VS2015成福,GCC4.8.4
//對(duì)于VS碾局,使用#pragma pack(1)禁用編譯器對(duì)齊
//對(duì)于GCC,使用__attribute__((__packed__))禁用編譯器對(duì)齊
class Fruit
{
int no;
double weight;
char key;
public:
void print() { }
virtual void process(){ }
}__attribute__((__packed__);
class Apple: public Fruit{
int size;
char type;
public:
void save() { }
virtual void process(){ }
}__attribute__((__packed__));
int main()
{
Fruit f;
Apple a;
cout << sizeof(f) << endl;
cout << sizeof(a) <<endl;
return 0;
}
x86(-m32)模式下:
-
VS的結(jié)果
- sizeof(f) = 17
- sizeof(a) = 22
-
內(nèi)存圖
- int + char + double = 13闷叉,再加上一個(gè)32位的虛指針擦俐,正好17
-
GCC
- sizeof(f) = 17
- sizeof(a) = 22
-
內(nèi)存圖
- 和VS的結(jié)果是一樣的
內(nèi)存符號(hào)的名字暗示了函數(shù)繼承的時(shí)候繼承的只是所有權(quán),函數(shù)體只有一份(Fruit::process, Apple::process)
另一件事就是虛表顯然是被類(lèi)所有的握侧,也可以說(shuō)是static的,不會(huì)占用實(shí)例的內(nèi)存空間
x64(-m64)模式下:
-
VS的結(jié)果
- sizeof(f) = 21
- sizeof(a) = 26
-
GCC
- sizeof(f) = 21
- sizeof(a) = 26
算一下嘿期,差異正好是一個(gè)32位指針品擎,所以布局一致,只是指針大了一倍
vtable倒是說(shuō)明了一件事备徐,C++的動(dòng)態(tài)綁定(Dynamic binding/Late Binding)和大家想要的還不完全是一個(gè)東西萄传,本質(zhì)上還是靜態(tài)綁定,畢竟編譯期已經(jīng)把一切偏移量都寫(xiě)死了,只是具有了多態(tài)特性秀菱,基類(lèi)指針指向不同派生類(lèi)實(shí)例的時(shí)候可以通過(guò)虛函數(shù)表跳到不同的函數(shù)入口點(diǎn)振诬。和大家想要的拿著名字去找函數(shù)的運(yùn)行時(shí)綁定還是有很大區(qū)別的