继承(inheritance):
一.继承是面向对象程序设计使代码可以复用的重要手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称为派生类(子类),原有的类称为基类(父类)。
二.继承定义格式:
class 派生类类名 : 继承关系 基类类名
﹛
派生类新增加的成员
﹜;
三.继承关系&访问限定符:
程序示例:
四.派生类的默认成员函数:
派生类有六个默认成员函数,如果派生类中没有显示的定义这六个成员函数,编译系统会默认合成这六个成员函数(构造函数、拷贝构造函数、析构函数、赋值操作符重载、取地址操作符重载、const修饰的取地址操作符重载)。
(1)继承关系中构造函数调用顺序
派生类的构造函数---->基类的构造函数(在派生类构造函数的初始化列表 中)---->派生类构造函数的函数体。
[说明]
①基类没有缺省构造函数,派生类必须要在初始化列表中显示的给出基类名和参数列表。
②基类没有定义构造函数,则派生类也可以不用定义,全部使用默认构造函数。
③基类定义了带有形参表的构造函数,派生类就一定要显示定义构造函数。
程序示例:
五.继承体系中的作用域
⑴ 基类和派生类是两个不同的作用域。
⑵ 基类与派生类中有同名成员,派生类该成员将屏蔽基类对该成员的直接访问。在派生类成员函数中可以使用基类 :: 成员名 进行访问。
⑶ 注意实际中在继承体系里面最好不要定义同名的成员。
程序示例:
六.继承与转换 ---赋值兼容规则---public继承
⑴ 基类对象可以赋值给基类对象(切割/切片)
⑵ 基类对象不能赋值给派生类对象。
⑶ 基类的指针/引用可以指向派生类对象,访问的是基类的成员。
⑷ 派生类的指针/引用不可以指向基类对象。(可以通过强制类型转换完成)
程序示例:
七.友元与继承
友元关系不能继承,也就是说基类友元不能访问派生类私有和保护成员。
给出一个特别示例:
注:这是因为输出运算符重载函数参数2的类型是基类的引用,而上面刚刚说过基类的引用/指针可以指向派生类的对象,访问的是基类的成员。所以该特例实质上并没有传递友元关系。
八.继承与静态成员
基类定义了static成员,则整个继承体系里面只有一个这样的成员,无论派生出多少个子类,都只有一个static成员实例。
程序示例:
九.单继承 & 多继承 & 菱形继承
单继承:一个子类只有一个直接父类。
多继承:一个子类有两个或两个以上直接父类。
菱形继承(钻石继承):
可以发现:在D 类中有两份B类成员,菱形继承存在二义性和数据冗余的问题。
sizeof(D)= 20.
十.虚继承
⑴ C++使用虚拟继承(Virtual Inheritance),解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅解决了二义性问题,也节省了内存,避免了数据冗余的问题。
⑵ 虚继承体系看起来很复杂,在实际应用中我们通常不会定义如此复杂的继承体系。一般不到万不得已都不要定义菱形结构的虚继承体系结构,因为使用虚继承解决了数据冗余问题也带来了性能上的损耗。
虚继承定义格式:
class 派生类名:virtual 继承关系 基类类名
﹛
派生类新增加的成员
﹜;