05 December 2022

C++ 核心指南目录

C.120: Use class hierarchies to represent concepts with inherent hierarchical structure (only)

理由

在代码中直接表达设计思想,更容易理解和维护。请确保基类所表达的思想,保持在继承类中一致,并且没有其他更好的方式表达这种紧耦合的继承。

如果使用成员数据可以实现相同的目的,就不要使用继承。这种情况下,通常在继承类中,会重载基类的虚函数,或访问受保护的基类成员数据。

例子

class DrawableUIElement {
public:
    virtual void render() const = 0;
    // ...
};

class AbstractButton : public DrawableUIElement {
public:
    virtual void onClick() = 0;
    // ...
};

class PushButton : public AbstractButton {
    void render() const override;
    void onClick() override;
    // ...
};

class Checkbox : public AbstractButton {
// ...
};

例子

不要用类继承层级来表达非层级领域的概念。

template<typename T>
class Container {
public:
    // list operations:
    virtual T& get() = 0;
    virtual void put(T&) = 0;
    virtual void insert(Position) = 0;
    // ...
    // vector operations:
    virtual T& operator[](int) = 0;
    virtual void sort() = 0;
    // ...
    // tree operations:
    virtual void balance() = 0;
    // ...
};

此处,很多继承类无法很好实现这些接口函数。因此基类成了实现过程的负担。更进一步, Container 的用户无法依靠成员函数高效地执行某些操作。还可能会抛出异常。因此用户要依靠运行时检查或者干脆不使用这些过于通用的接口,转而利用运行时类型查询来调用特定的接口(比如dynamic_cast)。

强化

  • 查看是否存在这种情况:类有很多成员,并且这些成员函数什么也不做,只是抛出异常。
  • 标记非公开的基类 B 的子类 D 没有重载 B 中的虚函数或者会访问 B 中的保护成员。并且 B 不是以下类型:空类,D 的模板参数,D 的模板实例化。