FAQ10-2

Q. lpfnWndProcに自作クラスのメンバー関数を代入するには


 WinMain()でWNDCLASSのlpfnWndProcにコールバック関数を代入します.ここで,自作クラスのメンバー関数を代入する方法を教えてください.
 また,自作のクラスのメンバー関数をダイアログ表示させたり,タイマー処理させる方法教えてください.
 MakeProcInstance()で関数のポインタをセットしようとしても型が異なって,うまくいきません.
(Dr.Mahorraさんからの質問です)


A. メンバー関数の定義にstaticを付ける


staticにすればよいが...


 これは,メンバー関数の定義にstaticを付けるだけでokです(リスト10-2).
 メンバー関数にstaticを付けると,関数は静的メンバーになります.静的なメンバー関数の場合は,関数のアドレスを他の変数に代入することができるようになります.
 しかし,静的なメンバー関数は,thisポインタで参照することができなくなってしまいます.つまり,同じクラスのメンバーを参照するのに,いちいちオブジェクト名から書かなくてはいけません.これは非常に不便です.
 というか,結局不便になっただけで,メンバー関数にしている意味がないです.まあ,プログラムを整理する上では意味がないわけではないのですが.

[リスト10-2] :


class MYCLASS {
public:
    static LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
    static VOID CALLBACK TimerProc( HWND hwnd, UINT message, UINT id, DWORD dwTime );
    static BOOL CALLBACK DialogProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
    ~~~~~~←ここにstaticを付けるだけでいい
};

MYCLASS     myclass;

void Func( void ) {
    WNDCLASS    wc;
    wc.style        = CS_HREDRAW | CS_VREDRAW ;
    wc.lpfnWndProc  = (WNDPROC)myclass.WndProc ;
        :
        :
    RegisterClass ( &wc );
    
}


LRESULT CALLBACK MYCLASS::WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_CREATE:
            SetTimer( hwnd, 100, 1000,
                (TIMERPROC)myclass.TimerProc );
                           ~~~~~~~←同じクラス内でもオブジェクト名を書かなくてはいけない
            break;
        case WM_LBUTTONDOWN:
            DialogBox( (HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ),
                    MAKEINTRESOURCE(IDD_DIALOG1), hwnd, (DLGPROC)myclass.DialogProc );
            return 0;                                            ~~~~~~~
              :
              :
}

VOID CALLBACK MYCLASS::TimerProc( HWND hwnd, UINT message, UINT id, DWORD dwTime ) {
    :
    :
}

BOOL CALLBACK MYCLASS::DialogProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    :
    :
}

なぜ変数に代入する場合は静的メンバーでなければいけないのか


 なぜ変数に代入する場合は静的メンバーでなければいけないのかというと,例えばある関数内でオブジェクトを定義した場合,メンバー変数はこの関数内でのみ有効で,関数を抜けてしまった後は消えてしまいます.
 そのようなとき,関数内でメンバー関数をウィンドウプロシージャに登録してしまった場合どうなるでしょう.
 メンバー関数のウィンドウプロシージャは,どのメンバー変数を見ていいのか,予測不能な事態に陥ります.同じクラスのオブジェクトを二つ定義した場合にも同じことが言えます.
 というわけで,この予測不能な事態は,コンパイラが予測不能になってしまうためコンパイルエラーになってしまうわけです.
 ...なんか複雑ですが,とにかくstaticを付ければできるのです.

Back to FAQ main page