本文内容基本来自于《Effective C++》一书,为学习后的笔记,以便温故。
《Effective C++ 》第 6节 继承与面向对象设计
(1)条款32:确定你的public继承塑模出is-a关系
public继承 意味is-a。适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived class对象也都是一个base class 对象。
(2)条款33:避免遮掩继承而来的名称
derived classes内的名称会遮掩base classes内的名称,在public继承下从来没有人希望如此。
为了让被遮掩的名称在再见天日,可使用using声明式或者转交函数。
(3)条款34:区分接口继承与实现继承
接口继承与实现继承不同,在public继承之下,derived classes总是继承base classes的接口。
pure virtual函数只具体制定接口继承
简朴的impure virtual函数具体制定接口继承及缺省实现继承
non-virtual函数具体指定接口继承以及强制性实现继承
(4)条款35:考虑virtual函数以外的其他选择
藉由non-virtual interface手法实现 template method模式
这种流派主张virtual函数应该几乎总是private。较好的设计是使用一个non-virtual的public成员函数作为对外的接口,并调用一个private virtual函数进行实际工作。
藉由Function Pointers实现strategy模式
这种方法主张类中接受一个函数指针,指向要执行的动作。从而实现不同的策略。
藉由tr1::function完成strategy模式
这种方法不再使用函数指针,而是改用一个类型为tr1::function的对象。
定义式:typedef std::tr1::function<int (const GameCharacter&)>HealthCalcFunc;
这个签名代表的函数“接受一个reference指向const GameCharacter,并且返回int”。这个tr1::function类型产生的对象可以持有任何与签名式兼容的可调用物。所谓兼容,意思是这个可调用物的参数可被隐式转换成const GameCharacter&,而其返回类型可被隐式转换为int。(这种方法没有明白,还要继续研究。)
(5)条款36:绝不重新定义继承而来的non-virtual函数
(6)条款37:绝不重新定义继承而来的缺省参数值
virtual函数是动态绑定,而non-virtual则是静态绑定,缺省参数值是静态绑定。
静态绑定就是他在程序中被声明时所采用的类型,动态类型是指“目前所指对象的类型”。也就是说,动态类型可以表现出一个对象将会有什么行为。
例如:class Shape{
public:
virtual void draw(ShapeColor color =Red)const = 0;
}
class Rectangle:public Shape{
public:
virtual void draw(ShapeColor color =Green) const ;
}
Shape* pr = new Rectangle();
pr->draw(); //此时默认的参数不是Green而是Red,因为,缺省参数值静态绑定!
(7)条款38:通过复合塑模出has-a或者“根据某物实现出”
复合的意义和public继承完全不同
在应用领域中,复合意味着has-a。在实现领域中,复合意味着is-implemented-in-terms-of(根据某物实现出),例如通过list实现set。
(8)条款39:明智而审慎地使用private继承
Private继承意味is-implemented-in-terms of。它通常比复合的级别低。但是当derived class需要访问protected base class的成员,或者需要重新定义继承而来的virtual函数时,这样设计是合理的。
和复合不同,private继承可以造成empty base最优化。这对致力于“对象尺寸最小化”的程序库开发者而言,可能很重要。
(9)条款40:明智而审慎地使用多重继承
多重继承比单一继承复杂,它可能导致新的歧义性,以及对virtual继承的需要。
virtual继承会增加大小,速度,初始化复杂度等成本。如果virtual base classes不带任何数据,将是最具实用价值的情况
多重继承的确有正当用途,其中一个情节涉及“public 继承某个Interface class”和“private继承某个协助实现的class”的两相组合。