最近看《深度探索c++物件模型》時,對物件的構造有了粗略的了解,同時也發現了其中的一些內容和我在其他書本中了解的有些不同的地方。在這裡記錄下來。
《effective c++》一書中 條款05:了解c++編寫並呼叫哪些函式
當然這些內容在《c++ primer》也有講到。
其中講的是class empty {};乙個空類在使用的時候哪些函式會被預設生成。
在這裡我定義乙個有兩個int 型別成員的類作為代替說明。
class point
;//這就好像你寫下
class point
point(const point &rhs)
~point(){}
point & operator = (const point & rhs)
private:
int x;
int y;
};
class point
;int main(int argc,char **ar**)
根據書本《effective c++》和《c++ primer》我們認為 在a 處 e1 需要呼叫point的建構函式,由於我們沒有定義任何乙個建構函式,於是編譯器會為point 生成乙個建構函式,並在a處呼叫它。b,c 處類似,當然在主函式返回之前,還需要對 e1,e2 呼叫析構函式。
但是真的事實如此嗎?編譯器真的會為這個類合成這些函式嗎?
我們首先編譯上面的這段**,生成可執行檔案。
然後使用objdump 進行反彙編。
反彙編後的輸出檔案片段,
雖然對彙編**不是很熟悉,但是也可以發現在main中沒有任何呼叫函式的操作,也就是建構函式、拷貝建構函式、拷貝賦值運算、析構函式都沒有被呼叫。同樣在反彙編後的檔案中,也沒有有關point的函式被合成。所以當我們寫下乙個類時,並在使用時,那些可能會被呼叫的操作,實際上並沒有被呼叫。那在什麼情況下才會被呼叫。
1、我們真的定義這些函式。
//把剛才的 class point ;替換為如下**
class point
point(const point &rhs)
~point(){}
point & operator = (const point & rhs)
private:
int x;
int y;
};
然後重複編譯和反彙編操作,生成的**如下。
可以發現這些操作真的被呼叫了。
2、我們沒有定義這些操作,但是編譯器需要合成乙個,已完成某種操作。但是編譯器合成的操作只能滿足編譯器的需求,並沒有滿足程式的需求,程式的需求是希望對x,y 執行初始化,但編譯器並沒有這個責任。
對於乙個建構函式,如果我們沒有定義任何建構函式,編譯器在什麼情況下會合成乙個呢
含有member class object 而且它含有乙個 default constructor,被合成出來的default constructor 的操作就是為了呼叫 member class object 的default constructor
帶有base class ,並且base class 中含有default constructor ,被合成出來的default constructor 的操作就是為了呼叫 base class object 的default constructor,base class 可能有多個,根據宣告順序被呼叫。
class 裡 含有 virtual function,無論是自己宣告,或者來自繼承鏈,編譯器都會為該類安插乙個vptr 指標,以指向該類的virtual function table,在建構函式中設定vptr的值,以通過該vptr 來完成某種特定的操作。
class 帶有乙個virtual base class,帶有virtual base class會使對virtual base class的成員的訪問操作變得複雜,編譯器會安插指標,已完成正確的操作。virtual base class 比較複雜,這裡說的比較簡單
對於建構函式如果沒有定義,編譯器會按照上面的規則來合成。
其他的函式,如果沒有定義,能被合成出來也是有一定規則的。後面會在補充。
所以編譯器合成出來的建構函式是為了完成某種操作,如果沒有任何操作需要完成,那編譯器也就沒有必要為它合成乙個。否則的話就浪費了無用的函式呼叫。
C 合成預設建構函式的真相
對於c 預設建構函式,我曾經有兩點誤解 第乙個誤解來自於我學習c 的第一本書 c primer 在書中392頁 只有當乙個類沒有定義建構函式時,編譯器才會自動生成乙個預設建構函式 實際上這句話也沒有說錯,它說明了預設建構函式定義的必要非充分條件,然而卻給當時初學c 的我造成了一定的誤解。第二個誤解依...
預設建構函式和合成預設建構函式
當我們沒有為類中的物件提供初始值,此時就會執行預設初始化,類會通過乙個特殊的建構函式來控制預設初始化過程,這個函式叫做預設建構函式,這個函式並不需要任何的實參,但是如果我們的類沒有顯式地定義建構函式,那麼編譯器就會為我們隱式地定義乙個預設建構函式 只要沒有顯式定義建構函式,編譯器就會提供預設建構函式...
C 函式 預設引數的函式
1 預設引數的目的 c 可以給函式定義預設引數值。通常,呼叫函式時,要為函式的每個引數給定對應的實參。例如 void delay int loops 函式宣告 void delay int loops 函式定義 void point int a void point 可以用下面的預設引數的函式來替代...