【C++】使用sizeof計算類物件所佔空間大小-sizeof總結
阿新 • • 發佈:2018-12-12
決定C ++中物件的大小的因素:
1.所有非靜態資料成員的大小 |
2.資料成員的順序 |
3.位元組對齊或位元組填充 |
4.其直接基類的大小虛擬函式的存在 |
5. 正在使用的編譯器 |
6.繼承模式(虛擬繼承) |
一、使用sizeof計算類物件所佔空間大小
需要注意,對類做sizeof運算時,並不是簡單地把各個成員所佔的記憶體數量相加。需要注意成員順序不同,可能需要位元組補齊。
程式設計例項:
#include <iostream> using namespace std; class A { public: int i; //int佔用4個位元組 }; class B { public: char ch; //char佔用1個位元組 }; class C { public: int i; short j;//short佔用2個位元組 }; class D //D共佔用8個位元組 { public: int i; //int佔用4個位元組 short j; //short和char共佔用3個位元組,由於這裡最寬的 char ch; //基本型別是int的4個位元組,再填充一個位元組湊成4的倍數 }; class E //E共佔用8個位元組 { public: int i; int ii; //兩個int共佔用8個位元組 short j; //1個short + 2個char = 4個位元組,剛好是最寬 char ch; //基本型別int的大小的整數倍,不需要再填充位元組 char chr; }; int main() { cout << "sizeof(A) = " << sizeof(A) << endl; //4 cout << "sizeof(B) = " << sizeof(B) << endl; //1 cout << "sizeof(C) = " << sizeof(C) << endl; //8 cout << "sizeof(D) = " << sizeof(D) << endl; //8 cout << "sizeof(E) = " << sizeof(E) << endl; //12 getchar(); return 0; }
小結:
1.類中的資料成員順序不同,類所佔的記憶體大小可能不同; |
2.注意需要 位元組對齊或位元組填充 的情況; |
3.派生類的記憶體大小需要加上基類的記憶體大小。 |
拓展知識:關於位元組對其你和位元組填充
程式設計例項:
class C {
char c;
int int1;
int int2;
int i;
long l;
short s;
};
分析:
這個類的大小是24位元組。儘管char c只消耗1個位元組,但將為它分配4個位元組,剩下的3個位元組將被浪費(留空)。這是因為下一個成員是int,它佔用4個位元組。如果我們不進入下一個(4)位元組來儲存這個整數成員,那麼這個整數的記憶體訪問/修改週期將是2個讀週期。所以編譯器會為我們做這個補位。
圖解:
二、使用sizeof計算含有虛擬函式的類物件的空間大小
虛擬函式的存在將在類中新增4個位元組的虛擬表指標,這將被新增到類的大小。 同樣,在這種情況下,如果類的基類已經直接或通過其基類具有虛擬函式,那麼這個額外的虛擬函式將不會新增任何類的大小。 虛擬表指標在類層次結構中是通用的。
程式設計例項:
#include <iostream> using namespace std; class Base //Base佔用的記憶體大小為4,即1個int { public: Base(int x) :a(x) { } void print() //函式不佔用記憶體 { cout << "base" << endl; } private: int a; }; class Derived :public Base //Derived的記憶體大小=Base的大小+Derived中的一個int, { //即4 + 4 = 8 public: Derived(int x) :Base(x - 1), b(x) { } void print() { cout << "derived" << endl; } private: int b; }; class A //A共佔用8個位元組 { public: A(int x) :a(x) { } virtual void print() //虛擬函式產生一個隱含的虛表指標成員,佔4個位元組 { cout << "A" << endl; } private: int a; //佔4個位元組 }; class B :public A //b所佔記憶體 = A所佔記憶體 + 4 { public: B(int x) :A(x - 1), b(x) { } virtual void print() { cout << "B" << endl; } private: int b; //佔4個位元組 }; int main() { Base obj1(1); cout << "size of Base obj is " << sizeof(obj1) << endl; //4 Derived obj2(2); cout << "size of Derived obj is " << sizeof(obj2) << endl; //8 A a(1); cout << "size of A obj is " << sizeof(a) << endl; //8 B b(2); cout << "size of B obj is " << sizeof(b) << endl; //12 getchar(); return 0; }
小結:
1. 普通函式不佔用記憶體; |
2.只要有虛擬函式就會佔用一個指標大小的記憶體,原因是系統多用一個這鎮維護這個類的虛擬函式表。 |
三、使用sizeof計算虛擬繼承的類物件的空間大小
要點:在C++中,有時由於某些原因,我們不得不使用虛擬繼承。當我們使用虛擬繼承時,在該類中,虛擬基類指標將會有4個位元組的開銷。
程式設計例項:
#include <iostream>
using namespace std;
class A //空類的大小不為零,一般來說它是1個位元組,
{ //確保兩個不同的物件具有不同的地址是非零的
};
class B //1個位元組
{
};
class C :public A, public B { //1個位元組
};
class D :virtual public A { //虛擬函式的存在將在類中新增4個位元組
//的virtual table pointer
};
class E :virtual public A, virtual public B { //虛繼承A有4個位元組+
//虛繼承B有4個位元組
};
class F
{
public:
int a; //佔4個位元組
static int b; //靜態成員的空間不在類的例項中,
//而是像全域性變數一樣在靜態儲存區
};
int F::b = 10; //在類外初始化靜態成員
int main()
{
cout << "sizeof(A) = " << sizeof(A) << endl; //1
cout << "sizeof(B) = " << sizeof(B) << endl; //1
cout << "sizeof(C) = " << sizeof(C) << endl; //1
cout << "sizeof(D) = " << sizeof(D) << endl; //4
cout << "sizeof(E) = " << sizeof(E) << endl; //8
cout << "sizeof(F) = " << sizeof(F) << endl; //4
getchar();
return 0;
}
知識擴充套件:為什麼C ++中空類的大小不為零?
例如:
#include<iostream>
using namespace std;
class Empty {};
int main()
{
cout << sizeof(Empty);
return 0;
}
輸出結果:
1 |
分析:
空類的大小不為零。一般是1個位元組。確保兩個不同的物件具有不同的地址是非零的。
例如:
#include<iostream>
using namespace std;
class Empty { };
int main()
{
Empty a, b;
if (&a == &b)
cout << "a 和 b的地址相同 " << endl;
else
cout << "a 和 b的地址不同 " << endl;
return 0;
}
輸出結果:
a 和 b的地址不同 |
還有另外一種情況,你可能會感到奇怪:
#include<iostream>
using namespace std;
class Empty { };
class Derived: Empty { int a; };
int main()
{
cout << sizeof(Derived);
return 0;
}
輸出:
4 |
為什麼是4,而不是5?
原因是C++有一條規則表明空基類不需要用單獨的位元組表示。因此編譯器可以在空基類的情況下自由優化。
<本文完>
參考資料:
3)《C和C++程式設計師面試祕笈》