转自https://blog.csdn.net/u010141928/article/details/72902498
基类就是父类,派生类就是子类。
派生类继承了基类的数据成员,所以派生类的构造函数中不仅要初始化派生类所增加的数据成员,还要 初始化基类中的数据成员。因此在执行派生类的构造函数时,应该调用基类的构造函数。具体的形式如下:
派生类构造函数名(总形式参数表列):基类构造函数名(实际参数表列){派生类中新增数据成员初始化语句}
举个例子:
Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s),age(a),addr(ad){}
上面的调用构造函数也是在初始化参数表列中执行的。
对于派生类中增加的成员数据的初始化也可以不再初始化表中进行初始化,而是在函数体中进行。
Student1(int n,string name,char s,int a,string ad):Student(n,nam,s)
{
age=a;
addr=ad;
}
需要注意的是基类中的数据的初始化只能在初始化表中进行,而不能再函数体中用赋值语句来初始化;而且在初始化表中进行的时候只能通过调用构造函数来进行,而不能通过赋值来初始化。
构造函数的执行顺序:
派生类构造函数先调用基类构造函数;
再执行派生类构造函数本身(即派生类构造函数的函数体)。
举个例子如下:
class Base
{
protected:
Base(){cout<<'A';)
};
class Derived:public Base
{
public:
Derived(char c)
{
cout<<c;
}
};
int main()
{
Derived d('B');
return 0;
}
对于上面的程序,最后的执行结果为AB。之所以会这样是因为在执行派生类的构造函数的时候,会先调用基类的构造函数,所以无论在派生类的构造函数中
是否明确写出调用基类的构造函数,基类的构造函数时一定要执行的。
在派生类对象释放时:
先执行派生类析构函数~Derived();
再执行其基类的析构函数~Base()。
上面的顺序和执行构造函数的顺序是相反的,原理就是:对于普通类来说,先创建的对象后析构,也就是说先调用构造函数的后调用析构函数。
有子对象的派生类的构造函数:
子对象:即对象中的对象,类的成员数据是另一个类的对象
具体的格式如下:
派生类构造函数名(总形式参数表列):基类构造函数名(实际参数表列),子对象名(实际参数表列)
{派生类中新增数据成员初始化语句}
举个例子:
Student1 (int n,string name,int n1,string nam1,int a,string ad):
Student(n,nam),monitor(n1,nam),age(a),addr(ad){}
执行构造函数的顺序:
1. 基类的构造函数
2. 子对象的构造函数
3. 派生类本身的构造函数(其他数据成员初始化)
多层派生的构造函数:
每一层的派生类只会调用上一层的直接的构造函数。不关心任何其他的包括上上层基类的构造函数。
一些特殊的规则:
基类中没有定义构造函数,或者定义了没有参数的构造函数:
在派生类构造函数中可不写调用基类构造函数的语句,调用派生类构造函数时系统会自动调用基类的默认构造函数。
基类或子对象类型的声明中定义了带参数的构造函数:
必须显示地定义派生类的构造函数,并在派生类构造函数中写出基类或子对象类型的构造函数及参数表。
基类中既定义无参数的构造函数,又重载了有参数的构造函数:
派生类构造函数中可以写明调用带参数的基类构造函数,也可以不写调用基类的构造函数。
综上,子对象初始化以及对基类构造函数的调用只能写在初始化参数列表中,不能写在函数体内。