咱们来看下面一段代码:ios
class B1 { public: B1(int i) {cout<<"constructing B1 "<<i<<endl;} }; class B2 { public: B2(int j) {cout<<"constructing B2 "<<j<<endl;} }; class B3 { public: B3( ){cout<<"constructing B3 *"<<endl;} }; class C: public B2, public B1, public B3 { public: C(int a, int b, int c, int d):B1(a),memberB2(d),memberB1(c),B2(b){} private: B1 memberB1; B2 memberB2; B3 memberB3; }; void main( ) { C obj(1,2,3,4); }
运行后的结果以下:
constructing B2 2
constructing B1 1
constructing B3 *
constructing B1 3
constructing B2 4函数
constructing B3 *
为何会有以上的结果?
众所周知构造函数的执行次序以下:
调用基类构造函数,调用顺序按照他们的继承时声明的顺序。
调用内嵌成员对象的构造函数,调用顺序按照他们在类中声明的顺序。
派生类的构造函数体中的内容。
析构函数的调用顺序相反。
那么再来看以上的例子就很容易理解了。B二、B一、B3是C的基类,按照上述的顺序,咱们先要构造基类,而后才是子对象,最后是其自己的构造函数因此先要执行这三个类的构造函数。在构造时按照他们在类中的顺序,首先调用B2的构造函数
B2(int j) {cout<<"constructing B2 "<<j<<endl;}
因为在默认参数列表
C(int a, int b, int c, int d):B1(a),memberB2(d),memberB1(c),B2(b){}
中,将b的值传给了B2的构造函数,b为2,故打印出:
constructing B2 2
接下来要构造的是B1了。显然在C的默认参数构造列表中将a的值传给了B1,
因此打印出:
constructing B1 1
B3在构造时没有传递参数,调用B3( ){cout<<"constructing B3 *"<<endl;}
打印出:
cout<<"constructing B3 *
这时基类的构造函数已经执行完毕,接着该处理内嵌成员对象的构造函数了。spa
咱们看到C类有三个对象:B1 memberB1;B2 memberB2;B3 memberB3;,按照构造函数的调用顺序,咱们须要按照他们在类中声明的顺序来分别构造memberB一、memberB二、 memberB3。在默认的参数列表中,用c来构造了memberB1,用d来构造memberB2,
故打印出:
constructing B1 3
constructing B2 4
constructing B3 *
最后调用自己的构造函数,因为函数体为空,故什么也没有打印出来。
总结下来,咱们必须明确的是当一个类继承与基类,而且自身还包含有其余类的成员对象的时候,构造函数的调用顺序为:调用基类的构造函数->调用成员对象的构造函数->调用自身的构造函数。构造函数的调用次序彻底不受构造函数初始化列表的表达式中的次序影响,与基类的声明次数和成员对象在函数中的声明次序有关。
再如:code
#include<iostream.h> class A { protected: char c; public: A(char ch) { c=ch; cout<<"c="<<c<<endl; cout<<"类A构造函数被调用"<<endl; } ~A() { cout<<"类A析构函数被调用"<<endl; } }; class B { protected: int i; public: B(int j) { i=j; cout<<"i="<<i<<endl; cout<<"类B构造函数被调用"<<endl; } ~B() { cout<<"类B析构函数被调用"<<endl; } }; class C:public A,B { private: int k; public: C(char ch,int ii,int kk):A(ch),B(ii),k(kk) { cout<<"k="<<k<<endl; cout<<"类C构造函数被调用"<<endl; } ~C() { cout<<"类C析构函数被调用"<<endl; } }; void main() { C A('B',10,15); }
输出结果:
c=B
类A构造函数被调用
i=10
类B构造函数被调用
k=15
类C构造函数被调用
类C析构函数被调用
类B析构函数被调用
类A析构函数被调用对象