一:默认构造函数的构建
默认构造函数总是在被需要的时候构建出来!!关键字“被需要的时候”!!
class Foo
{
public:
int val;
Foo *next;
};
void foo_bar()
{
Foo bar;
if(bar.val || bar.next)
//do something
}
上述的代码,编写者意图对象bar中的data member val 和 next 为0。但是编译器没有义务为你初始化为。首先对于堆栈中的变量都不一定会被初始化为0,而是上一次使用的痕迹。
对于Class Foo,如果没有任何的user-declared constructor,那么就会有一个default constructor被暗中声明出来,而一个被暗中声明出来的构造函数将是一个无用的构造函数,所以上面的代码休想正确运行。
所以,在生命class Foo对象bar的时候,编译器确实会隐性的声明默认构造函数,但是这个构造函数是无用的。只有在四种情况下,才会生成有用(nontrival default constructor)的构造函数。
1: 带有"Default Constructor" Member class object。
如果一个class没有任何的constructor,但是包含的member object 确有default construct,那么编译器为这个class隐形生成的构造函数将是nontrival即有用的,并且会在需要的时候调用发生。
2: 带有"Default Constructor" 的 Class Base
如果一个derived class没有任何constructor,但是继承自一个有default constructor的base class,那么这个derived class的构造函数将会是有用的,并且在被需要的时候生成出来,依照继承顺序调用基类的构造函数。
3: 带有一个"virtual function“ 的 Class
class Widget
{
public:
virtual int flip() = 0;
//..
};
void flip(const Widget* widget )
{
widget->flip();
}
void main()
{
Bell bell;
Whistle w;
flip(bell);
flip(w);
}
上述代码中,class Bell 和 Whistle均继承自Widget,在声明bell 和 w的时候,编译器隐形生成的默认构造函数会被调用。因为在基类Widget中有virtual function ,所有带Widget的对象模型中会有指向virtual table 的地址;而在子类class Bell和 Whistle总,这个指针同样需要被制定。
4: 带有一个“virtual base class” 的Class
对于不同的编译器,virtual base class在derived class object中的实现方式差别很大;但是共同点是virtual base class 必须在 derived class object 中的位置,能够在执行期间安置妥当,例如下面的代码:
class X { public int x; };
class A:public virtual X{public int j;};
class B:public virtual X{public float k;}
class C:public A,public B{public float g;};
//无法在编译期间确定x的位置
void foo(const A* pa)
{
pa->x = 1024;
}
void main()
{
foo(new B);
foo(new C);
}
为了在运行期间确定x的位置,我们必须做延迟处理:
void foo(const A* pa) { pa->_vbcX->x = 1024; }
其中_vbcX 即是只想virtual base class的指针, 正如你所想的_vbcX正是在构造函数被调用的时候制定的。所以对于没有默认构造函数的带有virtual base class的class object,编译器会在隐性生成的构造函数中指定!