pimpl

takelさん(id:takel)が、循環参照になるプログラムの解決方法を教えてくれましたヽ(´ー`)ノ

//Hoge.h
class Hoge{
private:
    Moke _moke;
    Hogera _hogera;
    Hogehoge* _pHogehoge;
};

というクラスがある場合、MokeとHogeraとHogehogeを定義したヘッダファイルをincludeすることになります。ここでは、それぞれ、"Moke.h" "Hogera.h" "Hogehoge.h"とします。


ここで問題なのが、Hogehogeクラスの中で、Hogeをメンバとして置くことがあるかもしれないということです。
そうなると、HogehogeクラスはHoge.hをincludeする必要があります。
しかし、Hoge.hでは、Hogehogeをincludeしているので、循環参照になり、困ってしまいます。
自分的には、こういうことで時間を使うのはすごい嫌なので、takelさんの教えてくれた、pimplパターンを適用してみます。

//Hoge.h
class Hoge{
public:
    Hoge();
private:
    class Impl;
    smart_ptr<Impl> _pImpl;
};
//Hoge.cpp
#include "Hoge.h"
#include "Moke.h"
#include "Hogera.h"
#include "Hogehoge.h"

class Hoge::Impl{
private:
    Moke _moke;
    Hogera _hogera;
    Hogehoge* _pHogehoge;
};

Hoge::Hoge() : _pImpl(new Impl) {}

こうすれば、ヘッダファイルには、includeする必要が無くなり、循環参照で困ることが無くなります。
依存関係を気にせずに、includeできて非常に(・∀・)イイ!!ですね。


ただ、少し気になるのが、速度。
例えば、これを実装しているクラスが、CAppなどの、global変数置き場(?)などの場合、

//CApp.h
class CDraw;
class CSound;
class CCharaList;

class CApp{
public:
    CApp();
    CDraw* getDraw();
    CSound* getSound();
    CCharaList* getCharaList();
private:
    class Impl;
    smart_ptr<Impl> _pImpl;
};
//CApp.cpp
#include "CApp.h"
#include "CDraw.h"
#include "CSound.h"
#include "CCharaList.h"

class CApp::Impl{
public:
    CDraw* getDraw(){ return &_draw; }
    CCharaList* getCharaList(){ return &_charaList; }
    CSound* getSound(){ return &_sound; }
private:
    CDraw _draw;
    CSoound _sound;
    CCharaList _charaList;
};

CApp::CApp() : _pImpl(new Impl) {}

CDraw* CApp::getDraw(){ return _pImpl->getDraw(); }
CSound* CApp::getSound(){ return _pImpl->getSound(); }
CCharaList* CApp::getCharaList(){ return _pImpl->getCharaList(); }

こうやって書くことになります。
普段であれば、ヘッダに書いて、インライン展開されるはずの関数が、cppファイルに移動しているため、インライン展開が出来ません。……出来ないよね?
しかも、CAppは、最上位にあるクラスなので、あらゆるクラスから頻繁にアクセスされます。
こういう、上位にあるクラスについては、pimplパターンを適用しない方が良いかもしれないですね。
まあ、どうしても循環参照が鬱陶しくなったクラスだけ、このpimplパターンを適用してみますか……。