10.5 派生类的构造函数和析构函数

    派生时,构造函数和释放函数是不能继承的,对派生类必须重新定义构造函数和析构函数,由于派生类对象中包含了基类数据成员的值,因此,创建派生类对象时,系统首先通过派生类的构造函数来调用基类的构造函数,完成基类成员的初始化,而后对派生类中新增的成员进行初始化。

    10.5.1 派生类的构造函数

    派生类构造函数的一般格式如下所示。


    派生类名(派生类构造函数参数表):基类构造函数(基类构造函数参数表) { //函数体 };

    必须将基类的构造函数放在派生类的初始化表达式中,以调用基类构造函数完成基类数据成员的初始化,派生类构造函数实现的功能,或者说调用顺序如下所述。

    ❑完成对象所占整块内存的开辟,由系统在调用构造函数时自动完成。

    ❑调用基类的构造函数完成基类成员的初始化。

    ❑若派生类中含对象成员、const成员或引用成员,则必须在初始化表中完成其初始化。

    ❑派生类构造函数体执行。

    代码10.5 派生类构造函数的调用顺序CallSequence


    <——————————文件名:example1005.cpp————————————————-> 01 #include<iostream> 02 using namespace std; 03 class A//类A的定义 04 { 05 private://private成员列表 06 int x; 07 public: 08 A(int xp=0)//构造函数,带默认参数 09 { 10 x=xp; 11 cout<<"A的构造函数被执行"<<endl; 12 } 13 }; 14 class B//类B定义 15 { 16 public: 17 B()//无参构造函数 18 { 19 cout<<"B的构造函数被执行"<<endl; 20 } 21 }; 22 class C:public A//类C由类A派生而来 23 { 24 private: 25 int y; 26 B b; 27 public: 28 C(int xp,int yp):A(xp),b()//构造函数,基类构造函数在初始化表中调用 29 { 30 y=yp; 31 cout<<"C的构造函数被执行"<<endl; 32 } 33 }; 34 int main() 35 { 36 C expC(1,2);//创建类C对象expC 37 return 0; 38 }

    输出结果如下所示。

    A的构造函数被执行

    B的构造函数被执行

    C的构造函数被执行

    【代码解析】代码10.5先定义了类A和类B,代码第22行,在A的基础上派生了类C,同时,C中还添加了一个B类型的对象成员,类C的构造函数如下所示。


    C(int x,int y):A(x),b()

    其中,C为派生类名,总参数表中共用2个参数,参数x用来初始化基类的数据成员,参数y用来初始化类C中新增数据成员y。除了要在初始化表达式中调用类A的构造函数外,类C对象成员b的初始化也要放在初始化表达式中进行。

    程序的输出结果印证了前面关于构造函数步骤执行顺序的论述,特别要说明的是,如果基类中采用的是系统提供的默认构造函数,或定义了无参构造函数(包括所有参数都有默认值的构造函数),基类的构造函数调用可省略,此时,系统调用默认的基类构造函数完成基类成员的初始化。

    也就是说,对代码10.5来说,由于类A提供了如下构造函数。


    A(int xp=0)类B也提供了无参构造函数,因此,此处类C的构造函数可写为如下形式。 C(int y) { y=yp; }

    但此时程序的输出结果不变,也就是说,系统仍会调用基类和对象成员的构造函数。

    注意

    派生类的构造函数调用的是基类的构造函数,初始化表达式中是构造函数表达式,而对象成员在初始化时,初始化表达式中是对象名及初始化参数。