類的大小一般是指經過例項化後類物件的大小。
//1真空類:長度:1
class a ;
//2空類 長度1,同真空類。
class a
public:
a();
~a();
void fun();//成員函式不會影響類的大小。
};//3簡單類,長度4
class a ;
//4有虛函式的類 長度:4
class a ;
注1 虛函式表:如果基類派生類定義了虛函式或者派生類從繼承自有虛函式的基類,編譯器會自動為這個類建立乙個 虛函式表,用來儲存該類中所有虛函式位址。在虛函式沒有被派生類重寫的情況下,派生類會直接繼承基類的虛函式表。
注2 虛函式表指標當類中定義了乙個虛函式,系統會秘密往這個類中植入乙個虛函式表指標。該指標在類物件構造時被初始化,指向該類的虛函式表。虛函式表被該類的所有物件所共有,虛函式表指標則是每個類物件獨有乙份。
注3 兩者關係:虛函式表指標指向乙個虛函式表(函式指標陣列),裡面存放著乙個或多個虛函式的位址。對於虛函式位址的翻譯取決於物件的記憶體位址,而非資料型別。因為物件的記憶體位址中包含乙個虛函式表入口位址,該位址在物件被構造時由編譯器寫入。所以乙個父類物件的指標如果賦予父類物件位址,就會呼叫父類虛函式表,如果被賦予子類物件位址,就會呼叫子類虛函式。這也是虛函式能實現多型的原因。
**解析
#include
using
namespace
std;
class a
};class b :public a
virtual
void fun2() {}
};int main()
執行結果:
derived
解析:
b類物件的虛函式指標的值賦值給a類指標,也就是b類物件虛函式表的位址,然後在虛函式表中提取第乙個位址,也就是b::fun()的位址,最後呼叫這個函式。
//5繼承 基類長度8,派生類長度8。
class a ;
class b :public a ;
6記憶體對齊 基類長度8,派生類長度8。
//記憶體對齊使得最後類物件大小為最大資料型別的最小整數倍。
class a ;
class b :public a ;
綜上:
空類或者繼承空類,大小都為1;
虛函式本身,成員函式,靜態資料成員不影響類的大小,因而類的大小》=非靜態成員資料。
1基類的大小=類中非靜態資料成員總和+1個虛函式表指標(如果存在虛函式)+記憶體對齊決定。
2派生類=繼承基類+自身特有的非靜態資料成員+記憶體對齊。
1為什麼空類有1位元組大小?
空類同樣可以例項化,並且每個類物件都有乙個獨一無二的位址。為此需要編譯器給空類物件隱含加乙個位元組。
2 為什麼類的靜態成員變數不影響類的大小?
類的靜態成員變數實際上作為一種特殊全域性變數,它一旦被申明,無論類物件是否被例項化,都存在唯一乙個。
類的非靜態成員資料只有類物件被例項化時才存在。
3為什麼成員函式不影響類的大小?
類的成員函式不是在類物件例項化時載入記憶體,而是在編譯鏈結時就確定了相對位址,在程式執行時所有函式載入到**區,被所有物件共用。
意義:成員函式不隸屬於任何乙個類物件,被該類所有物件所共享(便於簡化實現,節省記憶體以及保持一致性行為).雖然類物件雖然行為一致,但操作著不同成員資料。
4為什麼存在虛函式的類需要計算乙個虛函式表指標?
該類中的所有虛函式位址需要存放在乙個虛函式表中,因而必須儲存乙個指向虛函式表的指標位址。而虛函式表指標的位址存在類物件的記憶體空間中,也就是在類物件被例項化的時候才初始化。
小型物件記憶體分配
c 語法中動態分配和指標 引用的使用非常普遍,然而預設的自由儲存區分配器 比如 operator new和 operator delete 只適用於大物件對分配,對小物件分配並不有效,甚至非常低劣,多次分配小物件後容易產生碎片。小型物件分配器 小型物件分配器分為 4層結構。如圖所示,下層提供功能供上...
分清楚父類物件和子類物件的記憶體分配
一.背景 之前一直對類記憶體分布和物件真正的記憶體分布沒有清楚的理解.看到類記憶體分布時,子類中的變數有一部分是來自父類的,就認為在生成父類物件和子類物件時,他們共有的變數在記憶體上是重疊的.後來想了一下,應該不是這麼回事,就實地考察了下.二.舉例驗證 有如下的繼承關係,有分別定義了對應的物件,考察...
JAVA類記憶體分配
1 成員變數和區域性變數的區別 理解 1 在類中的位置不同 成員變數 類中方法外 區域性變數 方法定義中或者方法宣告上 2 在記憶體中的位置不同 成員變數 在堆中 區域性變數 在棧中 3 生命週期不同 成員變數 隨著物件的建立而存在,隨著物件的消失而消失 區域性變數 隨著方法的呼叫而存在,隨著方法的...