More C++ Idioms/能力照会(Capability Query)

出典: フリー教科書『ウィキブックス(Wikibooks)』

能力照会(Capability Query)
[編集]

意図[編集]

あるオブジェクトがあるインタフェースに対応しているかどうかを実行時に確認する。

別名[編集]

動機[編集]

実装からインタフェースを分離することは、良いオブジェクト指向ソフトウェア設計の習慣である。 C++ では、インタフェースクラス(Interface Class)イディオムが、実装からインタフェースを分離するために使われ、いかなる抽象の public メソッドも実行時多態性を用いて呼び出される。 インタフェースクラスイディオムの例を拡張し、ある 1 つの具象クラスが、以下のように複数のインタフェースを実装することがあるかもしれない。

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 { // 円(circle)は転がる - 具象クラス
    //...
    void draw() const;
    void roll();
    //...
};
class Square : public Shape { // 正方形(square)は転がらない - 具象クラス
    //...
    void draw() const;
    //...
};

ここで、抽象 Rollable クラスへのポインタのコンテナがあるとして、インタフェースクラスイディオムに記述されているとおり、全てのポインタに対して roll 関数を呼び出すことができる。

std::vector<Rollable *> rollables;
//  どうにかして vector である rollables を埋める
for (vector<Rollable *>::iterator iter (rollables.begin());
     iter != rollables.end();
     ++iter)
{
  iter->roll();
}

あるオブジェクトがある特定のインタフェースを実装しているかどうか、前もって知ることができない場合がある。 あるオブジェクトが複数のインタフェースクラスを継承している場合に、そのような状況がよく発生する。 あるオブジェクトがあるインタフェースを実装しているかどうかを、実行時に正確に調べるために、能力照会(Capability Query)イディオムが使われる。

解法とサンプルコード[編集]

C++ において、能力照会は、典型的には無関係な型間に対する dynamic_cast として表現される。

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

dynamic_cast のこの使い方は、しばしば クロスキャスト(cross-cast) と呼ばれる。 なぜなら、階層を上下するというよりも、階層を横切って(across)変換を行うからである。 我々の Shape と Rollable による階層の例では、Rollable への dynamic_cast は Circle に対してのみ成功し、Square に対しては成功しない。なぜなら Square は Rollable から継承していないからである。

能力照会の多用は、大抵、悪いオブジェクト指向設計の兆候である。

既知の利用[編集]

Acyclic Visitor Pattern - Robert C. Martin.

関連するイディオム[編集]

References[編集]

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