読者です 読者をやめる 読者になる 読者になる

main()の隠蔽

C++ D言語


小ネタ.
main()からプログラムを書き始めると,大した規模でないものでも,
物凄くプログラムを書いた感じがして,どっと疲れる.
自分は,元々Windowsプログラムは楽チンMFCから入った人間なので,多分,
main()から書き始めるプログラムは,何か大変っていう刷り込みがあるっぽい.
# 逆にmain()から書き始めないプログラムは,何か心許ないというのも分かる.


そんな訳で,main()の隠蔽方法についてメモ.


C++では,グローバル変数として宣言したインスタンスコンストラクタが,
main()より前に呼ばれる(っぽい)のを利用して,main()を隠蔽してた.
このやり方は MFC と同じ.(簡単な実例は SpeedShooter ソース参照)

//--------------------------------------------------
// アプリケーションの基底クラス
//--------------------------------------------------
class CMainApp 
{
public:
    static CMainApp* s_pMainInstance;

public:
    CMainApp()
    {
        s_pMainInstance = this;
    }

    virtual int Body()=0;
};
CMainApp* CMainApp::s_pMainInstance = NULL;


//--------------------------------------------------
// main 関数
//--------------------------------------------------
int main(int argc, char* argv[])
{
    return CMainApp::s_pMainInstance->Body();
}


//--------------------------------------------------
// ここから実装
//--------------------------------------------------
class CApp : public CMainApp
{
public:
    int Body()
    {
         ...(メインプログラム)...
    }
};

// 実装したクラスのインスタンスをグローバル変数にすると,
// main()より前に CMainApp::CMainApp() が呼ばれて 
// s_pMainInstance に実装したインスタンスのポインタが渡る.
CApp theApp;


Dだとインスタンスの生成には必ず new 文を使わないといけないっぽいので,
実行中に,どっかでインスタンスの生成を行わないといけないっぽい.
# ↑未確認.「静的インスタンス」みたいのって無いのかな?
で,リファレンスを読んでたんだけど,どうも「静的コンストラクタ」という
のが用意されているらしい.
>静的コンストラクタは、 main() に制御が移る前に初期化を実行する関数として
>定義されています。静的コンストラクタは、クラスの静的メンバを、
>コンパイル時には計算できない値で初期化する際に使用します。
よするに,プログラム中,最初から最後まで居座るインスタンスを作るような場合,
静的コンストラクタの中で new しろって事?


要はmain()より前に,実装したクラスのインスタンスが渡せれば良いので,
静的コンストラクタ内で自分のインスタンスを new して渡す事にしてみる.

//--------------------------------------------------
// アプリケーションの基底クラス
//--------------------------------------------------
abstract class CMainApp 
{
public:
    static CMainApp s_MainInstance;

public:
    static void boot(CMainApp app)
    {
        s_MainInstance = app;
    }
    
    int Body()
    {
        return 0;
    }
};


//--------------------------------------------------
// main 関数
//--------------------------------------------------
int main(char argv[][])
{
    return CMainApp.s_MainInstance.Body();
}


//--------------------------------------------------
// ここから実装
//--------------------------------------------------
class CApp : public CMainApp
{
public:
    // 静的コンストラクタ内で自分インスタンスを生成させて,
    // 実装したインスタンスのポインタを s_MainInstance に渡す.
    static this()
    {
        boot(new CApp);
    }
    
    int Body()
    {
         ...(メインプログラム)...
    }
};


まだ,簡単な実験しかしてないけど,一応うまく行きそう.
グローバルなインスタンスコンストラクタみたいに,曖昧な位置でなく,
明示的に「main() に制御が移る前に」実行される場所があるってのは良いかも.
ただ,実行順についてはかなり慎重に書かないといけなそうだけど.
あと,static メンバを2回記述しなくて済むのが素晴らしいな.