隱式建立預設建構函式的迷惑(一)
《深度探索
c++物件模型》讀書筆記
飄飄白雲
《深度探索
c++「
c++新手一般有兩個常見的誤解:
1,任何
class
如果沒有定義
default constructor
,就會被合成出乙個。
2,編譯器合成出來的
default constructor
會明確設定
「class
內每乙個
data member
的預設值」。
如你所見,沒有乙個是真的!」。
看了這一段,是不是覺得大學裡教
c++的就是糊弄小朋友的,如果不是見到這段話,我還會傻乎乎地相信,每個類如果沒有定義預設建構函式,就會自動建立乙個,並使用「零值」初始化資料成員。
先看個例子:
#include
using
namespace
std;
class
foo;
virtual ~foo()
;protected
:private:};
intmain()
else}在
vs下編譯執行輸出:
data member val hasn't been initialized to 0
。如果把被遮蔽的那個空建構函式恢復,輸出結果就是另外一回事了。
那麼到底在什麼情況下,
c++編譯器會為我們建立預設建構函式,並初始化資料成員呢?
c++ standard
〔iso-c++95
〕裡面這麼說的:
「對於class x
,如果沒有任何使用者宣告的建構函式,那麼會有乙個預設建構函式被隱式宣告出來……
乙個被隱式宣告出來的預設建構函式將是乙個沒什麼用的
(trival)
建構函式。」
這裡所說的「沒什麼用的
(trival)
」是指僅僅是為了編譯器編譯的需要,而不是為了程式需要(比如變數必須初始化)而建立這麼乙個建構函式。看了上面這段話,感覺前面的提醒似乎有點不對,呵呵,後面還有說明:
在四種情形下,「編譯器必須為未宣告
constructor
的classes
合成乙個
default constructor
」,c++
標準把那些合成物成為
隱式的有用的(
nontrival
)default constructor
,它們只能滿足編譯器的需要。
在這四種情況之外而有沒有宣告任何
constructor
的classes
,擁有的是隱式的沒什麼用的(
trivial
)default constructor
,實際上它們並不會被合成出來。
下面我們依次來說明這四種情形
a,b,c和d
。<
待續》情形a:擁有成員物件,並且這個成員物件所屬的類擁有預設建構函式。
乙個類沒有任何建構函式,但是它內含有乙個成員物件,而這個成員物件有預設建構函式,那麼編譯器就會在必要的時候為這個類隱式合成乙個有用的(
nontrival
)建構函式。
還是來看**說的清楚些:
#include
using
namespace
std;
class
foo;
foo(int
a);~foo();
intifooval;
};class
bar;
};int
main()
if (bar.ibarval == 0)
}在這段**裡,我把成員物件
foo的預設建構函式遮蔽了,按照上面的解釋,應該是會報錯,因為類
bar不會合成乙個隱式的有用的預設建構函式。編譯執行,看看編譯器怎麼說:
呵呵,不出所料!如果我們恢復
foo的預設建構函式
foo(),則編譯執行輸出:
default constructor of foo!
注意:bar
和foo
的資料成員並沒有因此而初始化為
0!下來我們來深入探索下在
foo有預設建構函式的情形下,宣告
bar物件時被合成的那個隱式有用的建構函式做了些什麼:
它會按照有顯式預設建構函式的成員物件在類中宣告的順序依次呼叫這些成員物件的顯式預設建構函式,除此之外它什麼也不做。
那麼為bar
合成的那個隱式建構函式就應該看起來象這個樣子:
inline
bar::bar()
建構函式隱式轉換
建構函式會引起乙個不引人注意的問題 用單個實參來呼叫的建構函式定義了從從形參型別到類型別的乙個隱式轉換。舉個例子說 cpp view plain copy class sales item sales item add sales item other sales item const std st...
建構函式 建構函式隱式轉換 拷貝建構函式
建構函式對於我們來說是比較熟悉的,c primer裡提到 類通過乙個或幾個特殊的成員函式來控制其物件的初始化過程,為 建構函式。例1 class fruit 定義乙個類,名字叫fruit 這樣的建構函式是我們比較常見的,但是如果變成 class fruit 定義乙個類,名字叫fruit 即使是乙個類...
類建構函式的隱式轉換
在程式設計中,型別轉換在所難免,在此我將介紹一下c 中常用的隱式轉換和強制型別轉換。關於隱式轉換 在c 中,某些型別之間存在相關的依賴關係,若兩種型別相關,則可以再需要某種型別的運算元位置上,使用該型別的相關型別物件或值。c 並不是吧兩個不同型別的值直接加在一起,而提供了一組轉換規則,一邊在執行算數...