More C++ Idioms/查询能力

维基教科书,自由的教学读本

查询能力(Capability Query)
[编辑]

目的[编辑]

在执行期间,检查是否物件支持一个界面

别名[编辑]

动机[编辑]

从实作分离出界面是一个好的物件导向设计练习。在C++,界面类别惯用语(Interface Class idiom)被用于从实作分离出界面,而且借由执行期间多型(polymorphism)唤起任意抽象类(abstraction) 的公用的成员函数。扩展界面类别惯用语的范例,一个具象的类别(concrete class)可能继承多个界面,如以下所示。

class Shape { // 介面類別
   public:
    virtual ~Shape();
    virtual void draw() const = 0;
    //...
};
class Rollable { // 又一個介面類別
  public:
    virtual ~Rollable();
    virtual void roll() = 0;
};
class Circle : public Shape, public Rollable { // circles roll - 具象的類別
    //...
    void draw() const;
    void roll();
    //...
};
class Square : public Shape { // squares 不能 roll - 具象的類別
    //...
    void draw() const;
    //...
};

现在假设我们得到抽象类别的指标容器,我们在每个指标能简单唤起函数roll(),就如同界面惯用语所描述。

std::vector<Rollable *> rollables;
// 以某種方法去填補指標向量容器。
for (vector<Rollable *>::iterator iter (rollables.begin());
     iter != rollables.end();
     ++iter)
{
  iter->roll();
}

有时候,不可能事先知道物件是否有实作一个特定界面。这样的情况普遍发生在一个物件有继承多个界面类别。使用查询能力惯用语是为了知道在执行期间界面存在与否。

解决方案与范例程式[编辑]

在C++ ,查询能力(Capability Query)典型被表示在不相关的资料型态之间一个动态型别转换dynamic_cast。 ( if you're using w/o RTTI, dynamic_cast to derived class may have a compile error)

Shape *s = getSomeShape();
if (Rollable *roller = dynamic_cast<Rollable *>(s))
  roller->roll();

使用dynamic_cast经常被称作跨型别转换(cross-cast),因为它企图转换透过阶层,而不是往上或往下到一个阶层。 在此范例中ShapeRollable的阶层,使用dynamic_cast 转换型别到 Rollable 将只成功在Circle,而不是Square。因为,Square并没有继承界面类别 Rollable

查询能力(Capability Query)过度使用经常是物件导向设计不良的迹象。

已知应用[编辑]

Acyclic Visitor Pattern - Robert C. Martin.

相关的惯用语[编辑]

参考[编辑]

Capability Queries - C++ Common Knowledge by Stephen C. Dewhurst