Effective C++笔记 (6.继承与面向对象设计)

public继承 意味着 is-a 
virtual函数意味“接口必须被继承”
non-virtual函数意味着“接口和实现都必须被继承”

条款32:确定你的public继承塑模出is-a关系

C++面向对象编程,最重要的一个规则是:public inheritance(公开继承)意味“is-a”(是一种)的关系。

is-a并非是唯一存在于classes之间的关系。另两个常见的关系是has-a(有一个)和is-implemented-in-terms-of(根据某物实现出)。

请记住:
  • “public继承”意味is-a。适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived class对象也都是一个base class对象。

条款33:避免遮掩继承而来的名称

请记住:
  • derived classes内的名称会遮掩base classes内的名称。在public继承下从来没有人希望如此。
  • 为了让被遮掩的名称再见天日,可使用using声明式或转交函数(forwarding functions)。

条款34:区分接口继承和实现继承

public继承概念由两部分组成:函数接口(function interfaces)继承和函数实现(function implementations)继承。

  • 成员函数的接口总是会被继承。
  • 声明一个pure virtual函数的目的是为了让derived classes只继承函数接口。
  • 声明简朴的(非纯)impure virtual函数的目的,是让derived classes继承该函数的接口和缺省实现。

声明non-virtual函数的目的是为了令derived classes继承函数的接口及一份强制性实现。

请记住:
  • 接口继承和实现继承不同。在public继承之下,derived classes总是继承base class的接口。
  • pure virtual函数只具体指定接口继承。
  • 简朴的(非纯)impure virtual函数具体指定接口继承及缺省实现继承。
  • non-virtual函数具体指定接口继承以及强制性实现继承。

条款35:考虑virtual函数以外的其它选择

    “令客户通过public non-virtual成员函数间接调用private virtual函数”称为 non-virtual interface(NVI)手法。它是所谓Template Method设计模式(与C++ templates并无关联)的一个独特表现形式。把这个non-virtual函数(healthValue)称为virtual函数的外覆器(wapper)。

一般而言,唯一能够解决“需要以non-member函数访问class的non-public成分 ”的办法就是:弱化class的封装。

本条款的根本忠告是,当你解决问题而寻找某个设计方法时,不妨考虑virtual函数的替代方案。、
  • 使用non-virtual interface(NVI)手法,那是Template Method设计模式的一种特殊模式。它以public non-virtual成员函数包裹较低访问性的virtual函数。
  • 将virtual函数替换为“函数指针成员变量”,这是Strategy设计模式的一种分解表现形式。
  • 以trl::function成员变量替换virtual函数,因而允许使用任何可调用物(callable entity)搭配一个兼容于需求的签名式。
  • 将继承体系内的virtual函数替换为另一个继承体系内的virtual函数。这是Strategy设计模式的传统实现手法。

请记住:
  • virtual函数的替代方案包括NVI手法及Strategy设计模式的多种形式。
  • 将机能从成员函数移到class外部函数,带来的一个缺点是,非成员函数无法访问class的non-public成员。
  • trl::function对象的行为就像一般函数指针。这样的对象可接纳“与给定之目标签名式(target signature)兼容”的所有可调用物(callable entities)。

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

请记住:
  • 绝不重新定义继承而来的non-virtual函数。

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

静态绑定又名前期绑定,early binding;
动态绑定又名后期绑定,late binding。

请记住:
  • 绝对不要重新定义一个继承而来的缺省参数值,因为缺省参数值都是静态绑定,而virtual函数-你唯一应该覆写的东西-却是动态绑定。

条款38:通过复合塑模出has-a或“根据某物实现出”

请记住:
  • 复合(composition)的意义和public继承完全不同。
  • 在应用域(application domain),复合意味has-a。在实现域(implementation domain),复合意味is-implemented-in-torms-of(根据某物实现出)。

条款39:明智而审慎地使用private继承

请记住:
  • Private继承意味is-implemented-in-terms of(根据某物实现出)。它通常比复合(composition)的级别低。但是当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数,这么设计是合理的。
  • 和复合(composition)不同,private继承可以造成empty base最优化。这对致力于“对象尺寸最小化”的程序库开发者而言可能很重要。

条款40:明智而审慎地使用多重继承

对virtual base classes(亦相当于virtual继承)的忠告很简单。
第一,非必要不使用virtual bases。平常请使用non-virtual继承。
第二,如果必须使用virtual base classes,尽可能避免在其中放置数据。

请记住:
  • 多重继承比单一继承更复杂。它可能导致新的歧义性,以及对virtual继承的需要。
  • virtual 继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes不带任何数据,将宿舍最具实用价值的情况。
  • 多重继承的确有正当用途。其中一个情节涉及“public继承某个Interface class”和“private继承某个协助实现的class”的两相组合。


你可能感兴趣的:(C++)