標籤:end initial ini 注意 sel int get 相容 model
最近在研讀《insight C++ object model》,看到第二章中建構函式部分,深有感觸,故此寫下,方便大家。當然,也方便我,免得我忘了。
1 class test{2 public:3 int a;4 };5 int main(){6 test t;7 std::cout<<t.a<<std::endl;8 }
結果大家都知道,t.a沒有被初始化,所以是個隨機值。那麼問題來了,以以前的知識來看,當某個類中沒有建構函式,編譯器會為其產生一個預設建構函式,而這個預設建構函式,會調用成員變數的預設建構函式,int的預設建構函式是將其初始化為0。
1 int t=int(); //t==0
那麼為什麼會出現這種結果?當年的標準是這樣定的:只有在編譯器需要的時候才會產生預設建構函式。換句話說,編譯器不關心使用者的“鳥事”,編譯器不在乎使用者是否需要,他只關心自己。。。試試下面的代碼:
test t=test();std::cout<<t.a<<std::endl; //get 0
這時候,顯式調用了test的建構函式,但test沒有建構函式,編譯器這時候需要建構函式來,於是他就自造了一個。於是a就得到預設值了。
為什麼要有這樣不合理的設計呢?Lippman在書裡沒有提到。但我猜想應該是為了相容C代碼,考慮一下:
1 struct test{2 int a;3 };4 int main(){5 struct test t;6 printf("%d\n",t.a);7 }
若test的預設建構函式產生,並導致a被初始化為0,那麼C++中就將輸出0。但C中沒有建構函式這一概念,所以就將輸出任意值。早期C++是目地之一為了很好的相容C代碼,所以C++編譯器為了更好的相容C,就選擇了這種看似很不可思議的方法。(ps:以鄙人之見,應該沒多少人會在參數未初始化情況下直接使用,所以不相容的機率應該及其低)
那麼在什麼情況下,C++編譯器才會類為其產生預設建構函式呢?很簡單,書上說了四種情況:
1、成員對象有預設建構函式的情況
2、此類發生繼承,而基類有預設建構函式
3、此類有虛函數
4、此類虛繼承自其他類
我歸結一下,就是C代碼裡不可能出現的情況。在C代碼裡可能出現的情況,編譯器都不會產生預設建構函式。以下依次說說這四種情況。
先考慮第一種:
class test1{public: int a;};class test2{public: test1 t; int b;};int main(){ test2 t; std::cout<<t.t.a<<std::endl; //print 0 std::cout<<t.b<<std::endl; //uninitialized}
說好的初始化呢?為什麼只有t會被初始化,b怎麼不會?請注意,被合成的預設建構函式只滿足編譯器的需要,而不是程式的需要(selfish)。換句話說,他只初始化有預設建構函式的成員對象(ps:int至少不是對象。另外,有人會問為什麼不初始化有建構函式但不是預設建構函式的成員對象。。。想想,這種建構函式得被顯示調用啊)。而且是一定會初始化有預設建構函式的成員對象。也就是說,
class test2{public: //... test2(){ b=0; }};
即使如此,t也會被初始化,這段代碼相當於:
class test2{public: //... test2():test1(){ b=0; }};
未完待更
Default Constructor in C++