从面向对象的程序设计的观点来看,继承表达的是对象类之间的相互关系。这种关系使得某类对象可以继承另外一类对象的特征和能力。如果一类对象继承了另一类对象的特征和能力,这个类就叫做所继承类的派生类。继承是一个进程,通过继承,一个对象可以获得另一个对象的属性(包括函数),并可向其中加入属于自己的一些特征。
1.继承的基本概念
C++中定义派生类的一般格式是:
class 派生类名:继承方式(public 、protected or private)基类名
{
<派生类新增加或修改的数据和成员函数>
};
继承方式:public 、protected or private
派生类的继承访问属性
private派生 protected派生 public派生
基类 派生类 基类 派生类 基类 派生类
private-->不可见 private-->不可见 private-->不可见
protected-->private protected-->protected protected-->protected
public-->private public-->protected public-->public
(1)无论哪种派生方式,基类中的private成员在派生类中都是不可见的。也就是说,基类中的private成员不允许外部函数或派生类中的任何成员访问。
(2)public派生与private派生的不同点在于基类中的public成员在派生类中的访问属性:
public派生时,基类中的public成员相当于派生类中的public成员。
private派生时,基类中的public成员相当于派生类中的private成员。
因此,private派生确保基类中的方法只能被派生类的对象的方法间接使用,而不能被外部使用。public派生使派生类对象与外部都可以直接使用基类中的方法,除非这些方法已经被重新定义。
2.单重继承、多重继承与继承链
从一个基类派生的继承称为单继承,换句话说,派生类只有一个直接基类。
单继承声明语句的常用格式为:
class 派生类名: 继承方式 基类名
{
数据成员和成员函数声明
};
与此相对地,从多个基类派生的继承称为多继承或多重继承,也就是说,一个派生类有多个直接基类。在某些面向对象的语言(如Java)中不支持类间的多重继承而只支持单重继承,即一个类至多只能有一个直接父类,因此实现类似的功能需要借助接口等其他机制。而在C++中提供了多重继承的语法支持,使得问题变得简单了许多。
多重继承声明语句的常用格式为:
class 派生类名: 继承方式1 基类名1, 继承方式2 基类名2,...
{
数据成员和成员函数声明
};
除了多重继承之外,一个派生类继承多个基类还有一种方法,就是把派生类作为基类再次供别的类继承,产生多层次的继承关系。例如类A派生类B,类B派生类C,则称类A是类B的直接基类,类B是类C的直接基类,类A是类C的间接基类。类的层次结构也叫做继承链。还是上面的例子,当建立类C的对象时,类A的构造函数最先被调用,接下来被调用的是类B的构造函数,最后是类C的构造函数。析构函数的调用顺序正好相反。当一个派生类继承有层次的类时,继承链上的每个派生类必须将它需要的变量传递给它的基类。
3.虚基类
如果某个派生类的部分或全部直接基类是从另一个共同的基类派生而来,在这些基类中,从上一级基类继承来的成员就有相同的名称,则在这个派生类中访问这个共同的基类中的成员时,可能会产生二义性,此时,可定义虚基类。这就要求在其直接基类的定义中,使用关键字virtual将那个共同的基类定义为虚基类,其语法形式如下:
class 派生类名: virtual 继承方式 基类
虚基类的初始化与一般的多重继承的初始化在语法上是一样的 ,但构造函数的调用顺序不同,虚基类构造函数的调用顺序是这样规定的:
1)在同一层次中,先调用虚基类的构造函数,接下来依次是非虚基类的构造函数,对象成员的构造函数,派生类的构造函数。
2)若同一层次中包含多个虚基类,这些虚基类的构造函数按对他们说明的先后次序调用
3)若虚基类由非虚基类派生而来,则仍然先调用基类构造函数,再调用派生类构造函数。
4.派生类构造函数和析构函数
派生类构造函数和析构函数的执行顺序
当派生类中不含对象成员时
●在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
●在撤消派生类对象时,析构函数的执行顺序是:派生类的构造函数→基类的构造函数。
当派生类中含有对象成员时
●在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
●在撤消派生类对象时,析构函数的执行顺序:派生类的构造函数→对象成员的构造函数→基类的构造函数。.
派生类构造函数和析构函数的构造规则
当基类中无显式定义构造函数或有函数但无参数时派生类可以不向基类传递参数,甚至可以不定义构造函数;
当基类中有构造函数且含有参数时,派生类必须定义构造函数以提供把参数传递给基类构造函数的途径。
派生类构造函数的一般格式为:
派生类::派生类构造函数名(参数表):基类构造函数名(参数表)
{
// 派生类新增成员
}
当派生类中含有对象成员时,其构造函数的一般形式为:
派生类::派生类构造函数名(参数表):基类构造函数名(参数表),对象成员名(参数表),……对象成员名n(参数表)
{
//新增数据初始化(不包括对象成员)
}