一、派生类的构造函数
首先明白一点,在声明派生类时,派生类并没有把基类的构造函数继承过来。所以,派生类构造函数不仅要负责其新增成员的的初始化,还要考虑基类数据成员的初始化。
解决此问题思路:在执行派生类的构造函数时,调用基类的构造函数。
先来看看简单派生类的构造函数
<span style="font-size:18px;">class Student
{
public:
Student(int n, string nam, char s)
{
num = n;
name = nam;
sex = s;
}
private:
int num;
string name;
char sex;
};
class student1: public Student
{
public:
student1(int n,string nam,char s,int Age) :Student(n,nam,s)
{
age = Age;
}
private:
int age;
int tel
};
</span>
其一般形式为:
派生类构造函数名(总参数表):基类构造函数名(参数表)
{派生类中新增数据成员初始化列表}
冒号: 前边部分是派生类构造函数的主干,其参数总列表包括基类构造函数所需的参数和对派生类新增的数据成员初始化所需的参数
后边部分是要调用的基类构造函数及其参数。
我们可以看到,派生类构造函数名后边括号内的参数表列包括参数类型和参数名,而基类构造函数后边的括号内只有参数名而不包括参数类型。
原因是:这里不是定义基类构造函数,而是调用!这些参数是实参 而不是形参。
二、有子对象的的派生类的构造函数
子对象:对象中的对象
<span style="font-size:18px;">class Student
{
public:
Student(int n, string nam)
{
num = n;
name = nam;
}
private:
int num;
string name;
};
class student1: public Student
{
public:
student1(int n,string nam,int n1,string nam1,int Age) :Student(n,nam),monitor(n1,nam1)
{
age = Age;
}
private:
int age;
Student monitor;
};
</span>
这里出现了对子对象的初始化,不能再声明派生类时对他初始化(类是抽象类型,只是一个模型,不能有具体的数据)
每一个派生类对象的子对象一般是不同的,因此子对象的初始化是在建立派生类时通过调用派生类构造函数实现的。
派生类构造函数的任务:
1、对基类数据成员初始化
2、对子对象数据成员初始化
3、对派生类数据成员初始化
student1(intn,stringnam,intn1,stringnam1,intAge) :Student(n,nam),monitor(n1,nam1)
五个形参,前两个作为基类构造函数参数,中间两个作为子对象构造函数参数(子对象是Student类,在建立对象也是调用基类构造函数),第五个作为派生类数据成员初始化的。
一般形式:
派生类构造函数名(总参列表):基类构造函数名(参数表),子对象名(参数表)
{派生类中新增数据成员初始化语句}
执行派生类构造函数顺序:
1、调用基类构造函数,对基类数据成员初始化;
2、在调用子对象构造函数,对子对象数据成员初始化;
3、在执行派生类构造函数本身,对派生类数据成员初始化;
多个子对象,派生类构造函数写法以此类推!
三、多层派生的构造函数
<span style="font-size:18px;">class Student
{
public:
Student(int n, string nam)
{
num = n;
name = nam;
}
private:
int num;
string name;
};
class student1: public Student
{
public:
student1(int n,string nam,int Age) :Student(n,nam)
{
age = Age;
}
private:
int age;
};
class student2:public student1
{
public:
student2(int n, char nam[10], int Age, int s) : student1(n, nam, Age)
{
score = s;
}
private:
int score;
};
</span>
注意:只需写出直接基类的构造函数
在声明student2 对象时,调用student2 构造函数;在执行期间,先调用student1 构造函数,在执行期间,又先调用Student构造函数
初始化顺序:
1、先初始化基类数据成员
2、再初始化student1的数据成员
3、再初始化student2 的数据成员
四、派生类构造函数的 特殊形式
1、当不需要对派生类新增成员进行任何初始操作时,派生类构造函数体可为空 列:
student1(int n,string nam,int n1,string nam1):Student(n,nam),monitor(n1,nam1)
{ }
此时,派生类构造函数不对派生类数据成员初始化。其作用只是为了将参数传递给基类构造函数和子对象,并在执行时调用基类的构造函数和子对象的构造函数
2、如果在基类中没有定义构造函数,或者定义了没有参数的构造函数,那么在定义派生类构造函数时可以不写基类构造函数。因为此时派生类构造函数没有向基类构造函数传递参数任务。在调用派生类构造函数时,系统会自动调用基类默认构造函数。
3、如果在基类和子对象类型的声明中都没有定义带参数的构造函数,而且也不需要对派生类自己的数据成员初始化,则可以不必显示定义派生类构造函数。
4、如果在基类或子对象类型的声明中定义了带参数的构造函数,那么就必须显示的定义派生类构造函数,并且在派生类构造函数中写出基类或子对象类型的构造函数及其参数列表。
5、如果在基类中定义无参的构造函数,又定义了有参的构造函数(构造函数重载),则在定义派生类构造函数时,既可以包含基类构造函数及其参数,又可以不包含基类构造函数。在调用派生类构造函数时,根据构造函数的类容决定调用基类的有参的构造函数还是无参的构造函数。
五、多重继承的构造函数
一般形式:
派生类构造函数名(总参数表):基类1构造函数(参数表),基类2构造函数(参数表),......
{派生类新增数据成员初始化语句}
<span style="font-size:18px;">class Teacher
{
public :
Teacher(string nam, int a, string t)
{
name = nam;
age = a;
title = t;
}
private:
string name;
int age;
string title;
};
class Student
{
public:
Student(char nam[], char s, float sco)
{
strcpy(name1, nam);
sex = s;score = sco;
}
private:
string name1;
char sex;
float score;
};
class Graduate:public Teacher,public Student
{
public:
Graduate(string nam,int a,char s,string t,float sco,float w):
Teacher(nam,a,t),Student(nam,s,sco),wage(w)
{}
private:
float wage;
}
</span>
多重继承的问题: 在多重继承时,从不同的基类会继承重复的数据。会引发二义性。所以就需要虚基类来解决这一问题。