(根据《C++程序设计》(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明)
由于基类的构造函数和析构函数是不能被继承的,所以在声明派生类时,需要我们自己定义派生类的构造函数和析构函数。
1 派生类的构造函数
在设计派生类的构造函数时,不仅要考虑派生类所增加的数据成员的初始化,还要考虑基类的数据成员的初始化。也就是说,
希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。解决这个问题的思路是:在执行派生类的构造函数时,调用基类的构造函数。
1.1 简单派生类的构造函数
简单的派生类只有一个基类,只有一级派生,且在派生类的数据成员中不包含基类的对象。通过具体的例子定义简单派生类的构造函数:
1: class Student //声明基类Student
2: {
3: public:
4: Student( int n , string nam , char s ) //定义基类的析构函数
5: {
6: num = n ;
7: name = nam ;
8: sex = s ;
9: }
10: ~Student(){} //基类的析构函数
11: protected:
12: int num ;
13: string name ;
14: char sex ;
15: };
16:
17: class Student1 : public Student //声明公用派生类Student1
18: {
19: public:
20: Student1( int n , string nam , char s , int a , string ad ) : Student( n , nam ,s )
21: //定义派生类的构造函数
22: //在函数体内只对派生类新增的数据成员初始化
23: {
24: age = a ;
25: addr = ad ;
26: }
27: ~Student1(){} //派生类的析构函数
28: private:
29: int age ;
30: string addr ;
31: };
请大家注意派生类构造函数首行的写法:
Student1( int n , string nam , char s , int a , string ad ) : Student( n , nam ,s )
Student1( int n , string nam , char s , int a , string ad ) ;
Student1 :: Student1 (int n , string nam , char s , int a , string ad ): Student( n, nam ,s )
{
age = a ;
addr = ad ;
}
1.2 有子对象的派生类的构造函数
类中的数据成员除了标准型(int, char等)或系统提供的类型(如string)外,类中的数据成员还可以包括类的对象,例如以上例为基础,可以在声明一个类时包含这样的数据成员:
Student s1 ; //Student是已声明的类名,s1是Student类的对象
1: class Student //声明基类,为简化,在上例的基础上去掉成员变量 char sex
2: {
3: public:
4: Student ( int n , string nam )
5: {
6: ...
7: }
8: ...
9: };
10:
11: class Student1 : public Student //声明公用的派生类
12: {
13: public:
14: Student1 ( int n , string nam , int n1 , string nam1 , int a , string ad )
15: : Student ( n , nam ) , monitor ( n1 , nam1 ) //派生类的构造函数
16: {
17: age = a ;
18: addr = ad ;
19: }
20: private:
21: Student monitor ; //派生类中含有基类的对象
22: int age ;
23: string addr ;
24: };
1.3 多层派生时的构造函数
一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构。通过例子来说明:
1: class Student //声明基类
2: {
3: public:
4: Student ( int n , string nam ) //基类的构造函数
5: {
6: num = n ;
7: name = nam ;
8: }
9: protected: //基类的保护数据成员
10: int num ;
11: string name ;
12: };
13:
14: class Student1 : public Student //声明公用派生类Student1
15: {
16: Student1 ( int n , string nam , int a ): Student( n ,nam ) //派生类的构造函数
17: {
18: age = a ; //函数体内只对新增的数据成员初始化
19: }
20: private: //派生类的私有数据成员
21: int age ;
22: };
23:
24: Student2 : public Student1 //声明间接公用派生类Student2
25: {
26: public:
27: Student2(int n ,string nam , int a , int s ): Student1( n , nam ,a ) //间接派生类的构造函数
28: {
29: score = s ; //函数体内只对新增的数据成员初始化
30: }
31: private:
32: int score ; //间接派生类新增数据成员
33: };
Student2( int n , string nam , int a , int s ):Student1( n , nam , a )
Student2( int n , string nam , int a , int s ) : Student( n , nam ),Student1(n , nam , a )
1.4 派生类构造函数的特殊形式
有两种特殊形式:
(1)当不需要对派生类新增的数据成员进行任何的初始化操作时,派生类构造函数的函数体可以为空。此时派生类构造函数的作用只是为了将参数传递给基类的构造函数和子对象,并在执行派生类的构造函数时调用基类的构造函数和子对象的构造函数。
(2)如果在基类中没有定义构造函数,或是定义了没有参数的构造函数,那么,在定义派生类的构造函数时可以不写基类的构造函数。在调用派生类的构造函数时,系统会自动首先调用基类的默认构造函数。
2 派生类的析构函数
析构函数的作用是在对象撤销之前,进行必要的清理工作。同样的,派生类是不能继承基类的析构函数的,也需要通过派生类的析构函数去调用基类的析构函数。在派生类中可以根据需要定义自己的虚构函数,用来对派生类中所增加的数据成员进行清理工作。基类的清理工作仍然由基类的析构函数负责,系统会自动调用基类的析构函数和子对象的析构函数,对基类和子对象进行清理。
调用的顺序与构造函数相反:先执行派生类自己的析构函数,对派生类新增加的成员进行清理,然后调用子对象的析构函数,对子对象进行清理,最后调用基类的析构函数,对基类进行清理。