一、內存字節對齊
參考
寫出一個class,然後sizeof,sizeof的結果往往都比你聲明的變量總長度要大,這是因爲字節對齊。顯然對齊更浪費了空間。那麼爲什麼要使用對齊呢?對齊和不對齊,是在時間和空間上的一個權衡。對齊節省了時間。
1. 數據成員對齊規則:類中的數據成員,第一個數據成員放在offset爲0的地方,以後每個數據成員存儲的起始位置要從該成員大小或者成員的子成員大小(比如說是數組)的整數倍開始
2. 類作爲成員:如果一個類中裏有其他類成員,則其他類成員要從其內部最大元素大小的整數倍地址開始存儲.(class A裏存有class B,B裏有char,int ,double等元素,那B應該從8的整數倍開始存儲.)
3. 收尾工作:結構體的總大小,也就是sizeof的結果,.必須是其內部最大成員的整數倍.不足的要補齊.
class A
{
int i;//0.3
short s[5];//4.14
char c;//15.16 規則3
};
class B
{
char c0;//0.7
double d[3];//8.32 規則1
char c;//33.40 規則3
};
二、一個空類的sizeof的大小
class Test{
};
sizeof(Test)的結果是1.
因爲一個空類也要實例化,所謂類的實例化就是在內存中分配一塊地址,每個實例在內存中都有獨一無二的地址。同樣空類也會被實例化,所以編譯器會給空類隱含的添加一個字節,這樣空類實例化之後就有了獨一無二的地址了。所以空類的sizeof爲1。
三、不含成員變量,僅含構造函數和析構函數類的大小
class Test2{
Test2(){
}
~Test2(){
}
};
sizeof(Test2)的結果是1.
因爲普通成員函數與sizeof無關。
四、不含成員變量,含虛析構函數
class Test3{
//long long i;
Test3(){
}
virtual ~Test3(){
}
};
sizeof(Test3)的結果是4.
因爲虛函數放在虛表中,類中定義了虛函數,需要存放一個指向虛表的指針。指針佔4個字節
五、測試
#include<iostream>
using namespace std;
class A
{
public:
int a;
private:
char b;
};
class B
{
public:
static int a;
private:
char b;
};
class C
{
public:
int a;
virtual void f(){}
};
class D
{
public:
int a;
virtual void f(){}
virtual void f2(){}
virtual void f3(){}
};
//普通繼承
class E
{
public:
int a;
private:
char b;
};
class F : public E
{
public:
int d;
char c;
};
class G
{
public:
int a;
private:
char b;
};
class H : public G
{
public:
char c;
int d;
};
//普通繼承含虛函數的父類
class Test
{
public:
char a;
virtual void get(){}
};
class Test2 : public Test
{
public:
int a;
};
//含虛函數的子類普通繼承含虛函數的父類
class Test3
{
public:
int a;
virtual void get(){}
};
class Test4: public Test3
{
public:
int a;
virtual void set(){}
};
//子類虛繼承父類
class Test5
{
public:
int a;
};
class Test6 : virtual public Test5
{
public:
int b;
};
//子類和父類中都含虛函數的虛繼承
//使用虛繼承,子類和父類的虛函數存放在不同的虛表中,因此子類和父類都需要一個指向虛表的指針。
class Test7
{
public:
int a;
virtual void get(){}
};
class Test8 : virtual Test7
{
public:
int a;
virtual void set(){}
};
//多重繼承
class Test9
{
public:
int a;
};
class Test10 : public Test9
{
public:
int b;
};
class Test11 : public Test9
{
public:
int c;
};
class Test12 : public Test10, public Test11
{
public:
int d;
};
//多重虛繼承,由於是虛繼承,虛基類數據成員a只需要保留一份。
class Test13
{
public:
int a;
};
class Test14 : virtual public Test13
{
public:
int b;
};
class Test15 : virtual public Test13
{
public:
int c;
};
class Test16 : public Test14, public Test15
{
public:
int d;
};
int main()
{
cout << sizeof(A) << endl;//8
cout << sizeof(B) << endl;//1
cout << sizeof(C) << endl;//8
cout << sizeof(D) << endl;//8
cout << sizeof(E) << endl;//8
cout << sizeof(F) << endl;//16
cout << sizeof(G) << endl;//8
cout << sizeof(H) << endl;//16
cout << sizeof(Test) << endl;//8
cout << sizeof(Test2) << endl;//12
cout << sizeof(Test3) << endl;//8
cout << sizeof(Test4) << endl;//12
cout << sizeof(Test5) << endl;//4
cout << sizeof(Test6) << endl;//12
cout << sizeof(Test7) << endl;//8
cout << sizeof(Test8) << endl;//20
cout << sizeof(Test9) << endl;//4
cout << sizeof(Test10) << endl;//8
cout << sizeof(Test11) << endl;//8
cout << sizeof(Test12) << endl;//20
cout << sizeof(Test13) << endl;//4
cout << sizeof(Test14) << endl;//12
cout << sizeof(Test15) << endl;//12
cout << sizeof(Test16) << endl;//24
system("PAUSE");
}
六、普通繼承總結
- 類的大小爲類的非靜態成員數據的類型大小之和,也就是說靜態成員數據不作考慮。
- 普通成員函數與sizeof無關。
- 虛函數由於要維護在虛函數表,所以要佔據一個指針大小,也就是4字節。
- 類的總大小也遵守類似class字節對齊的,調整規則。
七、虛繼承
class Parent
{
protected:
int x;
public:
Parent(){ }
virtual ~Parent(){}
};
class Child:virtual public Parent
{
protected:
int y;
public:
Child() :Top(){}
};
sizeof(Parent)的結果爲8,sizeof(Child)的結果爲16
因爲虛繼承,虛繼承的子類都要包含一個指向基類的指針