条款39、明智审慎地使用private继承
来源:互联网 发布:c语言点滴 pdf 百度云 编辑:程序博客网 时间:2024/05/23 02:12
TK32论证了public继承是is-a关系。类student继承自类Person。于是在编译必要时student暗自转变为Person。现在考虑private继承:class Person{….};class Student:private Person{….};void eat(const Person& p); //任何人都会吃void study(const Student& s) ; //学生专属行为Person p;Student s;eat(p); //Teat(s); //F 错误,难道学生不是人?
很明显private继承不是is-a关系。
编译器不会将派生类对象转为基类对象,同时,private基类继承而来的所有成员,在派生类中都会变成private,无论原本在基类中是Protecte或public属性。
现在讨论其意义:private继承意味着就某物实现出。D private B,只是为了采用B内已经备妥的某些特性。私有继承纯粹只是一种实现技术。TK34术语:私有继承意味着只有实现部分被继承,接口部分应略去。D private B,即、D对象根据B对象实现而得。private在软件设计层面上没有意义,意义只在于软件实现层面。Private继承和复合都是根据某物实现出,取舍方法是:尽量使用复合,必要时才使用私有继承。主要是protected成员或虚函数牵扯进来的时候。假设有一个类Widget,因为知道要调用次数而使用Timer类:class Timer{ public: explicit Timer(int Frequncy); virtual void onTick() const; //定时器每响一次,函数调用一次….};
我们可以重新定义虚函数用以取出Widget当时状态。这样必须继承Timer。但public明显不合适,因为widget并不是一个Timer。那并不是Widget接口的一部分。如果那样调用,会违反TK18“让接口易正确使用不易被调用”。于是我们采用private:class Widget: private Timer{ private: virtualvoid onTick() const; //查看Widget数据等};
这样onTick函数由公有变为私有函数,我们重新定义时仍把它留在那。
这虽然是个好设计,但私有继承并非绝对必要。我们可以采用复合的方法。如下:class Widget{ private: classWidgetTimer: public Timer{ public: virtual void onTick() const;}WidgetTimer timer;};
这样做的好处是:
1、Widget可以拥有Timer类,但又能防止派生类改写onTick函数。如果是继承Timer则不可能实现(私有继承也如此),因为派生类总是可以重定义虚函数。WidgetTimer是该类的私有成员,派生类无法取得,这样也就无法定义WidgetTimer的虚函数了。类似于Java的final----“阻止派生类重新定义虚函数”
2、降低编译依存性。如果是继承,Widget编译时Timer必须可见,即需要#include”Timer.h”.如果WidgetTimer移出widget,widget内只包含一个指 向WidgetTimer的指针。widger只需带一个简单的WidgetTimer声明,无需include任何与Timer相关的东西。
但涉及一种激进情况或空间最优化时,我们应选择“私有继承”而非“继承加复合”C+规定:独立对象必须具有非零大小。如下:class Empty{…}; //为空class anInt{ private: Empty e; //应该不需要内存 int x;}
你会发现sizeof(anInt)>sizeof(int); 而在大多数编译器中sizeof(Empty)为1.
因为面对“大小为零的独立对象”:C+官方默默安插一个char对象到空对象。
但又根据齐位需要,anInt不只是获得一个char大小,而是被放大到int.
但这个约束不适用于派生类的基类成分。如下:class anInt:private Empty{ private: int x;};
这样就保证了sizeof(anInt)=sizeof(int); 这就是EBO(empty base optimization)空白基类最优化。如果在意空间的情况下,可以采用EBO。但注意的是只能是单一继承,无法施行于拥有多个基类的派生类上。
事实上“空”类也不一定是空的,虽然没有非静态成员,但往往有typedef,enum,static成员。如STL中就有许多有用的空类。这样,EBO很少成为private继承的正当理由。复合和私有继承都是is-implemented-in-terms-of. 但只要在可以的情况下,都应选择复合。
但对于两个并不存在is-a关系的类,一个需要访问另一个的protected成员或要重新定义一个或多个虚函数,私有继承可能成为正统方法。
需要记住的:1、私有继承意味着根据某物实现出,通常比复合级别低。但当派生类需要访问protected base的成员或要重新定义继承而来的虚函数时,这么设计是合理的。2、和复合不同,私有继承可以empty base最优化。这对于空间要求高的开发而言很重要。
0 0
- 条款39:明智而审慎地使用private继承
- 条款39:明智而审慎地使用private继承
- 条款39、明智审慎地使用private继承
- 条款39:明智而审慎地使用private继承
- Effective C++:条款39:明智而审慎地使用private继承
- 读书笔记《Effective C++》条款39:明智而审慎地使用private继承
- [effectiv c++]条款39:明智而审慎地使用private继承
- 条款39:明智而审慎的使用private继承
- 条款40:明智而审慎地使用多重继承
- 条款40:明智而审慎地使用多重继承
- 条款39:明智而审慎的适用private继承
- item39:明智而审慎地使用private继承
- Effective C++ Item 39 明智而审慎地使用 private 继承
- C++之明智审慎地使用private继承(39)---《Effective C++》
- 明智而审慎的使用private继承
- 明智而审慎的使用Private继承
- Effective C++:条款40:明智而审慎地使用多重继承
- 读书笔记《Effective C++》条款40:明智而审慎地使用多重继承
- JAVA输出文件中的文件名
- UML类图几种关系的总结
- 用c语言实现闰年的查找或判断
- SQL2008无法连接到.\SQLEXPRESS,用户'sa'登录失败(错误18456)图文解决方法
- (四)yii修改表结构导致model创建表单出现字段为定义
- 条款39、明智审慎地使用private继承
- Linux文件路径中所有目录名必须都存在,而Windows不需要
- halcon学习之路
- 判断MST是否唯一
- 第四题(String的split方法)
- [boost]无法打开文件“libboost_thread-vc90-mt-sgd-1_43.lib”解决思路
- 槿叶轩记
- 流程、活动、工作项的定义
- 编程小混混闯入Windows phone