继承与面向对象设计
32.确定你的public继承塑模出is-a关系
public继承意味着is-a,适用于baseclasses 身上的每一件事情一定也使用于derived classes身上,因为每一个derived class对象也都是一个baseclass对象
33.避免遮掩继承而来的名称
Derived classes内的名称为遮掩base classes 内的名称,在public继承下,从来没有人希望如此,因为public 继承锁暗示的base和derived classes之间是is-a关系。
为了让遮掩的名称再见天日,可使用using申明式 using Base::mf1
或者转交函数 virtual void mf1(){ Base::mf1();}
34.区分接口继承和实现继承
pure virtual 函数, simple(impure) virtual 函数,non-virtual函数之间的差异,使得你得以精确指定你想要derived classes继承的东西:只继承接口,或是继承接口和一份缺省实现, 或是继承接口和一份强制实现。由于这些不同类型的声明意味根本意义并不相同的事情,当你声明你的成员函数时,必须谨慎选择。
接口继承和实现继承不同,在Public继承之下,derived classes 总是继承base class的接口
Pure virtual函数只具体指定接口继承
简朴impure virtual函数具体指定接口继承及缺省实现继承
Non-virtual 函数具体指定接口继承以及强制性实现继承
35.考虑virtual函数以外的其他选择
NVI手法
36.绝不重新定义继承而来的non-virutal函数
在任何情况下,都不应该重新定义一个继承而来的non-virtual函数,否则会违背public继承的is-a的关系和违背non-virtual函数的不变性高于其特异性。
37.绝不重新定义继承而来的缺省参数值
你只能继承两种函数,virtual函数和non-virtual函数,而后者是错误的,那么可不可继承一个带有缺省参数的virtual函数呢?
virtual函数系动态绑定而来,调用一个virtual函数时,究竟调用哪一份函数实现代码,取决于发出调用的那个对象的动态类型。
而缺省参数值确实静态绑定(staticallybound)
38.通过复合塑模出has-a或“根据某物实现出”
list不能应用于set, list允许重复,而set不允许重复
复合(composition)的意义和Public继承完全不同
在应用域(applicationdomain),复合意味着has-a(有一个),在实现域(implementation domain),复合意味着is-implemented-in-terms-of(根据某物实现出)
39.明智而审慎地使用private继承
如果classes之间的继承关系是private,编译器不会自动将一个derived class对象转换成一个base class对象,这和public 继承不同,由private base class继承而来的所有成员,在derivedclass中都会变成private属性,纵使它们在baseclass中原本是protected 或public属性
在composition和private之间,尽可能使用复合,必要时才使用private继承。
private继承意味着只有实现部分被继承,接口部分应略去。如果D以private形式继承B,意思是D对象根据B对象实现而得,再没有其他意义了。
Private继承意味着is-implemented-in-terms of (根据某物实现出),它通常比复合(composition)的级别低,但是当derived class需要访问protectedbase class的成员,或需要重新定义继承而来的virtual函数时,这么设计是合理的
和复合(composition)不同,private继承可以造成empty base最优化,这对致力于“对象尺寸最小化”的程序库开发者而言,可能很重要
40.明智而审慎地使用多重继承
如果你有一个单一继承的设计方案,而它大约等价于一个多重继承设计方案,那么单一继承设计方案一定比较受欢迎。
多重继承比单一继承复杂,它可能导致性的歧义性,以及对virtual 继承的需要
virtual继承会增加大小,速度,初始化,复杂度等等成本,如果virtual base classes不带任何数据,将是最具使用价值的情况
多重继承的确有正当用途,其中一个情节设计"public 继承某个interface class"和“private继承某个协助实现的class”的两相组合。