1. 问题

派生类可以多次继承同一个类。 派生类可以通过它的两个直接基类分别继承同一个间接基类, 也可以直接继承某个基类, 然后通过另一个基类再一次间接继承该类。如果某个类在派生过程中出现了多次, 则派生类中将包含该类的多个子对象。

2. 虚基类virtual inheritance

虚继承的目的是令某个类做出声明,承诺愿意共享它的基类。其中共享的基类子对象被称为虚基类,不论虚基类在继承体系下被继承多少次,在派生类中都只包含唯一一个共享的虚基类子对象(菱形继承)。

2.1 使用方式

指定虚基类的方式是在派生列表中添加关键字virtual:

//public和virtual的顺序随意
class Raccon : public virtual ZooAnimal{};
class Bear : virtual public ZooAnimal{};
class Panda : public Raccon,public Bear, public Endangered{};

2.2 支持向基类的常规类型转换

不论基类是不是虚基类, 派生类对象都能被可访问基类的指针或引用操作

void dance(const Bear &);
void rummage(const Raccoons);
ostreamS operator  << (ostreamS, const ZooAnimal&);
Panda ying_yang;
dance(ying_yang);//正确:把一个 Panda 对象当成 Bear 传递
rummage(ying_yang)//正确:把一个 Panda 对象当成 Raccoon 传递
cout << ying_yang;//正确:把一个 Panda 对象当成 ZooAnimal 传递

2.3 虚基类成员的可见性(二义性问题)

因为在每个共享的虚基类中只有唯一一个共享的子对象, 所以该基类的成员可以被直接访问, 并且不会产生二义性。

如果虚基类的成员只被一条派生路径覆盖, 则我们仍然可以直接访问这个被覆盖的成员。 但是如果成员被多余一个基类覆盖, 则一般情况下派生类必须为该成员自定义一个新的版本

与非虚的多重继承体系一样, 解决二义性最好的方法是在派生类中为成员自定义新的实例。

eg. 假定类 B 定义了一个名为 x 的成员, D1 和 D2 都是从 B 虚继承得到的, D 继承了 D1 和 D2, 则在 D 的作用域中, x 通过 D 的两个基类都是可见的。 如果我们通过 D的对象使用 X, 有三种可能性:

  • 如 果 在 D1 和 D2 中都没有 x 的定义, 则 x 将被解析为 B 的成员, 此时不存在二义性, 一个 D 的对象只含有 x 的一个实例。
  • 如果 x 是 B 的成员, 同时是 D1 和 D2 中某一个的成员, 则同样没有二义性, 派生类的 x 比共享虚基类 B 的 x 优先级更高。
  • 如 果 在 D1 和 D2 中都有 x 的定义, 则直接访问 x 将产生二义性问题。

C++ Primer 5th笔记(chap 18 大型程序工具)虚继承相关推荐

  1. C++ Primer 5th笔记(chap 18 大型程序工具)使用命名空间成员

    1. 3种方法 using 声明 命名空间的别名( namespace alias) using 指示( using directive) 1.1 命名空间的别名 namespace cplusplu ...

  2. C++ Primer 5th笔记(chap 18 大型程序工具) 多重继承之构造函数、析构函数

    1. 继承的构造函数与多重继承 如果从多个基类中继承了相同的构造函数(即形参列表完全相同),则程序将产生错误 struct Basel {Basel () = default;Basel (const ...

  3. C++ Primer 5th笔记(chap 18 大型程序工具) 重载与命名空间

    1. using 声明或 using 指示能将某些函数添加到候选函数集 2. 对于接受类类型实参的函数来说, 其名字查找将在实参类所属的命名空间中进行.在这些命名空间中所有与被调用函数同名的函数都将被 ...

  4. C++ Primer 5th笔记(chap 18 大型程序工具) 类、 命名空间与作用域

    1. 命名空间内部名字的查找规则 由内向外依次查找每个外层作用域. 外层作用域也可能是一个或多个嵌套的命名空间, 直到最外层的全局命名空间查找过程终止. 只有位于开放的块中且在使用点之前声明的名字才被 ...

  5. C++ Primer 5th笔记(chap 18 大型程序工具)未命名的命名空间unnamed namespace

    1. 定义 关键字 namespace 后紧跟花括号括起来的一系列声明语句 1.1 生命周期 未命名的命名空间中定义的变量拥有静态生命周期: 它们在第一次使用前创建, 并且直到程序结束才销毁 未命名的 ...

  6. C++ Primer 5th笔记(chap 18 大型程序工具)内联命名空间 (inline namespace)

    1. inline必须出现在命名空间第一次出现的地方 inline namespace FifthEd {//... }//后续再打开命名空间的时候可以写inline也可以不写 namespace F ...

  7. C++ Primer 5th笔记(chap 18 大型程序工具)命名空间

    1. 问题:命名空间污染 namespace pollution 多个库将名字放置在全局命名空间 1.1 一般人的解决方法 起长名字 eg. class cplusplus_primer_Query ...

  8. C++ Primer 5th笔记(chap 18 大型程序工具)noexcept

    1. 通过提供 noexcept 说明 ( noexcept specification ) 指定某个函数不会抛出异常. 其形式是关键字 noexcept 紧跟在函数的参数列表后面 {// 紧跟在函数 ...

  9. C++ Primer 5th笔记(chap 18 大型程序工具)异常处理

    1. 异常处理 ( exception handling) 允许程序中独立开发的部分能够在运行时就出现的问题进行通信并做出相应的处理. 异常使得我们能够将问题的检测与解决过程分离开来. 程序的一部分负 ...

  10. C++ Primer 5th笔记(chap 18 大型程序工具)构造函数与虚继承

    1. 继承体系中的每个类都可能在某个时刻成为" 最低层的派生类". 只要我们能创建虚基类的派生类对象, 该派生类的构造函数就必须初始化它的虚基类. Bear::Bear (std: ...

最新文章

  1. C++语言基本类型—浮点型
  2. PIE SDK Geometry的坐标转换
  3. keepalived主要模块
  4. 在线网摘收藏?让Google来吧!
  5. java类的实现_java类的实现
  6. webpack实战之手写一个loader和plugin
  7. 宝塔:ShopXO开源商城(如何二级域名访问)- 配置篇
  8. 模板上 php dede,DEDE模板中使用php和if判断语句实例
  9. huffman算法c语言程序,哈夫曼算法构造代码
  10. C# NPOI Excel 合并单元格和取消单元格
  11. 程序人生 - Nature封面:脑机接口突破,可将脑中“笔迹”转为屏幕字句,速度创纪录,准确率超高
  12. matplotlib之直方图
  13. 计算机桌面的图标怎么删除,电脑桌面图标箭头怎么去掉_消除桌面图标小箭头的具体方法-系统城...
  14. 趣味ACM题——圣骑士的斩杀
  15. 电子血压仪器小程序开发制作
  16. [ Windows 10 ] 任务栏按钮不显示正在打开的窗口了(打开任何程序任务栏图标按钮都不显示)
  17. 应届生毕业就失业?这该怎么办
  18. html鼠标拖尾效果,JavaScript鼠标划过背景拖尾效果
  19. JavaGUI界面—窗口、按钮、文本框,及其解决按钮的中文乱码
  20. 互联网金融大数据风控模型,到底需要多大的数据?

热门文章

  1. 操作系统:基本分页存储管理方式
  2. 框架:spring总结
  3. html 边框循环变色,方框用过渡走一圈变色用css怎么实现
  4. ios mdm更新应用_因使用MDM下架的家长控制应用OurPact重返App Store
  5. python phpstudy_GitHub - Writeup007/phpStudyBackDoor: phpStudy后门检测与利用工具,Python脚本,可一键 GetShell。...
  6. Android多个imei如何获取,如何在Android 10中获取IMEI号,这是获取在Android 10及以下Android 10中获取IMEI号的代码...
  7. 你以为ACI=SDN?大错特错!
  8. python数据分析方法五种_加速Python数据分析的10个简单技巧(上)
  9. TF之LSTM:利用基于顺序的LSTM回归算法对DIY数据集sin曲线(蓝虚)预测cos(红实)(TensorBoard可视化)
  10. 第三次作业-介绍一款原型设计工具