閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

Capsule パターン (2)

現状こんな感じ。

// Base.h
struct IBase { virtual ~Base() {} };
struct IHoge { virtual void hoge() = 0; };

// Impl.h
struct BaseImpl : public IBase, public IHoge
{
  virtual void hoge() { /* ... */ }
};

// Client.cpp
#include "Base.h"
void main()
{
  IBase* p = FactoryMethod(); // BaseImpl のインスタンスが返ってくる
  //p->hoge(); //< ここで IHoge にキャストしないといけない
}

Client には BaseImpl は見せたくない (include させたくない) わけですが、このままでは実現することができません。そこで、これに先ほどの Capsule パターンを適用することにします。すると以下のようになるわけですが――。

// Base.h
struct Capsule { virtual ~Capsule() {} };
/* IBase, IHoge はさっきと同じ */

// Impl.h
struct BaseImpl : public IBase, public IHoge, public Capsule
{/* 中身はさっきと同じ */}

// Client.cpp
void main()
{
  Capsule* c = f(); // 戻り値の正体は BaseImpl
  if(IHoge* h = dynamic_cast(c))
  { 
    h->hoge();
  }
}

この main の中で呼び出している f() をどこに置くか、という問題。

// Base.h
struct IBase
{
  virtual Capsule* GetCapsule() = 0;
};

// Impl.h
struct BaseImpl : public IBase, public IHoge, public ICapsule
{
  virtual Capsule* GetCapsule() { return this; }
};

これは変だよなあ。 BaseImpl は複数あるので GetCapsule をその数だけ定義しなければならないという問題もあって嫌らしい。うーん、悩ましい……。

だらだら書いてしまったけれど、職場には cpp2hatena がないためにコードの色分けができないので読み辛いかもしれない。家でビルドした実行ファイルだけ持ってくれば職場でも使えるはずなので、明日持ってくるかな。