继承多态
类为构建可复用软件提供了更高的灵活性和更好的模块性。为了设计类,需要探究类之间的关系。类之间的关系通常是关联、聚合、组合以及继承。
实现类之间的关系也是面向对象编程的一部分重要工作。
如果将嵌入的对象作为新类的公有成员,那么除了使用新类接口中提供的功能之外,还可以向包含的成员对象发送消息
如果将嵌入对象作为新类的私有成员,这时它是新类内部实现的一部分:新类中的方法可以使用成员对象提供的功能,但新类只向外部提供自己的接口,隐藏了包含的成员对象
成员对象是组合对象的一部分,随着组合对象的创建而创建,随着组合对象的撤销而撤销
成员对象不作为独立元素对外部展现
创建包含对象成员的组合对象时,会执行成员类的构造函数初始化对象成员
成员对象的初始化使用初始化列表语法
当组合对象被撤销时,会执行其析构函数,成员对象的析构函数也会被执行
析构函数的执行次序和构造函数相反
成员对象的初始化表
如果没有在初始化列表中对成员对象进行显式初始化,编译器会执行成员对象的默认构造函数,如果成员对象所属的类不存在默认构造函数,会引起编译错误
类中如果包含多个对象成员,在初始化列表中将它们用逗号隔开
成员初始化的次序和成员声明的次序相同,并不考虑它们在初始化列表中的排列顺序
继承是面向对象的核心特征之一
封装,继承,多态性
继承也是一种复用已有类的机制
在已有类的基础上继承得到新类型,这个新类型自动拥有已有类的特性,并可以修改继承到的特性或者增加自己的新特性
在C++中,
被继承的已有类称为基类;
继承得到的新类称为派生类;
派生类可以再被继承,这样构成的层次结构称为继承层次
派生类的生成过程经历了:吸收基类成员(全部吸收(构造、析构除外),但不一定可见。改造基类成员
。添加派生类新成员
在C++的继承机制中,派生类吸收基类中除构造函数和析构函数之外的全部成员。
通过在派生类中定义同名成员(包括成员函数和数据成员)来屏蔽(隐藏)在派生类中不起作用的部分基类成员。
仅仅继承基类的成员是不够的,需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现。
派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽了基类的同名成员
在派生类中使用基类的同名成员,显式地使用类名限定符:
类名 :: 成员
基类定义的静态成员,将被所有派生类共享(基类和派生类共享基类中的静态成员)
根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质
派生类中访问静态成员,用以下形式显式说明:
类名 :: 成员
或通过对象访问 对象名 . 成员
在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据
派生类构造函数声明为
派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员1( 变元表 )
… 对象成员n ( 变元表 ) ;
构造函数执行顺序:基类对象成员派生类
派生类构造函数和析构函数的使用原则
基类的构造函数和析构函数不能被继承
如果基类没有定义构造函数或有无参的构造函数, 派生类也可以不用定义构造函数
如果基类无无参的构造函数,派生类必须定义构造函数
如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造
派生类是否定义析构函数与所属的基类无关
(1)当派生类中不含对象成员时
在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
在撤消派生类对象时,析构函数的执行顺序是:派生类的析构函数→基类的析构函数。
(2)当派生类中含有对象成员时
在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
在撤消派生类对象时,析构函数的执行顺序:派生类的析构函数→对象成员的析构函数→基类的析构函数。
一个类有多个直接基类的继承关系称为多继承
多继承声明语法
class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
};
多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员。
执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。
一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别。
处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的基类顺序
与派生类构造函数中所定义的成员初始化列表顺序没有关系。
内嵌对象成员的构造函数执行顺序与对象在派生类中声明的顺序一致
析构函数名同样与类名相同,无返回值、无参数,而且其定义方式与基类中的析构函数的定义方式完全相同。
功能是在派生类中对新增的有关成员进行必要的清理工作。
析构函数的执行顺序与多继承方式下构造函数的执行顺序完全相反,首先对派生类新增的数据成员进行清理,再对派生类对象成员进行清理,最后才对基类继承来的成员进行清理。
在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。
继承的目的是通过“定义能为多个派生类提供共有元素的基类”的方式编写更精简的代码。
继承能够把这些共有元素集中在一个基类中,从而避免在多处出现重复的代码和数据。
一个虚函数,在派生类层界面相同的重载函数都保持虚特性
虚函数必须是类的成员函数
虚函数可以是另一个类的友元
析构函数可以是虚函数,但构造函数不能是虚函数
在派生类中重载基类的虚函数要求函数名、返回类型、参数个数、
参数类型和顺序完全相同
如果仅仅返回类型不同,C++认为是错误重载
如果函数原型不同,仅函数名相同,丢失虚特性
构造函数不能是虚函数。建立一个派生类对象时,必须从类层次的根开始,沿着继承路径逐个调用基类的构造函数
析构函数可以是虚的。虚析构函数用于指引 delete 运算符正确析构动态对象
使用虚函数实现多态性的一般步骤是
在基类中将需要多态调用的成员函数声明为virtual
在派生类中覆盖基类的虚函数,实现各自需要的功能
用基类的指针或引用指向派生类对象,通过基类指针或引用调用虚函数。