設計(4)
あとは、内部のデータクラスは公開する必要はないので内部クラスに入れて protected にして、ポインタはスマートポインタに変えてやる。
class Hoge{ protected: class Data{ public: virtual void foo(){} virtual void bar(){} }; private: Data* get(){ return (Data*)_obj.get(); } smart_ptr< Data > _obj; public: void foo(){ return get()->foo(); } void bar(){ return get()->bar(); } };
これで Hoge クラスの完成だ。
ところで、これを継承して、HogeEx というのが作りたくなった場合はどうなるのだろう。
実は、うまくいく。Hoge はあくまで入れ物で、その中には実オブジェクトへのポインタしか入っていない。
この _obj の実体を HogeEx にするだけで、HogeEx のメソッドが呼べるのだ。
class HogeEx : public Hoge{ protected: class Data : public Hoge::Data{ public: // override virtual void foo(){} }; private: Data* get(){ return (Data*)_obj.get(); } public: void foo(){ return get()->foo(); } };
HogeEx オブジェクトの中に HogeEx の実オブジェクトを入れて Hoge にキャストしても、Hoge::foo() を呼び出すと、HogeEx::foo() が呼び出される。
HogeEx hogeEx; // 本当はアクセスできないけど、これは仮 hogeEx.set( new HogeEx::Data ); Hoge hoge; hoge = hogeEx; hogeEx.foo(); hoge.foo();
最後の2行、ドット演算子でアクセスしているのに、両方とも HogeEx の関数(実際はその中の実オブジェクトの関数)が呼び出されるのだ。非常に Java ライクでおもしろい。
Java ライクと言えば Object クラスだ。全てのクラスを Object から派生すれば、かなり便利になる。
なので、ほとんどのクラスを Object から継承して使う形にしようと思う。