构造函数
前面介绍过,构造函数是为了初始化类中的数据成员,对于派生类而言,不会继承基类的构造函数,因此为了完成派生类数据成员的初始化,需要在派生类中自己定义构造函数。派生类的构造函数中除了要初始化派生类中新增的数据成员外,还需要初始化基类的数据成员,即派生类的构造函数要负责调用基类的构造函数。
若程序中不显式定义构造函数,则创建派生类对象时会调用编译器提供的默认构造函数。若想调用基类中带参数的构造函数,则派生类需自定义带参数的构造函数,以便向基类构造函数传递参数。派生类中定义带参数构造函数的形式如下所示:
派生类名::派生类构造函数名(参数列表):基类构造函数名(基类构造函数参数表)
{
派生类新增成员的初始化语句
}
从上述定义形式看出,通过在构造函数参数表后添加冒号“:”和基类构造函数名称及参数表,派生类中完成了基类数据成员的初始化操作,可见继承自基类的数据成员的初始化通过基类构造函数完成。接下来通过一个案例说明派生类构造函数的定义及使用,如例1所示。
1 #include <iostream>
2 using namespace std;
3
4 class Animal //定义基类
5 {
6 public:
7 Animal(int con_weight, int con_age); //声明带参数的构造函数
8 private:
9 int m_nWeight;
10 int m_nAge;
11 };
12 Animal::Animal(int con_weight, int con_age) //定义基类带参数的构造函数
13 {
14 m_nWeight = con_weight;
15 m_nAge = con_age;
16 cout << "Animal constructor with param!" << endl;
17 }
18 class Cat:public Animal
19 { //定义派生类
20 public:
21 //声明派生类带参数的构造函数
22 Cat(string con_name, int con_weight, int con_age);
23 private:
24 string m_strName;
25 };
26 /*
27 * 定义派生类带参数的构造函数,三个参数中,第一个参数用于对派生类私有成员m_strName进行初始化,
28 * 第二个、第三个参数用于基类数据成员的初始化
29 */
30 Cat::Cat(string con_name, int con_weight, int con_age):Animal(con_weight, con_age)
31 {
32 m_strName = con_name;
33 cout << "Cat constructor with param!" << endl;
34 }
35 int main()
36 {
37 Cat cat("Persian", 5, 7); //创建派生类对象
38 system("pause");
39 return 0;
40 }
程序运行结果如图1所示。
图1 例1运行结果
例1中编写派生类带参数的构造函数时,参数列表中提供了对基类数据成员和派生类数据成员进行初始化的参数,通过调用基类带参数的构造函数完成基类数据的初始化。从运行结果看出,创建派生类对象时,首先调用基类的构造函数,然后再调用派生类的构造函数。
关于派生类构造函数的定义,还有以下几点需要说明:
1、 派生类构造函数名后面括号内的参数列表中,应包含基类和派生类构造函数,需要进行初始化的所有数据成员的参数值。冒号后面的内容是要调用的基类构造函数及其参数,在这里是对基类构造函数的调用,因此参数为实参,不需要有类型名,基类构造函数后面的内容还可以是常量、全局变量。例如,Cat类的构造函数也可定义成如下形式,基类的数据成员使用常量进行初始化,具体代码如下所示:
//派生类构造函数,调用基类函数时提供了常量值,不需要使用派生类构造函数的参数
Cat::Cat(string con_name):Animal(3, 4)
{
name = con_name;
cout << "Cat constructor with param!" << endl;
}
2、 虽然公有派生类的构造函数中可以直接访问基类的公有和保护数据成员,甚至可以在构造时初始化它们,但是一般不这样做,而是通过基类的接口(即成员函数)去访问他们,初始化也是通过基类的构造函数,这样可以减少类之间的耦合性。
3、 若基类没有构造函数或仅存在无参构造函数,则在派生类构造函数的定义中可以省略对基类构造函数的调用。
4、 当基类的构造函数使用一个或多个参数时,派生类中必须定义构造函数,提供将参数传递给基类构造函数的方法,从而实现对基类数据成员的初始化。此时,派生类的构造函数体可能为空,仅仅为了向基类传递数据。下面代码中,派生类构造函数参数是传递给基类构造函数的,具体代码如下所示:
class Animal{ //定义基类
public:
//定义基类构造函数
Animal(int con_weight, int con_age):m_nWeight(con_weight), m_nAge(con_age)
{
}
private:
int m_nWeight;
int m_nAge;
};
class Cat:public Animal{ //定义派生类
public:
//定义派生类构造函数
Cat(int weight, int age):m_strName("Persian"), Animal(weight, age)
{
}
private:
string m_strName;
};