動的継承とは
C++で提供している機構では、静的な継承しか許されていない。
しかし、動的継承に近いことは可能である。
この方法は、「オブジェクト指向における再利用のためのデザインパターン」(SOFTBANK)
の本に出てくるDecoratorパターンを読んで気づいたものである。
この方法の特徴をあげよう。
メリット
デメリット
- メッソドを全て仮想にしなければいけない。(必須ではないけども)
- コストがかかる。すなわち、実行速度も遅くなり、メモリも余計にかかる。
- デバッグしにくい。
- 動的継承の段階でconst属性が失われる。
(失いたくなかったら、const 用のクラスを作ることも考えられる。)
見ての通り、メリットよりデメリットの方が多く、殆ど使う機会はないかもしれない。
実際、有用となるのは、「掛算の数のクラスを足算の数に減らせる場合」ぐらいであろう。
しかし、プログラマとして興味をそそられる手法ではある。
さて、例を見てみよう。
次のような部品があるものとする。
さらに、次のような種類があるものとする。
(これを属性にしてしまったら、話は進まないので、クラスにしなければいけないとしよう。)
つまり、「通常ウィンドウ」、「枠付ウィンドウ」、「影付ウィンドウ」、
「通常ボタン」、「枠付ボタン」、「影付ボタン」、
「通常メニュー」、「枠付メニュー」、「影付メニュー」の9つのクラス(n×m)が
必要ということになる。
これを、「ウィンドウ」、「ボタン」、「メニュー」、「通常」、「枠付」、「影付」の
6つのクラス(n+m)でやろうというのが、動的継承である。
(まあ、常識で考えると「通常」はいらないかもしれないが。)
具体的にちょっと書いてみよう。
struct Widget {
virtual void Draw();
};
struct Window : Widget {
void Draw(){ ... /* ウィンドウを描く */ }
};
struct Border : Widget {
Widget* m_p;
Border(Widget* p) : m_p(p) {}
void Draw(){ p->Draw(); ... /* 枠も描く */ }
};
Window w;
Widget* p = new Border(&w); // これが動的継承
p->Draw();
Widget* p2 = new Shadow(p);
p2->Draw(); // 枠も影も描く
(上のプログラムでは、雰囲気だけ分かるように手を抜いてある。)
これを見ても分かるように、何段にも重ねて継承を行うこともできる。
詳細については、先の本を参照して欲しい。
個人的には、何らかのインタープリタを実装するとき役に立つかもしれないと思っている。
戻る