設計(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 から継承して使う形にしようと思う。