读书笔记_Effective_C++_条款四十:明智而审慎地使用多重继承
多重继承是一种比较复杂的继承关系,它意味着如果用户想要使用这个类,那么就要对它的父类也了如指掌,所以在项目中会带来可读性的问题,一般我们都会尽量选择用单继承去替代它。
使用多重继承过程容易碰到的问题就是名字冲突,像下面这样:
class Base1
{
public:
void fun(){}
}; class Base2
{
private:
void fun(){}
}; class Derived : public Base1, public Base2
{}; int main()
{
Derived d;
d.fun(); // error C2385: 对“fun”的访问不明确
return ;
}
因为在两个父类中都有名为fun的函数,所以这时候编译器不知道用户想调用的是哪个函数。但这里细心的读者会发现,这里我们是把Base2的fun的访问权限设为了private的。这个例子同时也说明了,编译器会优先去查找最合适的重载函数,再去考虑它的可访问性。如果真的要去访问重名的函数,可以指定作用域,像这样d.Base1::fun()(但注意d.Base2::fun()不行,因为它的访问性是private的)。
多重继承另一个容易碰到的问题就是虚继承,我记得这还是面试官的一道面试题。试想一下,有一个父类名为A,类B和类C都继承于A,类D又同时继承了B和C(多重继承),那么如果不做任何处理,C++的类继承图里会包含两份A。
但如果在继承的时候加了virtual,像下面这样:
class B: virtual public A{…}
class C: virtual pulibc A{…}
那么D中就只有一份A了。C++标准库里面的流就是采用这样的形式,有一个父流basic_ios,basic_istream和basic_ostream分别虚继承于basic_ios,而basic_iostream又多重继承于basic_istream和basic_ostream。
为了保证不会出现两份父类,只要是public继承理论上都应该有virutal关键字,但virutal也是有代价的,访问virtual base class的成员变量要比访问non-virutal base class的成员变量速度要慢。所以作者的忠告是:
1. 非必要不使用virtual classes继承,普通情况请使用non-virtual classes继承
2. 如果必须使用virtual base classes,尽可能避免在其中放置数据。
后面的篇幅书上就举了一个多重继承的例子,在这里我就不说了,有兴趣的读者可以自己看看,但个人觉得还是能不用多重继承的时候,就尽量不用它,用复合+单继承往往能达到目的。
最后总结一下:
1. 多重继承比单一继承更复杂。它可能导致新的歧义性,以及对virtual继承的需要。
2. virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes不带任何数据,将是最具实用价值的情况。
3. 多重继承的确有正当用途。其中一个情节涉及”public继承某个Interface class”和”private继承某个协助实现的class”的两两组合。
读书笔记_Effective_C++_条款四十:明智而审慎地使用多重继承的更多相关文章
- 读书笔记_Effective_C++_条款四十九:了解new_handler的行为
本章开始讨论内存分配的一些用法,C/C++内存分配采用new和delete.在new申请内存时,可能会遇到的一种情况就是,内存不够了,这时候会抛出out of memory的异常.有的时候,我们希望能 ...
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- 读书笔记_Effective_C++_条款四十六:需要类型转换时请为模板定义非成员函数
这个条款可以看成是条款24的续集,我们先简单回顾一下条款24,它说了为什么类似于operator *这样的重载运算符要定义成非成员函数(是为了保证混合乘法2*SomeRational或者SomeRat ...
- 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型
比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...
- 读书笔记_Effective_C++_条款四十四:将与参数无关的代码抽离template
标题上说“将与参数无关的代码抽离template”,这里的参数既可以指类型,也可以是非类型,我们先来看看非类型的情况. 假定我们要为矩阵写一个类,这个矩阵的行列元素个数相等,是一个方阵,因而我们可以对 ...
- 读书笔记_Effective_C++_条款四十二:了解typename的双重意义
顾名思义,typename有双重含意.只要你用过template,那么第一重含意一定知道,那就是声明模板的时候,我们既可以这样写: template <class T> 也可以这样写 te ...
- 读书笔记_Effective_C++_条款三十:了解inline的里里外外
学过基本程序课的同学都知道,inline是内联的关键字,它可以建议编译器将函数的每一个调用都用函数本体替换.这是一种以空间换时间的做法.把每一次调用都用本体替换,无疑会使代码膨胀,但可以节省函数调用的 ...
- 读书笔记_Effective_C++_条款三十九:明智而审慎地使用private继承
private继承的意义在于“be implemented in turns of”,这个与上一条款中说的复合模型的第二层含义是相同的,这也意味着通常我们可以在这两种设计方法之间转换,但书上还是更提倡 ...
- 读书笔记_Effective_C++_条款三十四:区分接口继承和实现继承
这个条款书上内容说的篇幅比较多,但其实思想并不复杂.只要能理解三句话即可,第一句话是:纯虚函数只继承接口:第二句话是:虚函数既继承接口,也提供了一份默认实现:第三句话是:普通函数既继承接口,也强制继承 ...
随机推荐
- mysql只读模式的设置方法与实验【转】
在MySQL数据库中,在进行数据迁移和从库只读状态设置时,都会涉及到只读状态和Master-slave的设置和关系. 经过实际测试,对于MySQL单实例数据库和master库,如果需要设置为只读状态, ...
- Linux学习笔记-文件系统和基本命令
目录 分区设备文件名 分区 挂载 文件目录 文件处理命令 目录处理命令 硬件设备文件名 IDE硬盘 /dev/hd[a-d] USB硬盘 /dev/sd[a-p] 光驱 /dev/cdrom或者/de ...
- 激活Win10内置版Linux (ubuntu)
微软自从14316版本后,就开始原生支持Linux Bash命令行. 1.首先到系统设置——更新和安全——针对开发人员——选择开发者模式. 2.控制面板→程序和功能→启用或关闭Windows功能,勾 ...
- CVE-2010-0249 极光
传说中的极光漏洞 Microsoft Internet Explorer非法事件操作内存破坏漏洞 Microsoft Internet Explorer是微软Windows操作系统中默认捆绑的WEB浏 ...
- Ninject中调用webapi卡住的情况解决
过年这两天在家做项目,把mvc升级到了5.1,webapi升级到了2.1,忽然发现一个问题,在某些页面上ajax调用webapi时会发现卡死现象,CPU也没有被占用,就是网页一些在加载也不报错,经过2 ...
- 在oracle中varchar和varchar2有什么区别?
1.varchar2把所有字符都占两字节处理(一般情况下),varchar只对汉字和全角等字符占两字节,数字,英文字符等都是一个字节:2.VARCHAR2把空串等同于null处理,而varchar仍按 ...
- JavaScript工程师都应懂的33个概念
最近福利发的有点多啊,各种硬干货,小伙伴们是不是觉得很爽啊.Github真的蕴含着各种各样的宝藏,难怪各个大厂也都纷纷贡献自己的代码到Github上. 所以各种干货还是会源源不断的po给大家,觉得有帮 ...
- centos下安装zabbix
1. 安装mysql CREATE DATABASE zabbix;GRANT ALL ON zabbix.* TO 'zabbix'@'192.168.19.%' IDENTIFIED BY '12 ...
- CCF CSP 201709-1 打酱油
CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201709-1 打酱油 问题描述 小明带着N元钱去买酱油.酱油10块钱一瓶,商家进行促销,每买 ...
- 【转】Android开启网络调试的方法
方法是偶然看到的: Android 终端adbd服务需要开启5555号端口来建立于adb的连接,如果未开启5555端口,则不能通过网络调试 查看是否可以网络调试: # netstat Android ...