读书笔记_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++_条款三十四:区分接口继承和实现继承
这个条款书上内容说的篇幅比较多,但其实思想并不复杂.只要能理解三句话即可,第一句话是:纯虚函数只继承接口:第二句话是:虚函数既继承接口,也提供了一份默认实现:第三句话是:普通函数既继承接口,也强制继承 ...
随机推荐
- 2017北京网络赛 Bounce GCD加找规律
题目链接:http://hihocoder.com/problemset/problem/1584 题意:就是求一个小球从矩阵的左上角,跑到矩形的右下角不能重复经过的格子,小球碰到墙壁就反射. 解法: ...
- Gradle教程链接
Gradle教程:https://www.yiibai.com/gradle/ https://www.cnblogs.com/wxishang1991/p/5532006.html
- spring学习之一概念
概念 1.是开源的轻量级框架 2.是一站式框架,就是说在java ee的三层结构中,每一层它都提供了不同的解决技术 web层:springMVC servoce层:spring IOC ,控制反转,通 ...
- jupyter(ipython notebook) 安装和入门教程
近期大家无论是自己做数据分析还是紧急答辩做PPT,可能都需要画一些数据的展示图:以前大家都是用excel画图,但excel画图存在一定的局限性,比如你要画个累积直方图,excel就很麻烦了,所以给大家 ...
- python_Appium测试环境搭建
Android环境搭建 移动端Appium环境部署比Web的selenium环境稍微复杂一些,如用python编写测试用例脚本或者开发测试框架以及UI自动化操作方法是一样的,基本是通用.因两者都是基于 ...
- C#比较时分秒大小,终止分钟默认加十分钟,解决跨天、跨月、跨年的情况
private void cmbInHostimes_SelectedIndexChanged(object sender, EventArgs e) { DataRow[] dr; if (chkM ...
- android拾遗——Android 动画学习笔记
3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:property animation,这三 ...
- 不要62 hdu 2089 dfs记忆化搜索
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意: 给你两个数作为一个闭区间的端点,求出该区间中不包含数字4和62的数的个数 思路: 数位dp中 ...
- Ajax与传统Web开发的区别
基本概念 1.1,Ajax AJAX:即“Asynchronous Javascript And XML”(异步的JavaScript和XML),是指一种创建交互式网页应用的网页开发技术,尤其是在一种 ...
- [ 转载 ] Mysql 数据库常用命令
完整的创建数据库例子: >create database db_test default character set utf8 collate utf8_general_ci; >use ...