default constructor 会在需要的时候被编译器产生出来
----<<Inside C++ Object Model>>
一切从这开始, 是在谁需要的时候? 考察以下代码:class Foo{public: int val; Foo *pnext};
void FooBar()
{
//Foo Object 须在此初始化
Foo bar;
if(bar.val || bar.pnext)
//do something...
}
编译器不会为其产生一个 default constructor, 因为这是程序需要而不是编译器需要, 程序有需要, 那是程序员的责任, 因此上述代码不会合成一个 default constructor.
那么在那些情况下是编译器需要构建 default constructor 的情况呢?
1. 带有 Default Constructor 的 Member Class Object
但出现一个问题, 怎样防止在不同模块中生成多个 default constructor?
解决方法是, 把合成的 default constructor 都以 inline 的方式完成, inline 函数有静态连接, 不会被文件以外看到, 如果函数太复杂, 不适合做出一个 inline, 编译器则会做出一个 explicit non-inline static 实体. 考察以下代码:
class Foo{public: Foo(){} Foo(int){/* do something */}...};
class Bar{private: Foo foo; char *pstr;};
void FooBar()
{
//bar Object 需要在此初始化
Bar bar
if(str)...
}
此例中, 编译器会产生 bar 的 default constructor 来调用 class Foo 的 default constructor 初始化 Bar::foo, bar 的 default constructor 中, 并不存在初始化 str 的代码, 因为那是程序员的责任.
那么如果程序员已定义了用来初始化 str 的 constructor, 如:
Bar::bar(){str = 0;}
那么编译器会怎样做呢, 它会扩展你的代码, 在你的代码之前添加必要的 default constructor 即:
//你看上去的
Bar::bar(){str = 0;}
//实际可能是
Bar::bar(){Foo::Foo(); str = 0;}
问题又来了, 假如 class 中 有多个 member object 嗷嗷待哺呢?
结果是, 编译器会按照其声明的顺序初始化.
2. 带有 Default Constructor 的 Base Class
我倾向于用一个例子说明问题:
class Member{public: Member(){std::cout << "member ";}}
class Base1 {
public: Base1(){public: std::cout << "base1";}
private: Member m;};
public: Base2(){public: std::cout << "base2";}
private: Member m;};
class Derived:public Base2, public Base1
{public: Derived(){std::cout << "derived";}}
int main(){Derived d; return 0;}
输出结果是:
member //由程序员定义的 Base2::Base2() 被扩展
base2 //由此可见, 调用顺序由继承顺序有关
member
base1
derived //编译器扩展的代码结束, user code 开始运行
前四段代码是编译器在用户定义的 constructor 代码中, std... 之前插入的调用 base constructor 的代码产生的结果, 按照继承的顺序调用相应的 constructor.
3. 带有 Virtual Function 的 Class
在带有 virtual function 的 class 中, 如果缺少合适的 constructor, 编译器会进行两个扩张:
1) 一个 virtual function table 会被创建出来, 内放 class 的 virtual
function 地址
2) 在每一个 class object 中, 一个额外的 pointer member(即 vptr) 会被创建出来, 内含相关的 vtbl 地址
所以编译器会产生一个 default constructor 来初始化 vtbl 与 vptr
4. 带有Virtual Base Class 的 Class
考察以下代码:
struct X{int i;};
struct A:public virtual X{int j;};
struct B public virtual X{int k;};
struct C:public A, public B{double d;}
void Foo(const A *pa){pa->i = 1024;}
int main()
{
Foo(new A);
Foo(new C);
}
编译器无法确定 Foo() 中 _i 的实际 _i 移动的位置, 因为 pa 可以改变, 要延迟到执行期才能固定下来, 因此此动作要通过存取 virtual base class 的相关指针来完成, 因此编译器实际可能做的事情是把函数扩充为:
void Foo()(const A *pa){pa->__vbcX->i = 1024;}
没错, 那么 __vbcX 就需要在 object 被建构之前被初始化, 编译器就需要为它合成一个 default constructor.
新手的误解:
1) 若 class 没有定义一个 default constructor, 那么编译器就会合成一个出来;
2) 编译器合成出来的 default constructor 会明确设定 class 内每一个 data member 的初始值.
当然, 以上观念都是错的!