More C++ Idioms/能力照会(Capability Query)
能力照会(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