继承
什么是继承?
面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行时间的效果。
当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
继承代表了 isa 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。
在C++语言中,一个派生类可以从一个基类派生,也可以从多个基类派生。从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。
派生类的定义格式
单继承的定义格式如下:
1 2 3 4 | class<派生类名>:<继承方式><基类名> { <派生类新定义成员> }; |
其中,class是关键词,<派生类名>是新定义的一个类的名字,它是从<基类名>中派生的,并且按指定的<继承方式>派生的。<继承方式>常使用如下三种关键字给予表示:
public 表示公有继承;
private 表示私有继承;
protected 表示保护继承;
多继承的定义格式如下:
1 2 3 4 5 6 7 | class<派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类新定义成员>
}; |
可见,多继承与单继承的区别从定义格式上看,主要是多继承的基类多于一个。
如果省略继承方式,对'class'将采用私有继承,对'struct'将采用公有继承。
也就是说
1 2 3 4 5 | class Base1{};
struct Base2{};
class Derive:Base1,Base2{}; |
那么,Derive类将私有继承Base1,公有继承Base2。相当于:
1 | class Derive:private Base1,public Base2{}; |
3.派生类的生成过程经历了三个步骤:
●吸收基类成员(全部吸收(构造、析构除外),但不一定可见)
●改造基类成员
●添加派生类新成员
(1)吸收基类成员
在C++的继承机制中,派生类吸收基类中除构造函数和析构函数之外的全部成员。
(2)改造基类成员
通过在派生类中定义同名成员(包括成员函数和数据成员)来屏蔽(隐藏)在派生类中不起作用的部分基类成员。
添加新成员:
仅仅继承基类的成员是不够的,需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现。
继承类型:
当一个类派生自基类,该基类可以被继承为public、protected或private几种类型。我们几乎不使用protected或private继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:
· 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
· 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
· 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
重名成员:
(1)概念:派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽了基类的同名成员。
(2)句法形式:在派生类中使用基类的同名成员:类名::成员。
派生类中访问静态成员:
1.基类定义的静态成员,将被所有派生类共享(基类和派生类共享基类中的静态成员)
2.根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质
3.派生类中访问静态成员,用以下形式显式说明:
类名 :: 成员,或通过对象访问对象名.成员
基类的初始化:
(1)在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据
(2)派生类构造函数声明为:
· 派生类构造函数( 变元表) : 基类( 变元表) , 对象成员1( 变元表)
· …对象成员n (变元表 ) ;
(3)构造函数执行顺序:基类à对象成员à派生类
派生类构造函数和析构函数的定义规则:
· (1)基类的构造函数和析构函数不能被继承
· (2)如果基类没有定义构造函数或有无参的构造函数,派生类也可以不用定义构造函数
· (3)如果基类无无参的构造函数,派生类必须定义构造函数
· (4)如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造
· (5)派生类是否定义析构函数与所属的基类无关
派生类构造函数的定义:
· 派生类的数据成员既包括基类的数据成员,也包括派生类新增数据成员。
在C++中,派生类构造函数的一般格式为:
派生类::派生类名(参数总表):基类名(参数表)
{
// 派生类新增成员的初始化语句
}
注意:这是基类有构造函数且含有参数时使用
派生类析构函数:
(1)当派生类中不含对象成员时
在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
在撤消派生类对象时,析构函数的执行顺序是:派生类的析构函数→基类的析构函数。
(2) 当派生类中含有对象成员时
在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
在撤消派生类对象时,析构函数的执行顺序:派生类的析构函数→对象成员的析构函数→基类的析构函数。
多继承
(1)概念:一个类有多个直接基类的继承关系称为多继承
(2)多继承语法声明:
class 派生类名:访问控制 基类名1,访问控制 基类名2,…,访问控制 基类名n
{
数据成员和成员函数声明
};
(3)类C可以根据访问控制同时继承类A和类B的成员,并添加自己的成员
· classA
· classB
· class C:public A,public B
(4)多继承的派生类构造和访问
· 多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员。
· 执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。
· 一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别。
(5)多继承的构造函数
句法形式:派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),…,基类名n(参数表n)
{
// 派生类新增成员的初始化语句
};
执行顺序:先执行所有基类的构造函数,再执行对象成员的构造函数,最后执行派生类的构造函数
注:处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的基类顺序与派生类构造函数中所定义的成员初始化列表顺序没有关系。内嵌对象成员的构造函数执行顺序与对象在派生类中声明的顺序一致
(6) 多继承的析构函数:
析构函数名同样与类名相同,无返回值、无参数,而且其定义方式与基类中的析构函数的定义方式完全相同。
功能是在派生类中对新增的有关成员进行必要的清理工作。
析构函数的执行顺序与多继承方式下构造函数的执行顺序完全相反,首先对派生类新增的数据成员进行清理,再对派生类对象成员进行清理,最后才对基类继承来的成员进行清理
学习的心得体会:
继承的使用可以简便程序,可以减少代码的重复书写,使用的关键在于正确的找出2个类或者几个类之间相同的部分,找到重复的内容作为一个基类来单独定义,在别的需要用到这个功能的地方直接调用,避免多次书写。因为继承是两个类之间的联系,所以在使用过程中一定要仔细,严谨,防止出现一些可避免错误导致代码看起来糊里糊涂。