多重继承派生类的构造函数
与单继承中派生类的构造函数类似,多重继承派生类的构造函数不但要对派生类中新增成员完成初始化,还要依次对各基类的继承成员进行初始化。派生类对某个基类构造函数操作的规则与单继承中派生类的构造函数操作规则相同。
多重继承派生类的构造函数定义形式如下所示:
派生类名::派生类构造函数名(参数总表):基类1构造函数名(参数表1), 基类2构造函数名(参数表2), …
{
派生类构造函数体
}
上述定义形式中,派生类构造函数名后面的参数总表包含了其后各个基类构造函数需要的所有参数。多重继承派生类的构造函数需要调用该派生类的所有基类构造函数,并使用派生类构造函数参数列表对应的数据,完成各基类中数据成员的初始化。
从前面的知识了解到,派生类构造函数的调用顺序是先调用基类的构造函数再调用派生类的构造函数,对于多继承的派生类来说,多个基类的构造函数按照定义派生类时的先后顺序,依次调用。
接下来通过一个案例说明多重继承方式下,派生类构造函数的定义及调用形式,如例1所示。
1 #include <iostream>
1 using namespace std;
2
3 class Bird{ //定义鸟类
4 public:
5 Bird(int fh) //定义鸟类带参数的构造函数
6 {
7 cout << "Bird constructor!" << endl;
8 m_nFlightAltitude = fh;
9 }
10 //定义鸟在天空飞的成员函数
11 void fly_in_sky() { cout << "bird fly in sky!" << endl; }
12 //定义鸟呼吸的成员函数
13 void breath() { cout << "bird breath!" << endl; }
14 //定义获取鸟飞行高度的成员函数
15 int get_flightaltitude() { return m_nFlightAltitude; }
16 private:
17 int m_nFlightAltitude;
18 };
19 class Fish //定义鱼类
20 {
21 public:
22 Fish(int speed) //定义鱼类带参数构造函数
23 {
24 cout << "Fish constructor!" << endl;
25 m_nSwimSpeed = speed;
26 }
27 //定义鱼在水里游的成员函数
28 void swim_in_water() { cout << "fish swim in water!" << endl; }
29 //定义鱼呼吸的成员函数
30 void breath() { cout << "fish breath!" << endl; }
31 //定义获取游速的成员函数
32 int get_swimspeed() { return m_nSwimSpeed; }
33 private:
34 int m_nSwimSpeed;
35 };
36 //定义派生类-水鸟类,继承自基类Bird、Fish
37 class WaterBird:public Bird, public Fish
38 {
39 public:
40 //定义水鸟类带参数的构造函数,其中调用基类的构造函数
41 WaterBird(int fh, int speed):Bird(fh), Fish(speed)
42 {
43 cout << "WaterBird constructor!" << endl;
44 }
45 //定义水鸟行为的成员函数
46 void fly_swim() { cout << "waterbird cat fly and swim!" << endl; }
47 //定义水鸟呼吸的成员函数
48 void breath(){ cout << "waterbird breath!" << endl; }
49 };
50 int main()
51 {
52 WaterBird waterbird(20, 30); //定义水鸟对象
53 //调用get_flightaltitude()函数,显示水鸟飞行高度
54 cout << "waterbird flight altitude: " << waterbird.get_flightaltitude();
55 //调用get_swimspeed()函数,显示水鸟游速
56 cout << ", swimming speed:" << waterbird.get_swimspeed() << endl;
57 system("pause");
58 return 0;
59 }
程序运行结果如图1所示。
图1 例1运行结果
例1通过多重继承方式定义了派生类WaterBird。main()函数中定义派生类对象waterbird时会调用第42行定义的带参数的构造函数,完成数据成员初始化。要初始化的这两个数据成员m_nFlightAltitude、m_nSwimSpeed来自基类Bird、Fish,派生类构造函数通过调用基类的构造函数完成数据成员的初始化。从运行结果看,按照派生类定义时列出的基类名称先后顺序,先调用了Bird类的构造函数,再调用Fish类的构造函数,最后调用了派生类的构造函数。
除了上面介绍的多重继承派生类的构造函数外,派生类中新增加的成员还可以是类对象。假如派生类是多重继承,并且新增数据成员有一个或多个对象成员,那么派生类需要初始化的数据有三部分:继承的数据成员、新增类对象的成员和新增普通成员。
这种复杂派生类的构造函数定义形式如下所示:
派生类名::派生类构造函数名(参数列表):基类1构造函数名(参数表1), 基类2构造函数名(参数表2), …子对象名1(参数表n), 子对象名2(参数表n + 1)
{
派生类新增普通数据成员的初始化
}
接下来通过一个案例说明带有对象成员的派生类构造函数的定义及使用方法,如例2所示。
例2
1 #include <iostream>
2 using namespace std;
3
1 class Date{ //定义日期类
2 public:
3 Date(int con_year, int con_month, int con_day); //声明构造函数
4 //显示年月日信息的函数print_date()
5 void print_date(){ cout << m_nYear << "-" << m_nMonth << "-" << m_nDay << endl; }
6 private:
7 int m_nYear, m_nMonth, m_nDay;
8 };
9 Date::Date(int con_year, int con_month, int con_day) //定义日期类构造函数
10 {
11 cout << "Date constructor!" << endl;
12 m_nYear = con_year;
13 m_nMonth = con_month;
14 m_nDay = con_day;
15 }
16 class Bird //定义鸟类
17 {
18 public:
19 Bird(int fh) //定义鸟类带参数的构造函数
20 {
21 cout << "Bird constructor!" << endl;
22 m_nFlightAltitude = fh;
23 }
24 private:
25 int m_nFlightAltitude;
26 };
27 class Fish //定义鱼类
28 {
29 public:
30 Fish(int speed) //定义鱼类带参数构造函数
31 {
32 cout << "Fish constructor!" << endl;
33 m_nSwimSpeed = speed;
34 }
35 private:
36 int m_nSwimSpeed;
37 };
38 class WaterBird:public Bird,public Fish //定义水鸟类
39 {
40 public:
41 //定义派生类构造函数,函数的前三个参数用于为本类数据成员m_iBirthday提供初值
42 //m_iBirthday的初始化在初始化列表中完成
43 WaterBird(int year, int month, int day, int fh, int speed):Bird(fh),
44 Fish(speed),m_iBirthday(year, month, day)
45 {
46 cout << "WaterBird constructor!" << endl;
47 }
48 void print_birthday()
49 {
50 m_iBirthday.print_date();
51 }
52 private:
53 //定义Date类对象为WaterBird类的数据成员
54 Date m_iBirthday;
55 };
56 int main()
57 {
58 WaterBird waterbird(2010, 5, 1, 20, 30); //定义水鸟对象并提供参数
59 cout << "waterbird birthday:";
60 waterbird.print_birthday();
61 system("pause");
62 return 0;
63 }
程序运行结果如图2所示。
图2 例2运行结果
例2中,派生类定义了一个Date类数据成员m_iBirthday,对该成员的初始化在构造函数的初始化列表中完成。从运行结果看,先调用了基类的构造函数,再调用对象成员m_iBirthday的构造函数,最后调用了派生类的构造函数。
从上面的案例中,可以总结派生类构造函数的调用顺序如下所述:
● 首先调用基类构造函数。按它们在派生类中定义的先后顺序,依次调用。
● 其次调用对象成员的构造函数。按它们在派生类中定义的先后顺序,依次调用。
● 最后调用派生类的构造函数。
多重继承派生类、复杂派生类的析构函数只需要编写对新增普通成员的善后处理,而对类对象和基类的善后处理工作是由类对象和基类的析构函数完成的。析构函数的调用顺序与构造函数相反。