我们知道基类的构造和析构函数派生类不能继承,这就要求派生类要定义自己的相关函数,同时从基类继承的成员初始化仍可通过基类的构造函数来完成。 对派生类初始化时需要对基类的数据成员、派生类新增数据成员和内嵌的其他类对象的数据成员进行初始化。 所以派生类构造函数需要做的工作有:使用传递给派生类的参数,调用基类和内嵌对象成员的构造函数来初始化它他们的数据成员,再添加新语句初始化派生类的新成员。 语法形式为:派生类构造函数表要给出初始化的所有参数(基类,新增,内嵌对象)。然后指名初始化的各参数表(使用默认构造函数的基类没必要给出基类名和其参数表,内嵌对象同理)。各个基类名和内嵌对象可以以任意顺序排列。派生类名::派生类名(参数表):基类名1(参数表1),...基类名m(参数名m), 内嵌对象名(内嵌对象参数表1),...,内嵌对象名n(内嵌对象参数表n) { 初始化派生类新成员的语句; }
需要注意的是:如果基类构造函数有参数,则派生类必须定义构造,将传入参数再传给基类构造进行初始化。如果基类同时定义了默认构造和带参数的构造,则派生类中可以给出基类名及其参数表,也可以不显式给出。
派生类对象调用构造函数的顺序:1、首先调用基类构造,如果有多个基类则按照在派生类中声明时从左到右的顺序。2、如果有内嵌对象成员,则调用其构造,如果有多个,同样按照在派生类的声明顺序。3、调用派生类中构造中的语句。 需要注意的是:基类和内嵌对象成员构造函数的调用顺序和它们在派生类构造函数中出现的顺序无关。也就是说,无论声明顺序怎么样,总是遵循先基类后内嵌的顺序。
#include<iostream> using namespace std; class Base1 { public: Base1(){cout<<"Base1 construct"<<endl;} //默认构造 }; class Base2 { public: Base2(int x){cout<<"Base2 construct"<<x<<endl;} //带参数,派生类构造必须给出基类名和参数表 }; class Base3 { public: Base3(int x){cout<<"Base3 construct"<<x<<endl;} }; class Derived : public Base2,public Base3,public Base1 //公有继承,注意声明顺序 { public: Derived(int i,int j,int k,int l):b2(i),Base3(k),Base2(j),b3(l){}; //遵循先基类后内嵌,同类型的调用依照声明顺序,具体参数值查看参数表 //基类Base2->Base3->Base1 内嵌对象Base1->Base2->Base3 private: Base1 b1; //内嵌成员,注意声明顺序 Base2 b2; Base3 b3; }; int main() { Derived d(1,2,3,4); return 0; } /* 输出结果: Base2 construct2 Base3 construct3 Base1 construct Base1 construct Base2 construct1 Base3 construct4 */