結構體大小
首先看一下代碼案例,該運行環境爲Linux下的64位操作系統。代碼 test.c 如下:
/*******************
Author : lijd
data : 2019-07-11
********************/
#include <stdio.h>
struct A{
int a;
char b;
short c;
}T_A;
struct B{
char b;
int a;
short c;
}T_B;
struct C{
char b;
short c;
int a;
}T_C;
struct D{
short d;
char b;
short c;
int a;
}T_D;
struct E{
char b;
struct A t_d;
short c;
int a;
}T_E;
struct F{
char b;
int A_a;
char A_b;
short A_c;
short c;
int a;
}T_F;
int main()
{
printf("sizeof(int) = %d, sizeof(char) = %d, sizeof(short) = %d\n", sizeof(int), sizeof(char), sizeof(short));
printf("sizeof(T_A) = %d, sizeof(T_B) = %d, sizeof(T_C) = %d, sizeof(T_D) = %d\n", sizeof(T_A), sizeof(T_B), sizeof(T_C), sizeof(T_D));
printf("sizeof(T_E) = %d, sizeof(T_F) = %d\n", sizeof(T_E), sizeof(T_F));
return 0;
}
運行結果截圖如下:
結論:由於編譯器給結構體分配大小時,分配的大小一定是該結構體內最大系統支持類型成員(該例爲int類型)的整數倍。採用字節對齊方式計算分配大小。如內嵌結構體依舊採用解析(將內置結構體解析爲系統支持的類型結構)的方法去計算。
類大小
由於類的大小涉及到虛指針的大小,虛指針有牽扯類的繼承方式,因此以下從不含繼承的單類、單一繼承,多重繼承三個方向分析。
不含繼承的單類:
看一下代碼案例,該運行環境爲Linux下的64位操作系統。代碼如下:
/*******************
Author : lijd
data : 2019-07-11
********************/
#include<iostream>
using namespace std;
// 空類(實際包含構造、析構函數等)
class A
{
};
class A_1
{
int a;
char b;
short c;
};
class A_2
{
int a;
char b;
short c;
static int d;
};
class A_3
{
char b;
int a;
short c;
};
int main()
{
cout << "sizeof(A) : " << sizeof(A) << endl;
cout << "sizeof(A_1) : " << sizeof(A_1) << endl;
cout << "sizeof(A_2) : " << sizeof(A_2) << endl;
cout << "sizeof(A_3) : " << sizeof(A_3) << endl;
return 0;
}
運行結果如下:
空類即什麼都沒有的類,照理說大小應該是0,但是空類的大小爲1,因爲空類可以實例化,實例化必然在內存中佔有一個位置,因此,編譯器爲其優化爲一個字節大小。
由以上運行結果分析:不含繼承的單類大小跟成員函數、靜態成員變量無關,跟普通成員變量有關,關係類似於上述的結構體大小計算。
含虛函數的單一繼承:
看一下代碼案例,該運行環境爲Linux下的64位操作系統。代碼如下:
/*******************
Author : lijd
data : 2019-07-11
********************/
#include<iostream>
using namespace std;
class B
{
virtual void Fun();
char a;
};
class B_1: public B
{
int a;
void Fun();
virtual void Fun1();
};
int main()
{
cout << "sizeof(B) : " << sizeof(B) << endl;
cout << "sizeof(B_1) : " << sizeof(B_1) << endl;
return 0;
}
運行結果如下:
由於基類B中包含一個char類型的私有變量和一個虛函數,此時B類的內存佈局如下:
派生類B_1繼承了基類B,它有自己的int類型的成員變量且重寫了基類B中的虛函數Fun(),還定義了自己的虛函數。此時B_1類的內存佈局如下:
含虛函數的多重繼承:
看一下代碼案例,該運行環境爲Linux下的64位操作系統。代碼如下:
/*******************
Author : lijd
data : 2019-07-11
********************/
#include<iostream>
using namespace std;
class C
{
virtual void Fun();
virtual void Fun1();
char a;
};
class D
{
virtual void Fun();
virtual void Fun2();
int b;
};
class C_D : public C, public D
{
void Fun();
virtual void Fun3();
double c;
};
int main()
{
cout << "sizeof(C) : " << sizeof(C) << endl;
cout << "sizeof(D) : " << sizeof(D) << endl;
cout << "sizeof(C_D) : " << sizeof(C_D) << endl;
return 0;
}
運行結果如下:
由於基類C和基類D大小跟上面所述的含虛函數的單一繼承類中的基類結構相同,因此不再贅述。派生類C_D繼承了基類C和基類D,此時C_D類的內存佈局如下:
C_D類自己的虛函數表指針與其聲明繼承順序的第一個基類C的虛函數表指針合併,此外,若C_D類重寫了基類中同名的虛函數,則在對應虛函數表的對應位置都應該予以修改。C_D中新添加的虛函數位於第一個虛函數表項最後面,C_D中新添加的成員變量位於類的最後面,按其聲明順序與內存對齊原則進行排列。
總結:
與類大小有關的因素:普通成員變量,虛函數,繼承(單一繼承,多重繼承)
與類大小無關的因素:靜態成員變量,成員函數