Item 39 私有继承
来源:互联网 发布:美国矩阵风投公司资料 编辑:程序博客网 时间:2024/05/19 13:07
C++编译器把公有继承的类当作基类的特例,私有继承则不同:
可以看到,编译器并不把派生类对象转化为基类对象。
而且,所有基类的成员函数在派生类里都成为私有的。
公有继承中,基类和派生类有“类型”上的一致性;私有继承中,派生类只是对基类的某些成员函数感兴趣,借助它们实现功能。
所以,私有继承只继承了所有的“实现”细节,并不继承基类的接口。所以,私有继承和软件设计没关系,只和软件实现有关系。
Item 38引入的复合模式也是针对实现的。那么在实现时,如何在二者之间选择?答案:
1> 尽量用复合模式。
2> 如果涉及到protected member或者虚函数,考虑私有继承。
3> 一种极端情况。
看下例的widget。
如果一个软件的执行是分阶段的,那么不同的阶段肯定会有不同的执行模式。我们要跟踪每个成员函数的执行,然后定时汇报情况,同时输出widget的状态。所以我们需要Timer类:
不过,要想自定义onTick,必须使用继承!而且公有继承不行,因为Widget明显不是Timer,二者不能在类型上有继承关系。也不能让Widget客户使用onTick这个接口。所以:
如果不使用私有继承,使用“复合 + 公有继承”的话:
虽然可行,但是麻烦。
使用“复合 + 公有派生”这种方案是这么考虑的:
1> 你想让Widget有被派生的能力,但是又不想让其onTick被重定义。那么就不能让Widget直接从Timer派生,私有派生也不行。Item 35说了,派生类即使不能访问,也能重定义派生来的虚函数。所以Widget自建了一个私有的WidgetTimer类,只供自己使用,不让派生类染指。
2> 可以减小Widget对Timer的编译依赖。Widget如果从Timer派生,必须要#include "Timer.h",以便在编译时找到其定义。这就是依赖了!使用WidgetTimer,可以只用一个指针,然后把WidgetTimer移到外面,则去掉了依赖。
使用私有继承的极端情况:你要处理一个不占内存的类(该类没有non-static数据成员,没有虚函数,没有虚基类)。
但出于技术原因,C++不允许出现空类!
此时,sizeof(HoldsAnInt) > sizeof(int)。而且大多数编译器里,sizeof(Empty) = 1。C++会在空类里悄悄插个char。而且编译器对类做对齐处理,所以HoldsAnInt不会只有一个多余的char。
不过,空类不空,这种情况只用于那些freestanding类。这些类不和别的类构成继承关系。有继承关系就不一样了:
此时,sizeof(HoldsAnInt) == sizeof(int)。这有个编译器专门术语:EBO——empty base optimization。EBO只存在于单继承。
- Item 39 私有继承
- [翻译] Effective C++, 3rd Edition, Item 39: 谨慎使用 private inheritance(私有继承)(上)
- [翻译] Effective C++, 3rd Edition, Item 39: 谨慎使用 private inheritance(私有继承)(下)
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 私有继承
- 公有继承和私有继承
- 保护继承类似私有继承。
- 7.25私有继承、保护继承
- LinkedHashMap的最近最少使用(LUR)算法实践-
- 禁止或要求对象产生于堆中
- STL:Sort用法
- 5.1加班工作记录
- 数据对齐与sizeof()
- Item 39 私有继承
- 【转】MiniGUI 1.3.3 移植详解 作者:大漠孤狼
- C#获取电脑硬件信息(CPU ID、主板ID、硬盘ID、BIOS编号)说明
- 去达内还是去黑马,我选黑马
- 【excel技巧】基本技巧一
- 对与连连看求解算法的研究
- JS数组及面向对象
- 试试
- 关于安装LINUX时找不到硬盘问题解决