1. 程式人生 > >【C++】使用sizeof計算類物件所佔空間大小-sizeof總結

【C++】使用sizeof計算類物件所佔空間大小-sizeof總結

 決定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++程式設計師面試祕笈》