四、继承性和派生性
4.1 基类和派生类
基类(父类):已存在的用来派生新类的类
派生类(子类):由已存在的类派生出的新类
图4-1 派生类的构成
4.2 单继承与多继承
单继承:从一个基类派生的继承
多继承:从多个基类派生的继承
图4-2 单继承与多继承
4.2.1 单继承
格式:
图4-3 单继承
4.2.3 继承方式
public:公有继承
private:私有继承
protected:保护继承
作用:控制基类中声明的成员在多大的范围内能被派生类的用户访问
补充:对象只能访问类中pbulic(公有)成员,不能访问private和protected成员
缺省继承方式为private
4.2.3 继承对基类成员的访问能力
公有继承:1派生类成员函数可以访问基类非私有成员
2派生类的派生类成员函数可以访问基类非私有成员
3类的对象可以访问基类的公有成员
私有继承:1派生类成员函数可以访问基类非私有成员
2派生类的派生类成员函数无法访问基类所有成员
3类的对象无法访问基类的所有成员
保护继承:1派生类成员函数可以访问基类非私有成员
2派生类的派生类成员函数可以访问基类非私有成员
3类的对象无法访问基类的所有成员
4.2.4 总结
图4-4 继承对基类成员访问权限
4.2.5 示例
图4-5 继承的访问能力
图4-6 继承的访问能力(续)
图4-7 继承的访问能力(续)
4.2.6 基类与派生类的关系
1派生类是基类的具体化基类是对若干个派生类的抽象,而派生类是基类的具体化;基类抽取了它的派生类的公共特征,而派生类通过增加行为将抽象类变为某种有用的类型
2派生类是基类定义的延续
3派生类是基类的组合派生类将其自身与基类区别开来的方法是添加数据成员和成员函数
4.2.7 派生类构造函数调用顺序
基类的构造函数>>子对象的构造函数>>派生类构造函数体
4.2.8 派生类析构函数
析构函数不能被继承
执行派生类的析构函数时,基类的析构函数也将被调用
析构函数的执行顺序与构造函数严格相反
4.2.9 示例
图4-8 派生类构造函数调用顺序
4.2.10 派生类构造函数使用中应注意的问题
派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义任何构造函数(编译器会自动生成缺省构造函数)
当基类的构造函数使用一个或多个参数时,派生类必须定义构造函数,提供将参数传递给基类构造函数的途径(设基类数据成员为m个,派生类数据成员为n个,派生类的参数个数为x,则:0≤x≤m+n)
图4-9 派生类构造函数参数问题
4.2.10 多继承
格式:
图4-10 多继承
图4-11 多继承构造函数格式
派生类构造函数负责所有基类构造函数的调用
派生类构造函数执行顺序:执行所有基类的构造函数>>执行所有子对象的构造函数>>执行派生类构造函数体
处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表中的各项顺序无关
4.2.11 示例
图4-12 多继承构造函数调用顺序
4.3 二义性问题
原因:在多继承情况下,造成的对基类中某个成员的访问出现的不唯一的情况
4.3.1 成员函数二义性
图4-13 成员函数二义性
解决方法:1区别出是类A或类B的f函数,c1.A::f()或c1.B::f()
2在类中定义同名函数f
当一个派生类从多个基类派生,而这些基类又有一个共同的基类,则对该基类中说明的成员进行访问时,可能会出现二义性
4.3.2 成员变量二义性
图4-14 成员变量二义性
解决办法:1区别出是通过类B1或类B2调用类A的a,c1.B1::a或c1.B2::a
2虚基类
4.3.3 解决办法
利用成员名限定法消除二义性
在类中定义一个同名成员
虚基类
4.3.4 特殊说明
一个类不能从同一个类中直接继承一次以上
二义性检查在访问控制和类型检查之前进行,访问控制和类型检查不能解决二义性问题
4.3.5 示例
图4-15 二义性示例
4.4 虚基类
格式:virtual<继承方式> <基类名>
说明:关键字virtual与关键字public或private的相对位置无关,但必须位于虚基类名之前,且virtual只对紧随其后的基类名起作用
例如:class D:virtualpublic A,private B,virutalpublic C 其中,类A和类C是虚基类,而类B是非虚基类
4.4.1 虚基类与非虚基类的存储结构
图4-16 虚基类与非虚基类存储结构
4.4.2 虚基类的构造函数
派生类中只有一个虚基类子对象
虚基类构造函数必须只被调用一次,目的是要保证虚基类子对象只被初始化一次
最派生类:继承结构中建立对象时所指定的类
虚基类子对象由最派生类的构造函数通过调用虚基类的构造函数进行初始化
在一个成员初始化列表中出现对虚基类和对非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数的执行
最派生类的构造函数的成员初始化列表中必须给出对虚基类的构造函数的调用;如果未列出,则相应的虚基类必须有缺省构造函数
图4-17 虚基类的构造函数
4.4.3 示例
图4-18 虚基类与非虚基类
4.4.4 小结
图4-19 初始化顺序
传送门:1小时精通c++面向对象编程