【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++有一條規則表明空基類不需要用單獨的字節表示。因此編譯器可以在空基類的情況下自由優化。

<本文完> 

參考資料:

1)https://www.geeksforgeeks.org

2)https://www.cprogramming.com

3)《C和C++程序員面試秘笈》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM