含有虛函數的struct(class)內存對齊和空間大小的計算(win32)

考慮這樣一個類b,依次包含一個虛指針、char、類a、int、double數組

struct a {
    char c;//1+7
    double d;//8
};//16

struct b {
    char c;
    a s;
    int i;
    double d[3];
    virtual ~b() {}
};

 按照道理來講,虛指針vptr佔用4字節,然後char c 佔用1個字節,再補3個字節,使得a類的開始偏移量是a類最大成員double d的整數倍,然後a s佔用16字節,int i佔用4個字節,再補4個字節,使得double d[3]開始的位置是8的整數倍,最會double d[3]佔用24個字節,最終就是4+(1+3)+16+(4+4)+(8*3)=56個字節,但是實際上是64個字節。

爲什麼呢?打開類b的一個對象的內存分配看看:

int main() {
    b test;
    test.c = ' ';
    test.i = 1;
    test.s.c = ' ';
    test.s.d = 4;
    test.d[0] = (test.d)[1] = (test.d)[2] = 2;
    b *T= &test;
    cout << sizeof b << endl;
}

可以看到,虛函數指針後面補了4個字節,使得char c不得不補7個字節而不是3個字節, 以使得s的起始偏移量是8的倍數,所以多出來的8個字節在這裏。

初步得出結論:虛表指針不跟其它成員對齊一起計算,其它成員的第一個起始位置應該是成員中體積最大的成員的整數倍,此例中b中最大的成員是double,其包含的類a中最大的成員也是double,所以第一個成員char c的起始位置應該是4+4=8。

那麼,如果刪掉成員s或者數組double d[3]呢?

struct a {
    char c;//1+7
    double d;//8
};//16

struct b {
    char c;
   // a s;
    int i;
    double d[3];
    virtual ~b() {}
};
int main() {
    b test;
    test.c = ' ';
    test.i = 1;
    //test.s.c = ' ';
    //test.s.d = 4;
    test.d[0] = (test.d)[1] = (test.d)[2] = 2;
    b *T= &test;
    cout << sizeof b << endl;
}

註釋掉a類的成員,輸出40,內存分佈如下:

虛函數指針依舊補了4個字節。註釋掉double d[3],輸出40,內存分佈如下:

 

同樣地,虛函數指針補了4個字節 ,同時最後補了4個字節以成爲8的倍數。如果把兩個8字節的都註釋掉,即類b是這樣:

struct b {
    char c;
    int i;
    virtual ~b() {}
};
int main() {
    b test;
    test.c = ' ';
    test.i = 1;
    b *T= &test;
    cout << sizeof b << endl;
}

輸出就是喜聞樂見的12了。

說明初步的結論是正確的。也說明,當存在虛函數的時候,虛函數跟其它成員分開對齊,可以把其它成員當做一個類,這樣就轉換成爲類中包含類的對齊問題了。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章