条款32 确定你的public继承塑模出is-a关系
- public继承意味着“is-a”的关系
需要base class对象的地方,也可以给出derived class对象替代
条款33 避免遮掩继承而来的名称
derived class 的作用域嵌套于 base class 作用域之内
- derived classes 内的名称会遮掩 base classes 内的名称。
- 如果想要推翻遮掩继承而来的名称,可以使用 using 声明式。在 derived class 中使用 using 来声明 base class 中的名称,使它可见!
条款34 区分接口继承和实现继承
public继承分为:函数接口继承 和 函数实现继承。
- 声明一个 pure virtual 函数的目的是为了让 derived classes 只继承函数接口
- 声明 impure virtual 函数的目的,是让 derived classes 继承该函数的接口和缺省实现
父类的虚函数如果有定义,子类可以不重写;没有定义则要重写。
父类的纯虚函数,子类必须重写,否则会让子类也成为抽象类
- 声明一个 non-virtual 函数的目的是为了令 derived classes 继承函数的接口及一份强制性实现 | pure virtual 函数 | impure virtual 函数 | non-virtual 函数 | | —- | —- | —- | | 只继承接口 | 继承接口和一份缺省实现 | 继承接口和一份强制实现 |
条款35 考虑virtual函数以外的其他选择
藉由Non-Virtual Interface手法实现Template Method模式
这一设计模式思路,令客户通过public non-virtual成员函数间接调用private virtual函数,这个non-virtual函数称为virtual函数的外覆器(wrapper)。
这种(NVI)手法优点在于,可以在调用virtual函数之前,进行一些场景布置;在调用之后可以做一些清理工作。
std::function
对象可以保存任何可调用物,函数指针、函数对象或成员函数指针,只要其签名式兼容于需求端。
此外,这个可调用物的参数可以被隐式转换成function中定义的。
条款36 绝不重新定义继承而来的non-virtual函数
- non-virtual 函数都是静态绑定
- virtual函数是动态绑定
绝不要重新定义继承而来的non-virtual函数。
条款37 绝不重新定义继承而来的缺省参数值
动态类型:参数目前所指对象的类型。调用 virtual 函数,取决于发出调用的那个对象的动态类型。
- virtual 函数是动态绑定,而缺省参数值却是静态绑定。
C++这样运作的原因:运行期效率。
如果缺省参数值是动态绑定,编译器就必须有某种办法在运行期为 virtual 函数决定适当的参数缺省值。这比在编译器决定的机制更慢且更复杂。
一种解决方案是NVI手法:令 base class 内的一个 public non-virtual 函数调用 private virtual 函数,后者可以被derived classes 重新定义。而且可以在这里让 non-virtual 函数指定缺省参数,而 private virtual 函数负责真正的工作。
条款38 通过复合塑模出has-a或“根据某物实现出”
在应用域,复合意味着has-a。
在实现域,复合意味着is-implemented-in-terms-of(根据某物实现出)
条款39 明智而审慎地使用private继承
- 如果classes之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象。
- 由private继承而来的所有成员,在derived class中都会变成private属性
private继承意味着只有实现部分被继承。接口部分应略去。说明derived class根据base class实现而得。
面对大小为零的独立(非附属)对象,C++官方勒令默默安排一个char到空对象中。
- private继承意味着根据某物实现出。它通常比复合的级别低。
- private继承可以造成empty base最优化,可以做到“对象尺寸最小化”
条款40 明智而审慎地使用多重继承
- C++解析重载函数调用的规则:在看到是否有个函数可取用之前,C++首先确认这个函数对此调用是最佳匹配。找到最佳匹配后才检验其可用性。
避免菱形继承带来的两份间接基类的数据,可以令间接基类(最顶部的)成为virtual base class
IOFile直接继承InputFile和OutputFile在File中的共同成员,再继承他俩各自的新增成员
virtual 继承的那些 classes 所产生的对象会比 non-virtual 大;访问 virtual base classes 的成员变量时,也比访问non-virtual 的慢。
- 如果 virtual 继承不带有任何数据,那么将是最具使用价值的情况。