天天看點

C++類對象成員變量和成員函數記憶體配置設定的問題

(轉載自:http://blog.sina.com.cn/s/blog_4feac7b90101keet.html)

很多人都知道C++類是由結構體發展得來的,是以他們的成員變量(C語言的結構體隻有成員變量)的記憶體配置設定機制是一樣的。下面我們以類來說明問題,如果類的問題通了,結構體也也就沒問題啦。 類分為成員變量和成員函數,我們先來讨論成員變量。 一個類對象的位址就是類所包含的這一片記憶體空間的首位址,這個首位址也就對應具體某一個成員變量的位址。(在定義類對象的同時這些成員變量也就被定義了)我們來以一段代碼說明問題: //類的定義

class K{

public:

 K(){k = 12;}

 ~K(){}

 int k;

}; 

//類的使用//... K kTemp;

 printf("%d--%d\n",&kTemp,&kTemp.k);

 printf("%d--%d\n",sizeof(K),sizeof(kTemp.k));

 int *i = (int*)(&kTemp);

 int w = *i;

 printf("%d\n",w); 運作上面的代碼,結果如下:1310588--1310588

4--4

12

很明顯,類的記憶體大小和其唯一的成員變量的記憶體大小是一緻的。記憶體位址也是一緻的。他們甚至可以互相轉換。換成結構體結果也是一樣。網友可以自己運作上面代碼來進行确認。 這個時候,可能有人會提出疑問了。那麼成員函數又如何?上面得代碼就好像類沒有任何成員函數一樣,根本說明不了問題。 呵呵,所有的函數都是存放在代碼區的,不管是全局函數,還是成員函數。要是成員函數占用類的對象空間,那麼将是多麼可怕的事情:定義一次類對象就有成員函數占用一段空間。 我們再來補充一下靜态成員函數的存放問題吧:靜态成員函數與一般成員函數的唯一差別就是沒有this指針,是以不能通路非靜态資料成員,就像我前面提到的,所有函數都存放在代碼區,靜态函數也不例外。所有有人一看到 static 這個單詞就主觀的認為是存放在全局資料區,那是不對的

----------第二篇------------

c++是一種面向對象的程式設計語言,它向下保持了對c的相容,同時也允許程式員能夠自由的操控記憶體,雖然會帶來一些問題,但這不是我們要探讨的問題,略過不表。類是對某種對象的定義,包含變量和方法,也可以了解為現實生活中一類具有共同特征的事務的抽象,他是面向對象語言的基礎。是以類是不占有記憶體的,可是如果類生成執行個體那麼将會在記憶體中配置設定一塊記憶體來存儲這個類。

    類的執行個體在記憶體中是如何配置設定記憶體的,有什麼需要我們注意的,下面将慢慢到來。

    比如下面一個類:

    class A

    {};

    從形式上看,它似乎什麼有沒有,事實上它不止隐含了一個構造函數和一個析構函數,還有一些操作符重載函數,比如“=”。如果類A被執行個體話,如A a;在記憶體會占據多大的空間呢?有人可能會說4,也有人會說0,還有人會說1,說1的就對了,為什麼會是1呢?原因有很多,如果我們定義一個數組A b[10];如果上面是0,這樣的局面将會很尴尬,是以A這樣一個空類,編譯器會給它一個位元組來填充。  

    增加一個變量,(位元組對齊預設都是4)

    class  A

   {

     public:

       int i;

   }

   類A的執行個體将占據4個位元組的記憶體,sizeof(A) = 4

   變量i 的初值被編譯器指定位0xcdcdcdcd。

   再增加一個變量,

   class A

   {

      public:

      int  i;

      int  l;

   }

   此時按照變量生命的先後順序,i被放在低位址上,l緊随其後。

   執行個體占用8個位元組,sizeof(A) = 4*2 = 8

   如果類裡面含有函數:

  class A

 {

     public:

      int i;

      int l;

      int add(int x,int y){return (x+y);}

 };

 有些人可能會說類的大小是12,事實上sizeof(A) = 8;

 為什麼會這樣,這是因為sizeof通路的程式的資料段,而函數位址則被儲存在代碼段内,是以最後的結果是8.

 再看下面這個情況

 class A

 {

      public:

         int i;

         int l;

         static int s;

         int add(int x,int y){return (x+y)};

 };

此時sizeof(A)大小仍為8,這裡留給讀者去思考為什麼?(^-^)。

當類裡面含有虛函數時,情況會如何呢?

 class A

 {

      public:

         int i;

         int l;

         static int s;

         virtual void Say(){};

         int add(int x,int y){return (x+y)};

 };

 因為含有虛函數,是以類裡面将含有一個虛指針vptr,指向該類的虛表vtbl,一個指針占用四位元組的位址,是以sizeof(A) = 12

 虛指針放在類執行個體位址的最低位置,

 比如 A *a = new A;

 我們可以這樣給變量i指派

 int *p = (int *)a;

 p++;

 *p = 1;//把i的值賦為1.

如果類作為派生類,記憶體将如何配置設定呢?

這種情況雖然有些複雜,但并不是說不好了解。

他有多少個父類每個父類的大小加起來在加上自身就是sizeof的大小。

轉自:http://blog.csdn.net/alexwei2009/archive/2011/01/22/6157926.aspx

//-----C++類對象記憶體結構[講得很好] -------

首先介紹一下C++中有繼承關系的類對象記憶體的布局: 

在C++中,如果類中有虛函數,那麼它就會有一個虛函數表的指針__vfptr,在類對象最開始的記憶體資料中。之後是類中的成員變量的記憶體資料。 

對于子類,最開始的記憶體資料記錄着父類對象的拷貝(包括父類虛函數表指針和成員變量)。 之後是子類自己的成員變量資料。 

對于子類的子類,也是同樣的原理。但是無論繼承了多少個子類,對象中始終隻有一個虛函數表指針。 

繼續閱讀