程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++中類的內存空間大小(sizeof)分析,空間大小sizeof

C++中類的內存空間大小(sizeof)分析,空間大小sizeof

編輯:C++入門知識

C++中類的內存空間大小(sizeof)分析,空間大小sizeof


首先明確各數據類型占多大的空間。例如int到底是占2字節還是4字節空間:

在TC裡,int是2字節的(主要是因為TC是16位的,所以int類型也該是16位的)
VC++裡,int是4字節的,因為現代操作系統下的軟件大多是是32位。
64位的VC++,本來按理說,該是8字節的,但是可能為了維持32位的源代碼移植到64位盡量不出錯,所以也維持了4字節的長度。
至於其他有名的編譯器,如gcc,我還沒用過,你得查一查它所規定int的長度

或者利用sizeof(int)也可以計算出來。本人電腦上計算如下:

在C語言中存在關於結構體的存儲空間大小是比較深入的話題,其中涉及計算機的基本原理、操作系統等。我認為對齊是C語言中讓很多初學者都拿不准摸不透的問題,特別是在跨平台的情況下,對齊這種問題更加的復雜多變,每一種系統都有自己獨特的對齊方式,在Windows中經常是以結構體重最大內置類型的存儲單元的字節數作為對齊的基准,而在Linux中,所有的對齊都是以4個字節對齊。

    那麼在C++中的類的內存空間大小又有哪些特殊的問題呢?

    首先,我認為對齊肯定也是其中的問題之一,對齊主要是為了加快讀取的速度。

    關於對齊這個我認為基本上已經是操作系統內定好的,既然Linux與Windows存在差別,那麼在C++的類中,關於對齊肯定也會存在一定的差別。關於對齊我認為只要記住平時使用的系統的對齊准則就可以了,即:在Windows中經常是以結構體重最大內置類型的存儲單元的字節數作為對齊的基准,而在Linux中,所有的對齊都是以4個字節對齊。

    其次,我認為就應該討論在基類中哪些成員占有存儲空間,那些成員不占用內存空間?

    在C++中占存儲區間的主要是非static的數據對象,主要包括各種內置的數據類型,類對象等,類中的函數聲明以及函數定義都不算內存空間。但是需要注意所有的virtual函數(虛函數)共享一段內存區域,一般來說是4個字節。為什麼只是包含非static數據對象呢?因為static數據並不屬於類的任何一個對象,它是類的屬性,而不是具體某一個對象的屬性,在整個內存區域中只有一個內存區域存儲對應的static數據,也就是所有的類對象共享這個數據,所以不能算做具體某一個對象或者類型的內存空間。

因此可以認為基類對象的存儲空間大小為:

    非static數據成員的大小 + 4 個字節(虛函數的存儲空間)

    當然這個大小不是所有數據成員大小的疊加,而是存在一個對齊問題,具體的應該參考相關的對齊文章。

    最後,我認為肯定要關心一下派生類的存儲空間了?

    在C++中,繼承類是一個比較有用的類,繼承使得各種類在基類的基礎上擴展,這時候派生類中包含了基類的信息,一般而言,在基類中存在虛函數時,派生類中繼承了基類的虛函數,因此派生類中已經繼承了派生類的虛函數。因此繼承類中不能再添加虛函數的存儲空間(因為所有的虛函數共享一塊內存區域),而僅僅需要考慮派生類中心添加進來的非static數據成員的內存空間大小。

因此可以認為派生類對象的存儲空間大小為:

    基類存儲空間 + 派生類特有的非static數據成員的存儲空間

   還有一類是比較特殊的情況,如果是虛繼承的情況下,這時的存儲空間大小就會發生變化。

    基類的存儲空間 + 派生類特有的非static數據成員的存儲空間 + 每一個類的虛函數存儲空間。

    下面我采用一些例子說明上面的問題:

#include <iostream>
using namespace std;
class test
{
public:
        test();
private:
        int a;
        char c;
};
int main()
{
    cout << sizeof(test) << endl;
    //system("pause");//按Ctrl+F5
    return 0;
}

上面的代碼在linux以及windows下都會輸出8,而不是輸出5,這個是在C語言中已經討論過的話題,但是說明對齊在C++中也是要考慮的。關於操作系統的差異在後面用一個統一的例子說明。

    虛函數問題

    為了討論虛函數,我們在test類中添加一個虛析構函數,然後再測試結果。 

class test
{
public:
        test();
        virtual ~test();
private:
        int a;
        char c;
};

這段代碼與前面的代碼沒有什麼區別,只是添加了一個虛函數,然後編譯調試,這時候輸出的結果12,也就是說增加了一個虛函數以後,類的數據成員增加了4個字節,那麼是否是每一個虛函數都占有4個字節呢?其實是不會的,在test中加入一個新的虛函數virtual void get_a_c(),這時在輸出的結果還是12,這說明所有的虛函數共享4個字節。

    static數據

    我們知道static數據是非對象的屬性,而是類的屬性,他不能算是某一個對象或者類型的存儲空間,在類定義中只能聲明,初始化只能在類外執行,當然有例外的。這也不做分析了。具體參看後面的大例子。

    派生類的存儲空間

    派生類從基類中繼承了很多成員,自己也會增加很多的成員,由於虛函數也會被繼承下來,所以就是在派生類中不顯式定義虛函數,在派生類中也會存在從基類繼承下來的虛函數,因此虛函數不需要額外計算內存空間,而只需要增加基類的非static成員數據大小。定義如下面所示,該函數會輸出20,剛好是添加的非static數據double d的存儲空間大小。證明了上面的分析。

#include <iostream>
using namespace std;
class test
{
public:
        test();
        virtual ~test();
        virtual void get_a_c();
private:
        int a;
        char c;
};
class derived_test:public test
{
public:
    virtual ~derived_test();
private:
    double d ; 
};
int main()
{
    cout << sizeof(derived_test) << endl;
    return 0;
}

測試虛繼承的類的大小:

#include <iostream>
using namespace std;
class A
{
    char i[3];
public:
    virtual void a(){};
};
class B : public virtual A
{
    char j[3];
public:
    virtual void b(){}
};
class C: public virtual B
{
    char k[3];
public:
    virtual void c(){}
};
int main()
{
    cout << "sizeof(A): " << sizeof(A) << endl;
    cout << "sizeof(B): " << sizeof(B) << endl;
    cout << "sizeof(C): " << sizeof(C) << endl;
    return 0;
}

輸出結果為:

如果是虛繼承的情況下,這時的存儲空間大小就會發生變化。

    基類的存儲空間 + 派生類特有的非static數據成員的存儲空間 + 每一個類的虛函數存儲空間。

另外,如果A類改成如下形式:

class A
{
    char i[5];
public:
    virtual void a(){};
};

所占空間:12。因為

class A
{
    char i[9];
public:
    virtual void a(){};
};

所占空間:16。因為

class A
{
    char i[3];
    char t;
public:
    virtual void a(){};
};

所占空間:8。因為

class A
{
    char i[3];
    char t;
    char t1;
public:
    virtual void a(){};
};
所占空間:12。因為

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved