在文章開始之前,首先指出對於c++新手的兩個常見的誤解:
一、任何class如果沒有定義default constructor,就會被合成出一個來。
二、編譯器合成出來的default constructor會明確設定'“class內每一個data member的預設值”
首先我們來討論第一個誤解。編譯器並不是給任何一個沒有user-declared constructor的class合成出default constructor,編譯器只會在需要的時候才會給沒有user-declared constructor的class合成出default constructor。那到底什麼時候才是需要的呢?首先我們先看一下C++ standard中的一句話:“對於class X, 如果沒有任何user-declared constructor, 那麼會有一個default constructor被暗中(implicitly)聲明出來……一個被暗中聲明出來的default
constructor將是一個trivial(無能的) constructor”。對於這句話,首先解釋一下,原話中的暗中聲明出來並不代表編譯器會給他合成出來,對於trivial constructor,編譯器是不會給他們合成出來的,編譯器會合成出來的只是那些nontrivial default construtor,而到底哪些才算是nontrivial default constructor呢? 《Insider C++》中給出了四種情況。
1、一個class的成員中含有帶有default constructor的member class object
如果一個class中含有成員對象,而且這個對象有default constructor,, 那麼編譯器就會給這個class合成一個default constructor, 但是這個合成動作只有在調用需要時才會產生。也就是說,在需要時才會合成。
例如:
- class Foo{
- public Foo();
- ......
- }
-
- class Bar{
- Foo foo;
- char *str
- }
-
- void foo_bar(){
- Bar bar; //bar必須在此初始化
- if(str){}.....
- }
在上述代碼中,line12,bar必須在此初始化,當這時時,編譯器就會給Bar合成一個default constructor,在default constructor中安插代碼調用Foo的default constructor,但是有一點,編譯器為Bar合成的default constructor不會對str進行初始化,對str進行初始化,那隻是程式員需要做的事情,而對於合成出的default constructor,它只滿足編譯器的需求,而不會去滿足程式的需求。
如果class中內含一個以上的含有default constructor的object,那在為class合成的default constructor中,會按照object的聲明次序調用object 的 default constructor。
2、 class繼承於帶有default constructor的base class
如果一個沒有任何constructor的衍生類別繼承自一個帶有default constructor的base class, 那麼這個衍生類別的default constructor被認為是nontrivial,而對於nontrivial的default constructor, 編譯器會為他合成出來。在合成出的default constructor中調用base class的default constuctor.
如果設計者提供了多個constructor,但為提供default constuctor,那編譯器不會合成新的default constructor,而是會擴充所有的現有的constructor,安插進去default constructor所必須的代碼。如果此類中仍存在第一種情況,也就是說存在有menber object, 而且object含有default constructor, 那這些default constructor 也會被調用,在base class的default constructor被調用後。
3、 這個class中帶有virtual function
無論一個class是聲明(或繼承)了一個virtual function, 還是派生自一個繼承串聯,其中有一個或多個virtual base class.不管上述哪種情況,由於缺乏由user聲明的constructor, 編譯器會詳細記錄合成一個default constructor的詳細資料。
在編譯期間,會做以下的擴張工作:
(1) 一個virtual function table會被編譯器產生出來,內含virtual functions的地址。
(2) 編譯器會合成一個vptr, 插入每一個object中。
而合成出來的default constructor,當然會為每一個object 設定vptr的初值。
4、 帶有一個virtual base class的class
對於這種情況,我還沒有研究透徹,研究透徹後我會再給大家貼出來。
以上就是對第一個誤解的討論,對於第二個誤解,對於合成出的default constructor,只會做一些必要的事情,比如對base class subobject 和member class object進行初始化,而對於一些其他的nonstatic data member如整數,指標,數組等則不會進行初始化,因為那些東西對於編譯器來講並不是必要的。
總結:
以上給大家講述了那兩個誤解。希望能夠對大家有所協助。只有那四種情況,編譯器才會為未聲明constructor的class合成出default constructor,而且被合成出來的constructor只會滿足編譯器的需要,而不會去滿足程式的需要,而他們之所以能夠完成任務(滿足編譯器的需要),是藉著調用"member object或base class的default constructor”或是“為每一個object初始化其virtual function機制(包括vtbl的建立和vptr的正確初始化)或virtual
base class機制”。而對於沒有存在那四種情況並且又沒有user-decleared constructor的class,我們稱其擁有的是implict trivial default constructor, 而實際上,它並沒有被合成出來。
所以,由此可見,以上的兩個誤解,都是錯的。
本文出自 “一步一趨 只求每一步走..” 部落格,請務必保留此出處http://neuloner.blog.51cto.com/1479078/307497