C 物件之記憶體(無繼承)

2022-07-30 15:30:24 字數 2774 閱讀 6072

大多數情況下,非靜態成員變數在類中的宣告順序就是它們在記憶體中的排列順序。但是成員之間可能會被插入一些位元組,用於調整例項大小、存放某些指標等用途。下面深入看一下各種情況。

概念介紹:access section包括public, private和protected三種段落,如果乙個類的定義中有2個public和1個private,那麼它就有3個access sections。

c++ standard要求,在同乙個access section內,只要較晚出現的成員在類物件中有較高的位址即可。因此成員在記憶體中未必是連續的,中間可能會被填充一些位元組(上面提到的padding);也可能會有編譯器合成的一些內部使用的成員(data member),以支援整個物件模型(比如指向虛函式表或虛擬繼承中指向父類的指標)。

**測試如下:

class point ;

//main函式中:

printf("&point::x = %p\n", &point::x);//00000000

printf("&point::y = %p\n", &point::y);//00000001

printf("&point::z = %p\n", &point::z);//00000002

這裡用的&point::x是表示x在point物件中的相對位置,即偏移量(offset),而&x是表示x的記憶體位址。這裡輸出成員變數的位址也可以,但輸出偏移量會更直觀一些。另外,注意這裡要用printf,不要用cout。cout的輸出都是1,無論位置和變數。

通過**測試發現,x, y, z確實是按照宣告順序在記憶體中排列的。那麼如果還有其他access section呢?

c++ standard允許編譯器將多個access sections中的成員自由排列而不必在乎它們在類中的宣告順序。但目前大部分編譯器都是講乙個以上的access sections連鎖在一起,依照宣告順序成為乙個連續區塊。而且access sections的數量不會帶來額外負擔,在3個public中宣告3個int和在1個public中宣告3個int,得到的物件大小是一樣的。

**測試如下:

class point 

};//main函式中:

printf("&point::x = %p\n", &point::x);//00000000

printf("&point::y = %p\n", &point::y);//00000001

printf("&point::z = %p\n", &point::z);//00000003

point::where_is_a(); //00000002

可見編譯器是按照各個成員的宣告順序將它們排列在了一起。

class test ;
輸出sizeof(test)得到的結果為1。

空類的大小並不是0。這是因為空類也可以被例項化,而且它的每個例項也和其他例項一樣在記憶體中擁有獨一無二的位址。因此編譯器會給空類加乙個位元組,這樣在例項化時就可以給它的例項分配記憶體位址了。

class test  //constructor

test(const test& t) {} //copy constructor

void func()

void func2(); //non-inline function

test& operator =(const test& t){} //operator

~test() {} //destructor

};void test::func2()

class point 

void print_address()

};//main函式中:

point a, b, c;

cout << "a: ";

a.print_address();

cout << "b: ";

b.print_address();

cout << "c: ";

c.print_address();

絕大多數現代c/c++編譯器會將類的大小調整為8位元組的整數倍,這被稱為邊界調整,被填充的位元組叫做padding。之所以要進行邊界調整,是因為cpu在對8位元組或16位元組的資料塊定址時效率更高。可以通過編譯選項禁用邊界調整。但是,通過**測試發現,當類中只有char型別的成員變數時,編譯器並不會進行邊界調整。

**如下:

class test ;

//main函式中:

cout << sizeof(test); //2 = 2*1(char)

輸出為2,說明例項沒有被填充其他位元組。

而當成員變數既有char型別又有其他型別時,就會進行邊界調整了。**測試如下:

class test ;

//main函式中:

cout << sizeof(test); //8 = 4(int) + 1(char) + 3(padding)

輸出為8,說明填充了3位元組。

class test 

};//main函式中:

cout << sizeof(test);

輸出為1。這是因為靜態成員變數只與類有關而與例項無關;c++物件模型中,靜態成員不占用物件的記憶體空間

C 多重繼承之記憶體儲存

c 之多重繼承 1.c 中class與struct。在c 裡面,class與struct沒有本質的區別,只是class的預設許可權是private,而struct則是public。這個概念也揭示了一點 class和struct在內部儲存結構上是一致的。所以我們可以利用這一點來 class的實現原理。...

C 物件模型之記憶體布局

c 虛函式表解析 虛函式按照其宣告順序放於表中 父類的虛函式在子類的虛函式前面 覆蓋的函式被放到了虛表中原來父類虛函式的位置 沒有被覆蓋的函式依舊 每個父類都有自己的虛表 子類的成員函式被放到了第乙個父類的表中 所謂的第乙個父類是按照宣告順序來判斷的 待補充 c 物件模型之記憶體布局 1 c 物件模...

C 物件模型之記憶體布局(2)

多重繼承 繼承關係大於2,至少有父類,子類,孫子類三代關係。使用vs2017檢視物件記憶體布局如下 class c size 20 0 base class b 0 base class a 0 4 a1 8 a2 12 b1 16 c1 c vftable c meta 0 0 c a1 1 a ...