首先,本篇文章只讲 “默认构造函数”,即如你所知,默认构造函数是不带参数的构造函数。
编译器会在 适当的时候 为class合成一个默认构造函数 ~~
先问以下两个问题:
1 编译器会为任何没有声明构造函数的class,合成默认构造函数?? 错!!!
2 合成的默认构造函数会显示设定class内的每一个data member的默认值?? 错!!!
class Base
{
public:
int x;
int getX() const {return x;};
};
int main()
{
Base b;
cout << b.getX() << endl;
return 0;
}
结果不如人意,getX的输出值完全是随机的。
编译器的动作,是仅限于自己的责任,类的设计者如果需要为类的所有成员进行初始化,那么自己动手吧!!
编译器的动作是隐式的,因此,了解什么时候算是 “适当的时候”??
以下的4个方面是编译器的所谓的适当的时候。。。
1 带有“默认构造函数”的类成员对象。
就是说,如果类A的一个对象a作为类B的成员变量,并且类B没有定义构造函数,但是类A有自己的默认构造函数,那么,在定义类B的对象时,编译器会为类B合成一个默认构造函数。因为在创建类B的对象时,期间必须调用类A的默认构造函数初始化a。
例如:
class Base
{
public:
Base()
{
cout << "call Base default constructor..." << endl;
}
virtual ~Base(){}
};
class Base2
{
public:
Base2(){cout << "call Base2 default constructor..." << endl;}
};
class Derived
{
private:
Base2 b2;
Base b;
int x;
public:
//Derived(int _x){ x = _x; }
~Derived(){}
};
int main()
{
Derived d;
return 0;
}
执行结果为:
可以看到,成员变量b2和b的默认构造函数被调用,并且是按照其声明次序。
2 带有默认构造函数的基类
就是说。如果类Derived继承自类Base,但是Base类定义默认构造函数的话,分两种情况:
1 如果这个Derived类没有定义构造函数,那么编译器必定会为其合成一个,因为此时的默认构造函数将不是trivial的,因此必须将它合成,用于初始化基类。
2 如果Derived类定义了自己版本的构造函数,这其中并没有默认构造函数,那么在这些定义的构造函数调用之前,还是会调用基类的默认构造函数。(意味着先调用基类的默认构造函数,再调用自身的构造函数)。
如下:
class Base
{
public:
Base()
{
cout << "call Base default constructor..." << endl;
}
virtual ~Base(){}
};
class Base2
{
public:
Base2(){cout << "call Base2 default constructor..." << endl;}
virtual ~Base2(){}
};
class Member
{
public:
Member(){cout << "call Member default constructor..." << endl;}
};
class Derived : public Base, public Base2
{
private:
int x;
Member m;
string str;
public:
Derived(int _x):x(_x){}
Derived(string _str):str(_str){}
~Derived(){}
};
int main()
{
Derived d(0);
return 0;
}
执行结果为:
可以看到,在Derived类中并没有默认构造函数,但是当我们使用 "以int作为参数的构造函数"时,其基类的默认构造函数被调用(按声明次序),调用完成之后,如果还有成员对象,再调用该类的默认构造函数(如此处的Member).
3 带有 ”虚函数“的类
也就是说,如果一个class继承一个虚函数,或者是一个类的继承体系中含有 virtual继承。如果用户没有定义构造函数,那么编译器会合成。
如下:
class Base
{
private:
int x;
public:
Base(){cout << "call Base default ctor..." << endl;}
virtual void vCall(){cout << "virtual call in Base..." << endl;}
virtual ~Base(){}
};
class Derived:public Base
{
private:
int x ;
public:
void vCall(){x=1;cout << "virtual call in Derived..." << endl;}
};
void vCall(Base &b)
{
b.vCall();
}
int main()
{
Derived d;
vCall(d);
return 0;
}