明智而审慎地使用多重继承——条款40

2023-11-18

        当多重继承(multiple inheritance;MI)进入设计景框,程序有可能从一个以上的base classes继承相同名称(如函数、typedef等等)。那会导致较多的歧义机会。例如:

class BorrowableItem {             // 图书馆允许你借某些东西
public:
	void checkOut();               // 离开时进行检查
	...
};
class ElectronicGadget {
private:
	bool checkOut() const;        // 指向自我检测,返回是否测试成功
	...
};
class MP3Player:                 // 注意这里的多重继承(某些图书馆愿意借出MP3播放器)
    public BorrowableItem, 
    public ElectronicGadget 
{
	...                          // 这里,class的定义不是我们关心重点 
};
MP3Player mp;
mp.checkOut();                   // 歧义!调用的是哪个checkOut?

        注意此例之中对checkOut的调用是歧义(模棱两可)的,即使两个函数之中只有一个可取用(BorrowableItem内的checkOut是public,ElectronicGadget内的却是private)。这与C++用来解析(resolving)重载函数的调用的规则相符:在看到是否有个函数可取用之前,C++首先确认这个函数对此调用之言是最佳匹配。找出最佳匹配函数后才检验其可取用性。本例的两个checkOuts有相同的匹配程度(译注:因此才造成歧义),没有所谓最佳匹配。因此ElectronicGadget::checkOut的可取用性也就从未被编译器审查。

        为了解决这个歧义,你必须明白指出你要调用哪一个base class内的函数:

mp.BorrowableItem::checkOut();    // 哎呀,原来是这个checkOut...

        你当然也可以尝试明确调用ElectronicGadget::checkOut,但然后你会获得一个“尝试调用private成员函数”的错误。

        多重继承的意思是继承一个以上的base classes,但这些base classes并不常在继承体系中又有更高级的base classes,因为那会导致要命的“钻石型多重继承”:

        任何时候如果你有一个继承体系而其中某个base class和某个derived class之间有一条以上的相通路线(就像上述的File和IOFile之间有两条路径,分别穿越InputFile和OutputFile),你就必须面对这样一个问题:是否打算让base class内的成员变量经由每一条路径被复制?假设File class有个成员变量fileName,那么IOFile内该有多少笔这个名称的数据呢?从某个角度说,IOFile从其每一个base class继承一份,所以其对象内应该有两份fileName成员变量。但从另一个角度说,简单的逻辑告诉我们,IOFile对象只该有一个文件名称,所以它继承自两个base classes而来的fileName不该重复。

        C++其缺省做法是执行复制(也就是上一段所说的第一个做法)。如果那不是你要的,你必须令那个带有此数据的class(也就是File)成为一个virtual base class。为了这样做,你必须令所有直接继承自它的classes采用“virtual继承”:

        C++标准程序库内含一个多重继承体系,其结构就如右图那样,只不过其classes其实是class templates,名称分别是basic_ios,basic_istream,baseic_ostream和basic_iostream,而非这里的File,InputFile,OutputFile和IOFile。

        virtual继承的classes所产生的对象往往比使用non-virtual继承的体积大,访问virtual base classes的成员变量时,也比访问non-virtual base classes的成员变量速度慢。种种细节因编译器不同而异,但基本重点很清楚:你得为virtual继承付出代价。

        virtual继承的成本还包括其他方面。支配“virtual base classes初始化”的规则比起non-virtual bases的情况远为复杂且不直观。

        我对virtual base classes(亦相当于对virtual继承)的忠告很简单。第一,非必要不使用virtual bases。平常请使用non-virtual继承。第二,如果你必须使用virtual base classes,尽可能避免在其中放置数据。这么一来你就不需担心这些classes身上的初始化(和赋值)所带来的诡异事情了。Java和.NET的Interfaces值得注意,它在许多方面兼容于C++的virtual base classes,而且也不允许含有任何数据。

请记住

  • 多重继承比单一继承复杂。它可能导致新的歧义性,以及对virtual继承的需要。
  • virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes不带任何数据,将是最具有实用价值的情况。
  • 多重继承的确有正当用途。其中一个情节涉及“public继承某个Interface class”和“private继承某个协助实现的class”的两相组合。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

明智而审慎地使用多重继承——条款40 的相关文章

  • Effective C++学习笔记——宁以传引用替换传值

    目录 一 传值效率可能会很低 二 传值可能发生割裂问题 三 适用于传值的情况和注意事项 相关博客 C 引用知识归纳 一 传值效率可能会很低 我们假设有这样两个类 class Human public string name string s
  • 编写new和delete时需固守常规——条款51

    条款50已解释什么时候你会想要写个自己的operator new和operator delete 但并没有解释当你那么做时必须遵守什么规则 这些规则不难奉行 但其中一些并不直观 所以知道它们究竟是些什么很重要 让我们从operator ne
  • 考虑写出一个不抛异常的swap函数——条款25

    swap是个有趣的函数 原本它只是STL的一部分 而后成为异常安全性编程 exception safe programing 见条款29 的脊柱 以及用来处理自我赋值可能性 见条款11 的一个常见机制 由于swap如此有用 适当的实现很重要
  • 区分接口继承和实现继承——条款34

    表面上直截了当的public继承概念 经过严密的检查之后 发现它由两部分组成 函数接口 function interfaces 继承和函数实现 function implementations 继承 这两种继承的差异 很像本书导读所讨论的函
  • 运用成员函数模板接受所有兼容类型——条款45

    所谓智能指针是 行为像指针 的对象 并提供指针没有的机能 例如条款13曾经提及std auto ptr和tr1 shared ptr如何能够被用来在正确时机自动删除heap based资源 STL容器的迭代器几乎总是智能指针 无疑地你不会奢
  • 透彻了解inlining的里里外外——条款30

    Inline函数 多棒的点子 它们看起来像函数 动作像函数 比宏好得多 见条款2 可以调用它们又不需要蒙受函数调用所招致的额外开销 你还能要求更多吗 你实际获得的比想到的还多 因为 免除函数调用成本 只是故事的一部分而已 编译器最优化机制通
  • c++多重继承和虚继承

    多重继承 多重继承是指从多个直接基类中产生派生类的能力 多重继承的派生类继承了所有父类的属性 struct Base1 Base1 default Base1 const string Base1 shared ptr
  • 《Effective C++》学习笔记——区分接口继承和实现继承

    派生类public继承自基类 其中函数均是接口继承 实现继承又分为缺省继承与强制继承 对应着虚函数与非虚函数 我们在做项目时 对于任何事物都要抱有先描述再组织的心态 因此 当描述事物为其构建框架尤其是存在继承 is a 关系时 一定要搞清楚
  • 令operator=返回一个reference to *this——条款10

    关于赋值 有趣的是你可以把它们写成连锁形式 int x y z x y z 15 同样有趣的是 赋值采用右结合律 所以上述连锁赋值被解析为 x y z 15 这里15先被赋值给z 然后其结果 更新后的z 再被赋值给y 然后其结果 更新后的y
  • 尽可能延后变量定义式的出现时间——条款26

    只要你定义了一个变量而其类型带有一个构造函数或析构函数 那么当程序控制流 control flow 到达这个变量定义式时 你便得承受构造成本 当这个变量离开其作用域时 你便得承受析构成本 即使这个变量最终未被使用 仍需耗费这些成本 所以你应
  • 在operator=中处理“自我赋值”——条款11

    自我赋值 发生在对象被赋值给自己时 class Widget Widget w w w 赋值给自己 这看起来有点愚蠢 但它合法 所以不要认定客户绝不会那么做 此外赋值动作并不总是那么可被一眼辨识出来 例如 a i a j 潜在的自我赋值 如
  • 尽量以const、enum、inline替换 #define——条款02

    这个条款或许改为 宁可以编译器替换预处理器 比较好 因为或许 define 不能被视为语言的一部分 一 比如定义一个宏 define ASPECT RATIO 1 653 这个ASPECT RATIO也许从未被编译器看见 也许在编译器开始处
  • 将文件间的编译依存关系降至最低——条款31

    假设你对C 程序的某个class实现文件做了些轻微修改 注意 修改的不是class接口 而是实现 而且只改private成分 然后重新建置这个程序 并预计只花数秒就好 毕竟只有一个class被修改 你按下 Build 按钮或键入make 或
  • 条款13: 以对象管理资源

    结论 为防止资源泄漏 请使用RAII对象 它们在构造函数中获得资源并在析构函数中释放资源 两个常被使用的RAII classes分别是tr1 share ptr和auto ptr 前者通常是较佳选择 因为其copy行为比较直观 若选择aut
  • Effective C++改善程序与设计的55个具体做法笔记

    Scott Meyers大师Effective三部曲 Effective C More Effective C Effective STL 这三本书出版已很多年 后来又出版了Effective Modern C More Effective
  • 《Effective C++》 全书内容提炼总结

    个人博客地址 https cxx001 gitee io 本文阅读说明 孔子云 取乎其上 得乎其中 取乎其中 得乎其下 取乎其下 则无所得矣 对于读书求知而言 这句古训教我们去读好书 最好是好书中的上品 经典书 Effective C 就是
  • Effective C++ 学习笔记 《六》

    Item 6 Explicitly disallow the use of compiler generated functions you do not want 其实这一节的内容是和item5紧密相连的 上一节的核心围绕着编译器会自动生
  • 将与参数无关的代码抽离templates——条款44

    Templates是节省时间和避免代码重复的一个奇方妙法 不再需要键入20个类似的classes而每一个带有15个成员函数 你只需键入一个class template 留给编译器去具现化那20个你需要的相关classes和300个函数 cl
  • 掌握 Effective C++ : 条款01

    背景 Effective C 是每个 C 程序员都应该读的经典之作 书中涵盖了 C 编程中的一系列最佳实践 包括了面向对象设计 模板 STL 异常处理等方面的内容 由于 C 的发展非常迅速 书中的某些内容可能已经过时 但依然是值得好好学习的
  • Effective C++——尽可能使用const

    const允许指定一个语义约束 也就是指定一个 不该被改动 的对象 而编译器会强制实施这项约束 只要保持某个值不变是事实 就应该说出来 以获得编译器的协助 保证不被违反 const与指针 注意const的写法 const char p p可

随机推荐

  • C++ tuple元组的基本用法(总结)

    1 元组简介 tuple是一个固定大小的不同类型值的集合 是泛化的std pair 我们也可以把他当做一个通用的结构体来用 不需要创建结构体又获取结构体的特征 在某些情况下可以取代结构体使程序更简洁 直观 std tuple理论上可以有无数
  • 操作型bi研究报告(转)

    操作型bi是bi发展过程中的转折点 传统上认为 bi是从海量历史数据中利用成熟的分析工具发现业务中的模式和趋势 从战略上和战术上辅助决策的一种技术 但是操作型bi改变了这种观点 它将bi从后台搬出来并且嵌入到业务操作流程的细节中 驱动着日以
  • 影之刃3服务器维护,影之刃33月4日维护公告 内容公告预览

    影之刃3 将于3月4日10 00 12 00对全部服务器停服维护 维护期间将无法登录游戏 给您带来的不便敬请谅解 感谢您的理解和支持 本次维护预计持续2小时 维护时间可能延长或提前结束 具体时间请以开服时间为准 维护结束后 我们将为全服玩家
  • 域名能查到服务器信息么,域名查服务器信息

    域名查服务器信息 内容精选 换一换 用户可以通过查询域名注册信息 确认域名所属的DNS服务器信息 然后再根据域名所属的DNS服务器信息进行DNS验证的相关操作 当 Name Servers 显示如所图1示时 则表示域名所属的DNS服务器为华
  • RTX 3080 Linux和Windows 平台兼容性问题

    好不容易 在某电商平台抢到了一块3080显卡 高高兴兴的装机准备大搞游戏开始深度学习 却遇到了很多麻烦 当然经过多方探索 终于也是解决了linux和Windows双平台的兼容性问题 目前Pytorch和TensorFlow都能使用 首先是l
  • Windows系统下如何运行.sh脚本文件

    前言 sh文件是一种命令脚本文件 在Windows系统下可以通过命令行工具打开运行 通常可以使用Git工具来打开运行 sh脚本文件 不过很多第一次使用Git的人 可能对Git工具不熟悉 sh文件在命令行运行时是有固定写法的 下面介绍详细步骤
  • 【Linux】---进程控制(创建、终止、等待、替换)

    文章目录 进程创建 fork 进程退出 进程退出场景 进程退出方法 退出码 exit exit 进程等待 进程等待的方法 wait waitpid 阻塞和非阻塞 进程替换 替换的原理 替换所用到的函数 execl execlp execle
  • shell 字符串处理汇总(查找,替换等等)

    字符串 简称 串 有限字符的序列 数据元素为字符的线性表 是一种数据的逻辑结构 在计算机中可有不同的存储结构 在串上可进行求子串 插入字符 删除字符 置换字符等运算 字符 计算机程序设计及操作时使用的符号 包括字母 数字 空格符 提示符及各
  • 【Java基础知识 3】为何要配置环境变量?

    Java基础教程系列 Java基础教程系列 Java学习路线配套文章 搬砖工逆袭Java架构师 Java经典面试题大全 10万字208道Java经典面试题总结 附答案 简介 Java领域优质创作者 CSDN哪吒公众号作者 Java架构师奋斗
  • 模拟电路设计(33)---电源变换器简介

    概述 电子设备都需要供电 其电能来源于火力 水力 核子发电厂提供的交流电 这些交流电通过电源设备变换为直流电 但是 这种直流电源不符合需要 仍需变换 这称为DC DC变换 常规的变换器是串联线性稳压电源 其调整元件工作于线性放大区 通过的电
  • 学习Kali渗透测试笔记

    Kali渗透测试 一 什么是渗透测试 1 软件测试 2 安全测试与渗透测试 3 渗透测试 二 渗透测试的目标 1 网络硬件设备 2 主机操作系统 3 应用系统 4 数据库系统 三 渗透测试的意义 四 渗透测试的方法分类 1 按照信息掌握程度
  • LiteOrm "cannot be instantiated"

    错误提示 java lang Class
  • 【深度强化学习】(5) DDPG 模型解析,附Pytorch完整代码

    大家好 今天和各位分享一下深度确定性策略梯度算法 Deterministic Policy Gradient DDPG 并基于 OpenAI 的 gym 环境完成一个小游戏 完整代码在我的 GitHub 中获得 https github c
  • 网络管理服务器篇之Apache

    一 软件简介 1 Apache是最流行的Web服务器端软件之一 快速 可靠 可通过简单的API扩展 Perl Python解释器可被编译到服务器中 完全免费 完全源代码开放 如果你需要创建一个每天有数百万人访问的Web服务器 Apache可
  • 【文件上传绕过】五、文件后缀大小写绕过

    文章目录 一 黑名单 二 源码 三 大小写绕过 一 黑名单 本pass禁止上传 php php5 php4 php3 php2 php1 html htm phtml pHp pHp5 pHp4 pHp3 pHp2 pHp1 Html Ht
  • String类详解

    目录 一 创建字符串的四种方式 1 直接赋值 2 通过构造方法创建对象 3 通过字符数组创建对象 4 通过String类的静态方法valueOf 任意数据类型 gt 转为字符串 二 字符串比较相等 equals方法 equalsIgnore
  • ICMP协议Ping方法的Python实现解析

    ICMP协议Ping方法的Python实现解析 说明 本代码适合Windows 没有在其他系统下进行测试 参考对象为https github com samuel python ping 流程 选择目标网址 解析对方ip地址 构造数据报 添
  • KVM 虚拟机的热迁移

    热迁移 顾名思义在虚拟机不关机的情况下将KVM虚拟机进行迁移 准备工作 两台KVM虚拟机 一台nfs虚拟机 centos7 4系统 主机 IP地址 主机名 KVM01 10 00 11 kvm01 KVM02 10 0 0 12 kvm02
  • SSM简单项目

    暑假项目实训花了2个星期做的项目 前台完成了大部分 后台做了一点点 其中主要运用了ssm框架技术 layui前端技术 拦截器 阿里云支付宝接口 阿里云短信验证接口 layui轮播图 流加载 分页 表单 表格等技术 访问网站 http www
  • 明智而审慎地使用多重继承——条款40

    当多重继承 multiple inheritance MI 进入设计景框 程序有可能从一个以上的base classes继承相同名称 如函数 typedef等等 那会导致较多的歧义机会 例如 class BorrowableItem 图书馆