一、建構函式為什麼不能為虛函數:
1、所謂虛函數,也就是根據對象的動態類型決定調用哪個函數。
2、建構函式是在對象完全構造之前啟動並執行,換句話說,運行建構函式前,對象還沒有產生,更談不上動態類型了。
這樣看,建構函式不可能是虛函數。
二、函數模板
函數模板是一種不說明某些參數的資料類型的函數。例如,下面定義了一個可對任何類型變數進行操作(求絕對值)的函數模板:
template <class T> //或寫成:template <typename T>T abs(T val) { return val<0 ? -val : val;}
在函數模板被調用時,編譯器根據實際參數的類型確定模板參數T的類型,並自動產生一個對應的函數,即模板函數。模板參數的類型不同,產生的模板函數也不同。
三、一個類的執行個體化對象所佔控制項
一個類的執行個體化對象所佔空間的大小? 注意不要說類的大小,是類的對象的大小。
首先,類的大小是什嗎?確切的說,類只是一個類型定義,它是沒有大小可言的。 用sizeof運算子對一個類型名操作,得到的是具有該類型實體(對象)的大小。
如果Class A; A obj; 那麼sizeof(A)==sizeof(obj)。
一個對象的大小大於等於所有非靜態成員大小的總和。
為什麼是大於等於而不是正好相等呢?超出的部分主要有以下兩方面:1)C++物件模型本身對於具有虛函數的類型來說,需要有一個方法為它的實體提供類型資訊(RTTI)和虛函數入口,常見的方法是建立一個虛函數入口表,這個表可為相同類型的對象共用,因此對象中需要有一個指向虛函數表的指標,此外,為了支援RTTI,許多編譯器都把該類型資訊放在虛函數表中。但是,是否必須採用這種實現方法,C++標準沒有規定,但是這幾戶是主流編譯器均採用的一種方案。2) 編譯器最佳化
因為對於大多數CPU來說,CPU字長的整數倍操作起來更快,因此對於這些成員加起來如果不夠這個整數倍,有可能編譯器會插入多餘的內容湊足這個整數倍,此外,有時候相鄰的成員之間也有可能因為這個目的被插入空白,這個叫做“補齊”(padding)。所以,C++標準緊緊規定成員的排列按照類定義的順序,但是不要求在儲存空間中是緊密排列的。 基於上述兩點,可以說用sizeof對類名操作,得到的結果是該類的對象在儲存空間中所佔據的位元組大小,由於靜態成員變數不在對象中儲存,因此這個結果等於各非待用資料成員(不包括成員函數)的總和加上編譯器額外增加的位元組。
範例程式碼:
class A{public: static int i;};int A::i = 0; int main(){ cout << sizeof(A) << endl;//1 return 1;}
後者依賴於不同的編譯器實現,C++標準對此不做任何保證。 C++標準規定類的大小不為0,空類的大小為1,當類不包含虛函數和非待用資料成員時,其對象大小也為1。
如果在類中聲明了虛函數(不管是1個還是多個),那麼在執行個體化對象時,編譯器會自動在對象裡安插一個指標指向虛函數表VTable,在32位機器上,一個對象會增加4個位元組來儲存此指標,它是實現物件導向中多態的關鍵。而虛函數本身和其他成員函數一樣,是不佔用對象的空間的。
我們來看下面一個例子:(此例子在Visual C++編譯器中編譯運行)
範例程式碼
class A { };class B { char ch; void func() { }};class C { char ch1; //佔用位元組 char ch2; //佔用位元組 virtual void func() { }};class D { int in; virtual void func() { }};void main() { A a; B b; C c; D d; cout<<sizeof(a)<<endl;//result=1 cout<<sizeof(b)<<endl;//result=1 //對象c實際上只有位元組有用資料,但是 //按照上面第二點編譯器最佳化,編譯器將 //此擴充為兩個字,即位元組,有虛表地址,為其類型大小的整數倍 cout<<sizeof(c)<<endl;//result=8 cout<<sizeof(d)<<endl;//result=8}
綜上所述:
一個類中,虛函數、成員函數(包括靜態與非靜態)和待用資料成員都是不佔用類對象的儲存空間的。
對象大小 = sizeof(vptr) + 所有非待用資料成員大小 +
Aligin位元組大小(依賴於不同的編譯器)。