#include <iostream>
using namespace std;
class A
{
private:
int a;
public:
A(int x):a(x) { cout <<a <<" "; }
};
class B: A
{
private:
int b, c;
const int d;
A x, y;
public:
B(int v): b(v),y(b+2),x(b+1),d(b),A(v)
{
c=v;
cout <<b <<" " <<c <<" " <<d;
}
};
int main(void)
{
B z(1);
return 0;
}
1.定义一个派生类对象,首先初始化它的基类成员(基类部分)
即调用基类的构造函数(如果是多继承,则按继承的先后顺序调用基类的构造函数)
2.基类部分初始化完之后,初始化派生类部分,派生类的成员初始化依赖它的声明顺序
并不依赖它的初始化列表的顺序初始化派生类成员,总结来说:就是派生类成员的初始化
依赖它的声明顺序而不是依赖初始化列表的顺序。
3.调用派生类的构造函数,可以理解为就是执行派生类构造函数的函数体而已
4.特别注意:但是,请注意:上面两点调用构造函数或者其他的参数传递是参考初始化列表给出的参数的
详细解释:
首先:B z(1);则依据1,调用基类的构造函数,但是这里不知道该调用基类的哪个构造函数
因为基类有默认的构造函数(即没有参数)和你定义的A(int x)这个构造函数,所以,编译器
要进行选择。依据4,参考到初始化列表b(v),y(b+2),x(b+1),d(b),A(v)中有A(v),所以编译器
选择调用你定义的构造函数A(int x),所以打印输出a的值,输出 1,然后,依据2,派生类自身定义的
部分是按它的定义顺序初始化的,即按下面这个顺序,b,c,d,x,y.
int b, c;
const int d;
A x, y;
所以,依据4,分别参考初始化列表b(v),y(b+2),x(b+1),d(b),A(v) 给出的参数信息,可知道
初始化b,使用b(v),b被初始化为1。然后,初始化c,由于初始化列表中没有指定c的初始化,所以
暂时c不被初始化,然后初始化d,根据初始化列表中的d(b),d被初始化为b的值,即为1。然后初始化
A类对象x和y,依据初始化列表中的x(b+1)初始化x,由于b的值为1,所以即相当于x(2),给除了一个参数
2,则调用你定义的构造函数A(int x),打印输出类A的x对象中的a的值,即输出2,同理,依据y(b+2)
初始化y,打印输出3。
最后,依据3,调用派生类构造函数,即
B(int v)
{
c=v;
cout <<b <<" " <<c <<" " <<d;
}
这时,直接忽略初始化列表了,执行这个派生类的构造函数,那么执行函数体
c=v;则把那个没初始化的c被赋值为v的值,即c的值为1。最后打印输出b和c的值
所以再输出两个1。
综上所述:输出1 2 3 1 1 1