前言:
在设计派生类的构造函数时,希望执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时被初始化。解决这个问题的思路是:在执行派生类的构造函数时,调用基类的构造函数。
5.1简单的派生类的构造函数
派生类构造函数一般形式为
派生类构造函数名(总参数表):基类构造函数名(参数表)
{
派生类中新增数据成员初始化语句
}
总参数表包括基类构造函数所需的参数和对派生类新增的数据成员初始化所需的参数。
注意:
派生类构造函数名后面的总参数表包括参数名和参数类型,冒号后面的基类构造函数名后面的参数表只有参数名无参数类型,因为这里不是定义基类构造函数,而是调用基类构造函数,因此这里的参数是实参不是形参(实参可以来自总参数表,也可以来自全局变量和常量)
例如
#include <vector>
#include<iostream>
#include <string>
#include <stdio.h>
using namespace std;
class Student
{
public:
Student( int nn, string na, char ss )
{
num = nn;
name = na;
sex = ss;
}
public:
int num;
string name;
char sex;
};
class Studentl:public Student
{
public:
Studentl( int nn, string add, char ss, string nam ):Student( nn, nam, ss )
{
address = add;
}
void OutPut()
{
cout << "num:" << num << endl;
cout << "name: " << name << endl;
cout << "sex: " << sex << endl;
cout << "address: " << address << endl;
}
private:
string address;
};
int main()
{
Studentl s1(1,"nwpu", 'f', "xutian");
s1.OutPut();
return 0;
}
同样也可以将派生类构造函数在类外定义,而在类体中只写该函数的声明:
#include <vector>
#include<iostream>
#include <string>
#include <stdio.h>
using namespace std;
class Student
{
public:
Student( int nn, string na, char ss )
{
num = nn;
name = na;
sex = ss;
}
public:
int num;
string name;
char sex;
};
class Studentl:public Student
{
public:
Studentl( int nn, string add, char ss, string nam );
void OutPut()
{
cout << "num:" << num << endl;
cout << "name: " << name << endl;
cout << "sex: " << sex << endl;
cout << "address: " << address << endl;
}
private:
string address;
};
Studentl::Studentl( int nn, string add, char ss, string nam ):Student( nn, nam, ss )
{
address = add;
}
int main()
{
Studentl s1(1,"nwpu", 'f', "xutian");
s1.OutPut();
return 0;
}
注:
1.在类中对派生类构造函数进行声明时,不包括基类构造函数名(参数表)这一部分。只有定义函数时,才将这一部分列出。
2.调用基类构造函数的实参可以使从派生类构造函数的总参数表中得到的,也可以不从派生类构造函数的总参数表中传递过来,而直接使用常量或者全局变量。例如:
Studentl::Studentl( int nn, string add, char ss, string nam ):Student( 21, "xutian", 'f' )
{
address = add;
}
3.可以利用初始化表对构造函数的数据成员进行初始化,而且可以利用初始化表调用派生类的基类构造函数,实现对基类数据成员的初始化。例如:
Studentl::Studentl( int nn, string add, char ss, string nam ):Student( 21, "xutian", 'f' ),address(add)
{
}
4.执行构造函数的顺序:
先调用基类构造函数再执行派生类构造函数本身。
在派生类构造函数释放时,先执行派生类析构函数,在执行基类析构函数。
5.2有子对象的派生类的构造函数
子对象的定义:
类中的数据成员还可以包含类对象,此时类对象中的内嵌对象称为子对象,即对象中的对象。
子对象的初始化:
是在建立派生类时通过调用派生类构造函数来实现的。
派生类构造函数的任务应该包括以下三部分:
(1)对基类数据成员进行初始化
(2)对子对象数据成员进行初始化
(3)对派生类数据成员进行初始化
定义派生类构造函数的一般形式为
派生类构造函数名(总参数表):基类构造函数名(参数表),子对象名(参数表)
{
派生类中新增数据成员初始化语句
}
例如:
#include <vector>
#include<iostream>
#include <string>
#include <stdio.h>
using namespace std;
class Student
{
public:
Student( int nn, string na, char ss )
{
num = nn;
name = na;
sex = ss;
}
public:
int num;
string name;
char sex;
};
class Studentl:public Student
{
public:
Studentl( int nn, string add, char ss, string nam,int mnn, string monnam, char monsex );
void OutPut()
{
cout << "num:" << num << endl;
cout << "name: " << name << endl;
cout << "sex: " << sex << endl;
cout << "address: " << address << endl;
cout << "monitor's num: "<<monitor.num << endl;
cout << "monitor's name: "<<monitor.name << endl;
cout << "monitor's sex: " << monitor.sex << endl;
}
private:
string address;
Student monitor;
};
Studentl::Studentl( int nn, string add, char ss, string nam,int mnn, string monnam, char monsex ):Student( 21, "xutian", 'f' ),address(add),
monitor( mnn, monnam, monsex )
{
}
int main()
{
Studentl s1(1,"nwpu", 'm', "xutian",21,"lihaobo",'f' );
s1.OutPut();
return 0;
}
执行派生类构造函数的顺序是:
(1)调用基类构造函数
(2)调用子对象构造函数
(3)派生类构造函数本身
5.3多层派生时的构造函数
不需要列出每一层派生类的构造函数,只需写出其上一层派生类(它的直接基类)的构造函数即可。
5.4派生类构造函数的特殊形式
(1)
当不需要对派生类新增的成员进行任何初始操作时,派生类构造函数的函数体可以为空。
此派生类构造函数的作用只是将参数传送给基类构造函数和子对象,并在执行派生类构造函数时调用基类构造函数和子对象的构造函数。
(2)
如果在基类中没有定义构造函数,或定义了没有参数的构造函数,那么,在定义派生类构造函数时可以不写基类构造函数。
如果在基类和子对象类型的声明中都没有定义带参数的构造函数,而且也不需要对派生类自己的数据成员进行初始化,则可以不必显式地定义派生类构造函数。
如果在基类和子对象类型的声明中有定义带参数的构造函数,那么必须显式地定义派生类构造函数。
对于在基类中有构造函数的重载,则根据派生类构造函数的内容决定调用基类的有参的构造函数还是无参的构造函数。