類的各種成員函式在類中是如何分配的?

2021-06-27 13:45:23 字數 3341 閱讀 4499

個類,有成員變數:靜態與非靜態之分;而成員函式有三種:靜態的、非靜態的、虛的。

那麼這些個東西在記憶體中到底是如何分配的呢?

以乙個例子來說明:

[html]view plain

copy

print?

#include"iostream.h"  

class cobject  

;  void cobject::fun()  

cobject::cobject()  

cobject::~cobject()  

int cobject::a=1

;  void main()  

這是我的一段測試**, 

執行結果是: 

sizeof(cobject):8 

cobject::a=1 

construct! 

sizeof(myobject):8 

sizeof(int)4 

destruct! 

我有疑問如下: 

(1)c++

中,應該是物件才會被分配記憶體空間吧??為什麼cobject記憶體大小是8,剛好和兩個成員變數的大小之和一致!難道還沒例項化的時候,類就 已經有了記憶體空間了? 

(2)當物件生成了之後,算出的記憶體大小怎麼還是8,函式難道不占用記憶體空間嗎?至少應該放個函式指標在裡面的吧?記憶體是怎樣布局的?

(3)靜態成員應該是屬於類的,怎麼類的大小中沒有包含靜態成員的大小?

下面分別解答如下:

1)sizeof(cobject)是在編譯時就計算了的,乙個類定義了,它所佔的記憶體編譯器就已經知道了,這時只是得到它占用的大小,並沒有分配記憶體操作 。也可以這樣想:編譯器肯定知道大小了,這與分配記憶體空間無關,知道大小了,以後例項化了才能知道要分配多大。

2)類的普通成員、靜態成員函式是不佔類記憶體的,至於你說的函式指標在你的類中有虛函式的時候存在乙個虛函式表指標,也就是說如果你的類裡有虛函式則 sizeof(cobject)的值會增加4個位元組。

其實類的成員函式 實際上與 普通的全域性函式一樣。 

只不過編譯器在編譯的時候,會在成員函式上加乙個引數,傳入這個物件的指標。

成員函式位址是全域性已知的,物件的記憶體空間裡根本無須儲存成員函式位址。 

對成員函式(非虛函式)的呼叫在編譯時就確定了。 

像 myobject.fun() 這樣的呼叫會被編譯成形如 _cobject_fun( &myobject ) 的樣子。

函式是不算到sizeof中的,因為函式是**,被各個物件共用,跟資料處理方式不同。物件中不必有函式指標,因為物件沒必要知道它的各個函式的位址(調 用函式的是其他**而不是該物件)。 

類的屬性是指類的資料成員,他們是例項化乙個物件時就為資料成員分配記憶體了,而且每個物件的資料成員是對立的,而成員函式是共有的~ 

靜態成員函式與一般成員函式的唯一區別就是沒有this指標,因此不能訪問非靜態資料成員。總之,程式中的所有函式都是位於**區的。

3)靜態成員並不屬於某個物件,sizeof取的是物件大小。

知道了上面的時候,就可以改一下來看看:

我也補充一些: 

class cobject 

; 這個類用sizeof()測出來的大小是 2*sizeof(double)=16 

class cobject 

; 大小是2*sizeof(int)=8 

class cobject 

; sizeof(char)+sizeof(int)

其實這裡還有乙個是記憶體對齊的問題。

空類大小是1。 

另外要注意的一些問題:

先看乙個空的類佔多少空間?

class base

; class base ;

注意到我這裡顯示宣告了構造跟析構,但是sizeof(base)的結果是1.

因為乙個空類也要例項化,所謂類的例項化就是在記憶體中分配一塊位址,每個例項在記憶體中都有獨一無二的位址。同樣空類也會被例項化,所以編譯器會給空類隱含 的新增乙個位元組,這樣空類例項化之後就有了獨一無二的位址了。所以空類的sizeof為1。

而析構函式,跟建構函式這些成員函式,是跟sizeof無關的,也不難理解因為我們的sizeof是針對例項,而普通成員函式,是針對類體的,乙個類的成 員函式,多個例項也共用相同的函式指標,所以自然不能歸為例項的大小,這在我的另一篇博文有提到。

接著看下面一段**

[html]view plain

copy

print?

class base   

private:   

int  a;                  //佔4位元組   

char *p;                 //4位元組指標   

};   

class derive:public base   

;         

~derive(){};   

private:   

static int st;         //非例項獨佔   

int  d;                     //佔4位元組   

char *p;                    //4位元組指標   

};   

int main()     

class base private: int a; //佔4位元組 char *p; //4位元組指標 }; class derive:public base ; ~derive(){}; private: static int st; //非例項獨佔 int d; //佔4位元組 char *p; //4位元組指標 }; int main() ; 

~derive(){}; 

private: 

static

int st; 

int  d; 

char *p; 

char c; 

}; 

class derive:public base ; ~derive(){}; private: static int st; int d; char *p; char c; };

這個時候,結果就變成了

1224

乙個char c;增加了4位元組,說明類的大小也遵守類似class位元組對齊,的補齊規則。

具體的可以看我那篇《5分鐘搞定位元組對齊》

至此,我們可以歸納以下幾個原則:

1.類的大小為類的非靜態成員資料的型別大小之和,也 就是說靜態成員資料不作考慮。

2.普通成員函式與sizeof無關。

3.虛函式由於要維護在虛函式表,所以要佔據乙個指標大小,也就是4位元組。

4.類的總大小也遵守類似class位元組對齊的,調整規則。

在非類函式中如何使用類的成員

在不屬於類成員的函式中是不能直接使用類的成員函式的,可以有如下方法解決 1 傳遞類例項指標 這個方法簡單實用。如下 類ctestdlg的成員函式onbutton中呼叫了非類成員函式noclassfun,而在noclassfun又需要使用成員函式updatedata和成員變數m type,於是傳入類c...

const在類成員函式中的作用

程式通常不直接修改類物件。在必須修改類的物件時,應呼叫公有成員函式集來完成。為尊重類物件的常量性,編譯器必須區分不安全與安全的成員函式 即區分試圖修改類物件與不試圖修改類物件的函式 類的設計者通過把成員函式宣告為const,以表明它們不修改類物件。例如 class screen 只有被宣告為cons...

在類的成員函式中呼叫delete this

在類的成員函式中能不能呼叫delete this?答案是肯定的,能呼叫,而且很多老一點的庫都有這種 假設這個成員函式名字叫release,而delete this就在這個release方法中被呼叫,那麼這個物件在呼叫release方法後,還能進行其他操作,如呼叫該物件的其他方法麼?答案仍然是肯定的,...