虚函数意味着接口必须被继承,非虚函数意味着“接口和实现都必须被继承”。
条款32:确定你的public继承塑模除is-a关系
如果令class D以public形式继承class B,你便是告诉编译器,每个类型D对象同时也是一个类型B对象,反之则不成立。这个意思表明B比D表现的更一般化的概念,D比B表现的更特殊化的概念。public主张,能够施行于基类对象的每一件事,也可以施行于派生类上,如果这样的主张无法满足,则不应该以public变现基类和派生类的关系
条款33:避免遮掩继承而来的名称
派生类内的名称会遮掩基类中的名称。但在public继承中从来就没人希望如此,因为这会推翻public is-a的继承基础。如果在public继承中想重载基类中的函数,可以在派生类中使用using base::bf1;using base::bf2,使基类中被重载的函数在派生类可见
然而有时我们并不想继承基类中所有的函数,这是一个很常见的需求。虽然在public继承中,这绝对不可以发生,然而在private继承体系之下却是有意义的。假如派生类以private继承基类,但是派生类只想唯一继承的是bf1的那个无参版本,using声明在这里就用不上了,因为using声明式会令继承而来的某给定名称的所有同名参数在派生类中都可见。但是我们可以使用转交函数:即覆盖要继承的函数,然后在函数体中调用基类中的函数。
条款34:区分接口继承和实现继承
成员函数的接口都会被继承,但每个函数的声明方式都不相同:有纯虚函数,非纯虚函数,非虚函数,这些不同形式代表不同的实现继承方式:
(1)声明一个纯虚函数的目的是为了让派生类只继承函数接口。(虽然纯虚函数也可以提供函数定义,但在调用时必须明确指出)
(2)声明非纯虚函数的目的,是让派生类继承该函数的接口可缺省实现。
(3)声明非纯虚函数的目的是为了令派生类继承函数接口以及一份强制性实现。
条款35:考虑虚函数以外的其他选择
例:实现不同人物的不同血量,除了虚函数外,还可是
(1)藉由Non-virtual Interface 手法实现Template Method模式
这一基本设计,也就是”令客户通过public non-virtual成员函数间接调用private virtual函数,称为non-virtual interface手法“。(重新定义virtual函数表示某些事如何被完成,调用虚函数表示他何时被完成)。//但是如果派生类中的虚函数需要调用基类中的虚函数可能会有问题)
(2)藉由Function Pointers 实现strategy模式
例如我们可能会要求每个人物的构造函数都接受一个指针,指向一个健康计算函数,而我们可以调用该函数进行实际计算。。
这中设计提供了有趣的弹性:
(1)同一人物类型不同实体可以有不同的血量计算函数
(2)人物的健康函数可在运行期变更
//但如果健康函数需要访问类的成员,需要具体问题具体分析
(3)回调函数完成strategy
为什么”健康指数计算“必须是个函数,而不能是某种”像函数的东西“?
和前一个设计相比:在计算人物健康时可以使用任何兼容的可调物。(如函数,函数对象,成员函数。。。)
(4)古典设计
每个人物对象都含有一个指针,指向健康继承体系的对象。
条款36:绝不重新定义继承而来的非虚函数
这样会导致”精神分裂“。
条款37:绝不重新定义继承而来的缺省参数值
重新定义非虚函数永远都是错误的,所以本条款讨论”继承一个带有缺省参数的virtual“。
本条款成立的理由非常直接而确定:virtual函数系动态绑定,而缺省参数值确实静态绑定,导致的结果是函数来自派生类,参数来自基类。
条款37:通过复合塑模出has-a或者”根据某物实现出“
......
条款39:明智而审慎的使用private继承
如果class之间的继承关系是private,编译器不会自动将一个派生类对象转换为基类对象。
Private继承意味着根据某物实现出。
如果让class D以private形式继承class B,我们的用意是为了采用class内某些已经备妥的某些特性,不是因为B对象和D对象之间存在任何观念上的关系。
private继承纯粹只是一种是实现技术(这就是为什么继承自一个private base class的每样东西都是private的,因为他们只是实现的细枝末叶)。
在一般情况下,尽可能使用复合,必要时才使用private继承。
条款40:明智而审慎的使用多重继承
略。