C 建構函式語義 預設建構函式

2021-06-05 07:33:18 字數 1735 閱讀 7622

《the c++ arm》告訴我們:「預設建構函式會在需要的時候自動生成(被編譯器)。」然後「在需要的時候」是乙個很抽象的概念,本文主要描述的問題也正是這些需要的情況。

我們看看下面的**片段:

class foo

;void foo_bar()

}

使用者並沒有顯示地定義預設建構函式,編譯器會為它自動生成乙個無關緊要(trivial)的預設建構函式,生成的預設建構函式什麼也不錯,既不會講其成員變數置零,也不會做其他的任何事情,只是為了保證程式能夠正確執行而已,這就是所謂的「需要」,如果還需要給初始化成員變數,這件事情還是交給程式設計師做吧!

c++標準描述了哪些情況,這樣的隱式預設建構函式是無關緊要的。乙個非平凡(non-trivival)的預設建構函式是arm中所說的被實現所「需要」,並在必要的時候被編譯器自動生成。下面來看看預設建構函式是非平凡的四種情況:

如果該類包含乙個成員類物件,它有預設的建構函式,那麼這個類的隱式建構函式是非平凡的,並且編譯器需要為包含的這個成員類物件生成乙個預設建構函式。然後,這個編譯器生成的預設建構函式只有在實際上被呼叫時才會被真正的生成。

class foo

int _i;

};class bar

;void foo_bar()

在這個程式片段中bar的成員foo含有預設建構函式,它初始化自己的類成員_i為1而bar本身並沒有定義預設的建構函式,這個建構函式的目的是為了初始化它的成員變數foo,實際上就是呼叫bar::foo的預設建構函式,但它並不會做一丁點關於另外乙個變數str的初始化和賦值工作,初始化bar::foo是編譯器的責任,二初始化str是程式設計師的。我們可以用以下**來大致描述一下編譯器的工作:

inline 

bar::bar()

如果這裡的bar含有預設建構函式呢?我們可以從編譯器和程式設計師的責任劃分來考慮這個問題:

1. bar的預設構造函式呼叫foo的預設建構函式,那麼編譯器啥也不用做了。

2. bar的預設建構函式中沒有去foo這個成員變數,那麼編譯器需要去幫助程式設計師把這件事情做完,插入一條類似「foo.foo::foo();」的**。

注:如果bar含有多個成員類變數,則編譯器會按照這些變數的宣告順序去做以上處理。

類似的,要是乙個繼承的基類包含預設建構函式而該類本身沒有任務的建構函式,那麼編譯器會生成乙個預設建構函式,目的是初始化它的基類。

當程式設計師為該類定義了多個建構函式,就是沒定義預設建構函式呢?

在這種情況下,編譯器會在每乙個建構函式中增加(augment)有關呼叫基類的預設建構函式部分**。

生成的預設建構函式是必須的當另外兩個額外條件(滿足其一):

1.該類定義了(或繼承了)虛函式。

2.在該類的繼承關係中,有乙個或更多的虛基類。

class widget

;class bell: public widget

};class whistle: public widget

};void flip(widget &widget)

void foo()

在編譯時,在預設建構函式中會發生下面的兩個類擴充(augmentation):

1.虛表會被產生,其內容被這個類的活動(active)虛函式填充。

2.編譯器為每個類物件生成乙個虛指標(vtbl)。

《inside the c++ object model》

C 建構函式語意學 預設建構函式

在 class 中,若程式設計師沒有為該 class object 定義 default constructors,則編譯器會根據需要產生乙個 implicit default constructor,該 implicit default constructor 被認為是 trivial 無用的 那...

建構函式語義學

有些書上說,如果乙個類中沒有任何的建構函式,那麼編譯器會為我們預設的合成乙個 合成預設規則函式 其實,系統是在 必要的時候 才會為我們合成預設的建構函式。這個可以去分析obj檔案 情況1 如果乙個類中沒有任何的建構函式,且它的成員變數中含有乙個類型別的成員,那麼這個時候系統會為這個類合成乙個預設的建...

C 物件模型 拷貝建構函式語義

目錄引例 如果乙個類a沒有拷貝建構函式,但是含有乙個類型別ctb的成員變數m ctb。該型別ctb含有拷貝建構函式,那麼當 中有涉及到類a的拷貝構造時,編譯器就會為類a合成乙個拷貝建構函式。如果乙個類ctbson沒有拷貝建構函式,但是它有乙個父類ctb,父類有拷貝建構函式,當 中有涉及到類ctbso...