条款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中定义的。

image.png

条款36 绝不重新定义继承而来的non-virtual函数

  • non-virtual 函数都是静态绑定
  • virtual函数是动态绑定

绝不要重新定义继承而来的non-virtual函数。

条款37 绝不重新定义继承而来的缺省参数值

动态类型:参数目前所指对象的类型。调用 virtual 函数,取决于发出调用的那个对象的动态类型。

  • virtual 函数是动态绑定,而缺省参数值却是静态绑定

image.png
image.png

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

image.png

IOFile直接继承InputFile和OutputFile在File中的共同成员,再继承他俩各自的新增成员

virtual 继承的那些 classes 所产生的对象会比 non-virtual 大;访问 virtual base classes 的成员变量时,也比访问non-virtual 的慢。

  • 如果 virtual 继承不带有任何数据,那么将是最具使用价值的情况。