階層構造の継承(昨日の続き)

#include
using namespace std;

template  class M{
public:
     T* Alloc(void){return new T;}
};

class B1{
public:
     int x;
     virtual ~B1(){}
};
class A1{
public:
     B1 *b1;
     M b1alc;
     A1(){b1 = b1alc.Alloc();}
     virtual void f(int i){b1->x = i;}
};

class B2 : public B1{
public:
     int y;
};
class A2 : public A1{
public:
     M b2alc;
     A2(){b1 = b2alc.Alloc();}
     virtual void f(int i, int j){
          A1::f(i);
          B2 *b2 = dynamic_cast(b1);
          b2->y = j;
     }
};
int main(void){
     A2 a2;
     a2.f(10, 20);
     B2 *b2 = dynamic_cast(a2.b1);
     cout << b2->x << " " << b2->y << endl;
}

えと、

A1 -------- B1
← 継承 ← 継承
A2 -------- B2

A1がメンバ変数にB1を持っている、という構造でA1とB1をそれぞれ拡張したクラスを作りたいとする。こういうときはやっぱりテンプレート使った方が効率いいんだろうか・・・。しかしそれだとクラス全体をテンプレートで記述しないといけなくなるし。ということで苦肉の策としてアロケータを作ることに。しかしこれでも問題があって

  1. ダウンキャストが避けられない
  2. あらかじめこういう使われ方をされることを予測してスーパークラスを設計しなければいけない

と思う。特に2番目はオブジェクト指向としてどうなのか。サブクラスの仕様にスーパークラスの仕様が依存するというのもおかしな話だ。

テンプレートを使っても2番目の問題は変わらないわけで。

ということで、強引な解決法としては、A1にB1へのポインタ、A2にはB2のポインタを持たせておいて、A2ではB1とB2のポインタが同じものを指すようにする。こうすればとりあえずA1側で仕様を変える必要はないし、ダウンキャストもいらない。あとB1とかを無駄にpolymorphicにする必要もない。ただ同じものを指すポインタを何個も持つってのは微妙だし、新しいオブジェクトをnew()して古いのをdelete()するってのも無駄なオーバーヘッドではある。結局テンプレートが一番無駄がないってことでしょうかね。

#include
using namespace std;

class B1{
public:
     int x;
};
class A1{
public:
     B1 *b1;
     A1(){ b1 = new B1; }
     virtual void f(int i){b1->x = i;}
};

class B2 : public B1{
public:
     int y;
     B2(const B1 * const b1){
          x = b1->x;
     }
};
class A2 : public A1{
public:
     B2 *b2;
     A2(){
          A1::A1();
          b2 = new B2(b1);
          delete b1;
          b1 = b2;
     }
     virtual void f(int i, int j){
          A1::f(i);
          b2->y = j;
     }
};
int main(void){
     A2 a2;
     a2.f(10, 20);
     cout << a2.b2->x << " " << a2.b2->y << endl;
}

まあ、泥臭いけどテンプレートを使いたくないなら一番いい解決法なのかも????難しいです・・・。サブクラス側で対応っていうのが個人的にはいいと思うので、これで行ってみますか。