轉載:http://blog.csdn.net/xmu_jupiter/article/details/42648717
(轉載自: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,在類對象最開始的內存數據中。之後是類中的成員變量的內存數據。
對於子類,最開始的內存數據記錄着父類對象的拷貝(包括父類虛函數表指針和成員變量)。 之後是子類自己的成員變量數據。
對於子類的子類,也是同樣的原理。但是無論繼承了多少個子類,對象中始終只有一個虛函數表指針。