跳转到内容

更多 C++ 惯用法/能力查询

来自维基教科书,开放书籍,为开放的世界

能力查询

[编辑 | 编辑源代码]

在运行时检查对象是否支持某个接口。

将接口与实现分离是良好的面向对象软件设计实践。在 C++ 中,接口类 惯用法用于将接口与实现分离,并使用运行时多态性调用任何抽象的公共方法。扩展接口类惯用法中的示例,具体类可以实现多个接口,如下所示。

class Shape {  // An interface class.
  public:
    virtual ~Shape();
    virtual void draw() const = 0;
    //...
};

class Rollable {  // One more interface class.
  public:
    virtual ~Rollable();
    virtual void roll() = 0;
};

class Circle : public Shape, public Rollable {  // Circles roll - concrete class.
    //...
    void draw() const override;
    void roll() override;
    //...
};

class Square : public Shape {  // Squares don't roll - concrete class.
    //...
    void draw() const override;
    //...
};

现在,如果我们得到一个指向抽象类 Rollable 的指针的容器,我们可以简单地对每个指针调用 roll 函数,如接口类惯用法中所述。

std::vector<Rollable *> rollables;
//  Fill up rollables vector somehow.
for ( Rollable * rPtr : rollables )
  rPtr->roll();

有时,我们无法提前知道对象是否实现了特定的接口。这种情况通常发生在对象从多个接口类继承时。为了在运行时发现接口的存在与否,可以使用能力查询。

解决方案和示例代码

[编辑 | 编辑源代码]

在 C++ 中,能力查询通常表示为在无关类型之间进行 dynamic_cast

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

这种 dynamic_cast 的用法通常称为交叉转换,因为它试图跨越层次结构进行转换,而不是向上或向下层次结构。在我们关于形状和可滚动对象的示例层次结构中,dynamic_castRollable 仅对 Circle 成功,而对 Square 则不成功,因为后者没有从 Rollable 接口类继承。

过度使用能力查询通常表明面向对象设计存在缺陷。

已知用途

[编辑 | 编辑源代码]
  • Martin,Robert C. "无环访问者模式" (PDF). {{cite web}}: |archive-url= requires |archive-date= (help)
[编辑 | 编辑源代码]
华夏公益教科书