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