0%

6 继承与面向对象设计

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

  1. public inheritance(公开继承)意味”is-a“(是一种)的关系。
  2. 令class D(”Derived”)以public形式继承class B(“Base”),意味着每个类型为D的对象同时也是一个类型为B的对象,反之不成立。B比D概念上更一般化,D比B更特殊化。
  3. 对于现实世界,我们可能对已有事物进行概念上的内涵和外延来抽象不同的状态和动作。企鹅是一种鸟,然而它不会飞,对于鸟会飞的先入为主的观念,可能会使实际偏颇。“企鹅不会飞”这一限制可由编译期强制实施,但若违反“企鹅尝试飞行,是一种错误”这一条规则,只有运行期才能检测出来。
  4. is-a并非是唯一存在于classes之间的关系。另两个常见的关系是has-a(有一个)和is-implemented-in-terms-of(根据某物实现出)。

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

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

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

  1. public继承概念由两部分组成:函数接口function interfaces)继承和函数实现function implementations)继承。
  2. 声明一个pure virtual函数的目的式为了让derived classes只继承函数接口。声明纯朴的impure virtual函数的目的,是让derived classes函数继承改函数的接口和缺省实现。声明non-virtual函数的目的是为了令derived classes继承函数的接口及一份强制性实现。

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

  1. 令客户通过public non-virtual成员函数间接调用private virtual函数,称为non-virtual interface(NVI)手法。它是Template Method设计模式的独特表现形式。
  2. Strategy设计模式简单应用:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    // NVI写法
    class GameCharacter
    {
    public:
    int healthValue() const
    {
    ...
    int retVal = doHealthValue();
    ...
    return retVal;
    }
    ...
    private:
    virtual int doHealthValue() const
    {
    ...
    }
    };

    // Function Pointers写法
    class GameCharacter; // forward declaration
    int defaultHealthCalc(const GameCharacter &gc);
    class GameCharacter
    {
    public:
    typedef int (*HealthCalcFunc)(const GameCharacter&);
    explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf) {}
    int healthValue() const
    { return healthFunc(*this); }
    ...
    private:
    HealthCalcFunc healthFunc;
    };

    // std::fucntion写法
    // 与FP写法不同的是,std::function对象相当于一个指向函数的泛化指针。
    class GameCharacter;
    int defaultHealthCalc(const GameCharacter &gc);
    class GameCharacter
    {
    public:
    typedef std::function<int (const Characater&)> HealthCalcFunc;
    explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf) {}
    int healthvalue() const
    { return healthFunc(*this); }
    ...
    private:
    HealthClacFunc healthFunc;
    };

    // 古典设计模式写法
    class GameCharacter;
    class HealthCalcFunc
    {
    public:
    ...
    virtual int calc(const GameCharacter &gc) const
    { ... }
    ...
    };
    HealthCalcFunc defaultHealthCalc;
    class GameCharacter
    {
    public:
    explicit GameCharacter(HealthCalcFunc *phcf = &defaultHealthCalc) : pHealthCalc(phcf) {}
    int healthvalue() const
    { return pHealthcalc->calc(*this); }
    ...
    private:
    HealthCalcFunc *pHealthcalc;
    };
    ```C++
    // 有着更惊人的弹性

// 健康计算函数
short calchealth(const GameCharacter&);
// 为计算健康而设计的函数对象
struct HealthCalclator
{
int operator()(const GameCharacter&) const
{ … }