1、 乙個類是不是一定有建構函式?
c++ annotated referencemanual(arm):建構函式只在需要的時候才會被編譯器產生出來。關鍵字「在需要的時候」,被誰需要?一種是程式需要的時候,一種是變編譯器需要的時候。如果程式有需要(如,完成某些非靜態資料成員的初始化),那是程式設計師的責任,程式設計師需要自己提供建構函式。如果是編譯器需要則才會合成出來預設建構函式。編譯器不會替程式設計師完成任何多餘的工作。
2、 編譯器什麼情況下產生預設建構函式?產生的預設建構函式做些什麼?
1、 類a中包含類b物件的資料成員,且類b帶有預設建構函式。編譯器將會合成預設建構函式用以呼叫b的預設建構函式完成類b物件的初始化。
2、 類a擁有乙個帶有預設建構函式的基類b,編譯器將會合成預設建構函式用以呼叫b的預設建構函式。(無論是明確宣告或是被合成而得)
3、 類a中包含乙個虛函式時,編譯器將會合成預設建構函式用以完成物件模型中虛函式表指標的初始化。
4、 類a擁有乙個虛基類時,編譯器將合成預設建構函式用以安插「允許每乙個虛基類的執行期訪問操作」的**。
備註1:如果程式設計師已提供預設建構函式,則編譯器將所需的操作插入該建構函式完成擴充套件。
備註2:c++書籍裡常見的錯誤
1> 任何class如果沒有定義預設建構函式,就會被合成出來乙個
2> 編譯器合成出來的預設建構函式會明確的設定「class內每乙個data member的預設值」。
如你所見,沒有乙個是真的!
3、 編譯器什麼情況下產生複製建構函式?
「在必要的時候」,即class不展現出bitwise copy semantics時。
1、類a中包含類b物件的資料成員,且類b帶有複製建構函式。編譯器將會合成複製建構函式用以呼叫b的複製建構函式完成類b物件的初始化。
2、類a擁有乙個帶有複製建構函式的基類b,編譯器將會合成複製建構函式用以呼叫b的複製建構函式。(無論是明確宣告或是被合成而得)
3、類a中包含乙個虛函式時,編譯器將會合成複製建構函式用以完成物件模型中虛函式表指標的重新設定。
4、類a擁有乙個虛基類時,編譯器將會合成複製建構函式用以完成對virtual base class的特殊處理(發生在derived class初始化base class的情況下,需要訪問基類的操作)。
備註:說的更明白一些同預設建構函式產生的情況類似(一致)。
4、 複製建構函式的程式轉化。
複製建構函式的呼叫發生在以下三種情況下:明確的初始化操作、引數的初始化、返回值得初始化。複製建構函式的呼叫都伴隨著程式轉化:
1、 明確的初始化操作:
重寫每乙個定義,其中的初始化操作被剝除;類的複製構造呼叫操作被安插進去。
c++ code 1
2345
6 x x0;
void foo_bar()
轉化後
c++ code 1
2345
void foo_bar()
2、 引數的初始化
已知的函式定義:void foo(x x0);
c++ code 1
2 x xx;
foo(xx);
轉化後
c++ code 1
23x __tmp0;
__tmp0.x::x(xx);
foo(__tmp0);
3、 返回值的初始化
新增額外引數,型別是class object的乙個reference,用來防治被拷貝構建而得的返回值;在return之前安插乙個複製構造的呼叫操作。
c++ code 1
2345
6 x bar()
轉化後
c++ code 1
2345
678
void bar(x &__result)
所以 x xx=bar();將被轉化為 x xx; bar(xx);
1> 當class內含乙個member object,而後者的class宣告有乙個copy constructor時(不論是被class設計者明確地宣告,或是是被編譯器合成)。
2> 當class繼承自乙個bass class而後者存在有乙個copy constructor時(再次強調,不論是被明確宣告或被合成而得)。
3> 當class宣告了乙個或多個virtual functions時。這種情況編譯器會為每乙個class object安插乙個vptr指標,這樣該類就不展現bitwise semantics了。現在,編譯器要合成乙個copy constructor,以求將vptr適當地初始化。
注意:① 當乙個類物件以另乙個相同的類物件作為初值時,都可以直接靠"bitwise copy semantics"完成。
② 當乙個base class object以其derived class的object內容初始化操作時,其vptr複製操作必須保證安全。
合成出來的基類copy constructor會明確設定object的vptr指向基類的virtual table,
而不是直接從右手邊的派生類中將其vptr現值拷貝過去。
4> 當class派生自乙個繼承串聯,其中有乙個或多個virtual base classes時。
virtual base class 的存在需要特別處理。乙個class object如果以另乙個object作為初值,而後者有乙個virtual class subobject,那麼會使"bitwise copy semantics"失效。
每乙個編譯器對於虛擬繼承的支援承諾,都表示必須讓「derived class object中的virtual base class subobject位置」在執行期備妥。維護「位置的完整性」是編譯器的責任。bitwise copy semantics可能會破壞這個位置,所以編譯器必須在它自己合成出來的copy constructor中做出仲裁(一部分工作是安插一些碼設定virtual base class pointer/offset的初值或簡單地確定它沒有被摸消)。
5、成員初始化列表(member initializationlist)
以下四種情況必須使用成員初始化列:
1、 當初始化乙個引用型別的資料成員時;
2、 當初始化乙個const資料成員時;
3、 當呼叫基類的帶參建構函式時;
4、 當調object型別的資料成員的帶參建構函式時;
前兩者因為要求定義時初始化,所以必須明確的在初始化佇列中給它們提供初值。後兩者因為需要顯式的呼叫它們的帶參建構函式而非預設建構函式在定義時初始化它們。
備註:說清楚點就是所有需要在定義時初始化的都需要使用初始化列表。
建構函式語意學
default建構函式操作 首先需要說明 帶來的第乙個問題,編譯器什麼時候合成預設建構函式 nontrivial 答案是編譯器需要的時候,而不是程式需要的時候。1 class foo class bar void foo bar 此時編譯器就會合成default 建構函式 類似 inline bar...
C 建構函式語意學 預設建構函式
在 class 中,若程式設計師沒有為該 class object 定義 default constructors,則編譯器會根據需要產生乙個 implicit default constructor,該 implicit default constructor 被認為是 trivial 無用的 那...
深度探索C 物件模型 之 建構函式語意學
explicit被引入c 是為了使程式設計師能夠制止 單一引數的constructor函式 被當做乙個conversion 運算子。有四種情況 1 帶有default constructor 的member classobject 2 帶有default constructor 的base clas...