本节目标
一、继承的概念及定义
二、基类和派生类对象赋值转换
三、继承中的作用域
四、派生类的默认成员函数
五、继承与友元
六、继承与静态成员
七、复杂的菱形继承及菱形虚拟继承
八、继承的总结和反思
九、笔试面试题
一、继承的概念及定义
1.继承的概念
- 继承是面向对象程序设计中是代码可以复用的手段,允许了程序员在原有的类特性上进行扩展,增加功能,这样产生新的类,称为派生类
- 继承呈现了面向对象程序设计的层次结构
- 以前我们接触的复用都是函数复用,继承是类设计层次方面的复用
- 用例如下
2.继承的定义
- 父类跟子类,也叫基类跟派生类
- 继承关系和访问限定符:
- 继承又分为三种继承关系 public protected private
- 继承后子类对父类的访问又分为三种 public protected private
- 如果父类也就是基类,里面的函数和变量都是private的,
- 那么子类/派生类继承后,也无法访问到父类里面的函数和变量
- 如果父类里面是protected和private 就可以访问
- protected比较特殊,跟private的不同是,private的所有东西子类和类外都不可以访问
- 而protected则是 子类可以访问,类外不可以访问
- 实际中我们都使用public继承,很少使用其他两种
二、基类和派生类对象赋值转换
- 派生类可以赋值给基类的对象/指针/引用
- 但是基类不可以赋值给派生类对象
- 但是基类的指针/引用可以通过强制类型转换来赋值给派生类的指针/引用
- 派生类赋值给基类时,其实基类是把派生类里自己的东西拿走,其他的东西不拿走,换个说法也叫切割或者切片,就是把派生类中基类的东西切掉赋值过去
- 切割如图所示(子类student里父类的东西切割 送过去)
三、继承中的作用域
- 在继承体系中,基类和派生类都有自己的作用域
- 如果基类和派生类中有同名成员, 子类将屏蔽父类的成员,这种情况叫做隐藏,也叫重定义
- 如果不想屏蔽掉,想使用同名成员里的父类的,可以通过使用基类::基类成员来进行访问使用
- 只要函数名相同就构成隐藏,不管返回值类型
- 在继承体系中最好不要定义同名成员
- 这里不展示类详细信息,看结论
四、派生类中的默认成员函数
- 还是6个默认成员函数
- 父类里面的成员变量 必须 通过父类的构造函数来初始化,子类不能初始化
五、继承和友元
- 友元关系不能继承
- 基类的友元不能访问子类的私有成员和保护成员
六、继承与静态成员
- 基类如果定义了static静态成员,则整个继承体系里只有一个这样的成员
- 子类也共用,无论派生出多少子类,都只有一个static成员
- 额外补充 注意: static静态成员在类中声明,类外初始化 类外初始化不用加static
- 比较简单,这里不做演示
七、复杂的菱形继承及菱形虚拟继承
1.各种继承
- 单继承
- 一个子类只有一个直接父类就叫单继承
- 多继承
- 一个子类有两个及以上直接父类叫多继承
- 菱形继承
- 菱形继承是多继承的一种特殊情况
- 关于菱形继承 有着很大的问题,由于多继承的出现就导致了菱形继承
- 观察上图
- student和teacher两个类继承了person
- 而assistant又同是继承了他俩
- 那么在assistant里面 就有了两个同名的成员变量,此时如果访问的话,编译器就不知道是访问的谁的 student还是teacher的
2.虚拟继承
- 为了解决掉这个问题
- 此时出现了虚拟继承
- 虚拟继承可以解决菱形继承中的二义性和数据冗余
- 在上面的student和teacher 继承 person时加上virtual 即可解决问题
- 注意:虚拟继承不要在其他地方使用 仅限于菱形继承
3.虚拟继承解决数据冗余和二义性的原理
- 为了研究虚拟继承原理,我们给出了一个简化的菱形继承继承体系
八、继承的总结和反思
- 很多人说C++语法复杂,其实多继承就是一个体现,有了多继承,就存在了菱形继承,有了菱形继承就有了虚拟继承,底层实现就很复杂,所以一般不建议设计出多继承,在java里面是没有多继承的,菱形继承一定不要设计出来,复杂性太高
- 多继承可以认为是C++的缺陷之一
- 继承和组合
- 继承是is的关系,组合是has的关系
- 优先使用组合,而不是继承
- 什么是组合? 下图 这里没用继承 将轮胎给到了车上
九、笔试面试题
- 1.什么是菱形继承?菱形继承的问题是什么?
- 2.什么是菱形虚拟继承,如何解决数据冗余和二义性的?
- 3.继承和组合的区别?什么时候用继承?什么时候用组合?