先引用《深度探索C++對(duì)象模型》中的一段話:
C++ 新手一般有2個(gè)誤解
1 任何class如果沒(méi)有定義default constructor,就會(huì)被合成出一個(gè)來(lái)
2 編譯器合成出來(lái)的default constructor會(huì)顯示設(shè)定class類每一個(gè)data member的默認(rèn)值。
如你所見(jiàn),沒(méi)有一個(gè)是真的。
有下列4種情況,編譯器必須會(huì)未聲明的constructor合成一個(gè)“default constructor”, 被合成出來(lái)的constructor只能滿足編譯器需要而不是程序需要。
1 "帶有Default Constructor"的member class object
class Foo{
public:
Foo();
Foo(int);
};
class Bar
{
public:
Foo foo;
char *str;
};
這種情況下,編譯器會(huì)為class Bar 合成一個(gè)default constructor,被合成的default constructor內(nèi)含必要的代碼,能夠調(diào)用class Foo的default constructor來(lái)處理Bar::foo。至于*str的初始化(程序的需要),編譯器并不會(huì)管。
偽代碼:
inline Bar::Bar()
{
foo.Foo::Foo();
}
但是如果Bar已經(jīng)顯示定義了一個(gè)默認(rèn)構(gòu)造函數(shù),比如
Bar() { str = nullptr; }
現(xiàn)在程序的需求已經(jīng)滿足了,但是編譯器還需要初始化member object foo。這是,編譯器不能定義default constructor了,只能在程序員定義的構(gòu)造函數(shù)安插一些代碼,確認(rèn)user code被執(zhí)行之前,先調(diào)用default constructor。類似偽代碼:
Bar {
/*
插入的代碼
foo.Foo::Foo();
*/
str = nullptr;
}
class A { public A() { } };
class B { public B(int) { } };
class C { public C() { } };
class D {
public:
D(): b(int) { }
public:
A a;
B b;
C c;
};
這種情況是D的構(gòu)造函數(shù)會(huì)被改造為:
D():b(int) {
a.A::A();
b.B::B(int);
c.C::C();
// 其他
}
注意順序是按照聲明順序來(lái)的。
2 "帶有Default Constructor"的Base Class
類似道理,如果沒(méi)有任何constructors的class繼承自一個(gè)帶有Defaultor Constructor的Base class, 那么derived class的default constructorh會(huì)被合成出來(lái),調(diào)用Base class的defaultor constructor。
3 "帶有Virtual Function"的Class
class Widget
{
public:
virtual void flip() = 0;
};
class Bell : public Widget {......}
class Whistle : public Widget {......}
void flip(const Widget& widget) { widget.flip(); }
void foo() {
Bell b;
Whistle w;
filp(w);
filp(b);
}
下面2個(gè)行為會(huì)在編譯期間發(fā)生:
- 一個(gè)virtual function table(vptl)會(huì)被編譯器產(chǎn)生出來(lái),里面放class 的virtual function的地址。
- 在每一個(gè)class object中,一個(gè)額外的pointer member(vptr)會(huì)被產(chǎn)生出來(lái),內(nèi)含vtbl地址。
這一段可以結(jié)合另外2篇文章理解:
C++ 對(duì)象模型分析
C++ 虛函數(shù)表分析
4 "帶有一個(gè)Virtual Base Class"的Class
這塊還不熟悉,待更。