1、构造函数调用顺序
当一个类继承与基类,并且自身还包含有其他类的成员对象的时候,
构造函数的调用顺序为:
1)调用基类的构造函数,调用顺序按照他们的继承时声明的顺序
2)调用成员对象的构造函数,调用顺序按照他们在类中声明的顺序
3)调用自身的构造函数
构造函数的调用次序完全不受构造函数初始化列表的表达式中的次序影响,与基类的声明次数和成员对象在函数中的声明次序有关。
代码如下:
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);
}
运行后的结果如下:
分析如下:
(1)基类的构造函数
B2、B1、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
所以打印出:
constructing B1 1
B3在构造时没有传递参数,调用B3(){cout<<"constructing B3 *"<<endl;}
打印:constructing B3 *
(2)内嵌成员对象的构造函数
这时基类的构造函数已经执行完毕,接着该处理内嵌成员对象的构造函数了。C类有三个成员对象:B1 memberB1;B2 memberB2;B3 memberB3;,按照构造函数的调用顺序,需要按照他们在类中声明的顺序来分别构造memberB1、memberB2、 memberB3。在默认的参数列表中,用c来构造了memberB1,用d来构造memberB2,
故打印出:
(3)调用本身的构造函数
由于函数体为空,故什么也没有打印出来。
2、析构函数调用顺序
析构函数的调用顺序是跟构造函数的相反:
1)调用自身的析构函数
2)调用成员对象的析构函数(跟声明顺序相反)
3)调用基类的析构函数(跟声明顺序相反)
#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 c('B',10,15);
}
输出结果:
c=B
类A构造函数被调用
i=10
类B构造函数被调用
k=15
类C构造函数被调用
类C析构函数被调用
类B析构函数被调用
类A析构函数被调用