staticでないクラスメンバ関数を_beginthreadで実行させる方法。


クラスメンバ関数を_beginthreadする場合、メンバ関数はstaticでなければならない。
非staticなメンバ関数を実行したい場合は、以下のようにstaticでなメンバ関数をかませて実行する。

// スレッドを発生されるクラス
class Test {
:private
	HANDLE thread;	// スレッドハンドル

	// スレッド開始
	void threadStart(){
		thread = (HANDLE) _beginthread(
			&test::executeLauncher,	// ランチャを起動
			0,
			this);
	}

	// ランチャ
	static void executeLauncher(void* args){
		// 無理やりtest*型にキャストして、本命の処理を実行する。
		reinterpret_cast<test*>(args)->execute();
	}
	
	// 本命の処理(非staticメンバ変数)
	void execute(){
		…
	}
};

main(){
	Test test = new Test();
	// スレッドで、staticではないメンバ変数execute()が実行
	test->threadStart();	

}

メンバ関数ポインタがstaticでなければならない理由。


MSDNによると、

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

start_address
 新規スレッドの実行を起動するルーチンの開始アドレス。_beginthread の呼び出し規約は __cdecl または __clrcall

関数呼び出し規約


VC++での関数呼び出し規約は、__cdecl、__stdcall、__clrcall、__thiscall等がある。
それぞれの詳細は、こちらを参照→二流プログラマの三流な日常: 関数呼び出しの内部を理解する(2)によると…

__cdecl

一般的な関数呼び出し規約。普通の関数ポインタはこれで呼び出す。

___stdcall

WindowsAPI用の関数呼び出し規約。

__clrcall

CLR用の関数呼び出し規約

__thiscall

C++において、インスタンスからメンバ関数を呼び出す時の呼び出し規約。
隠しパラメータとして、thisが与えられる。
staticなメンバ変数ではthisは不要なため、__thiscallでは呼び出せず、__cdeclにて呼び出される。
thisから、staticメンバ関数が呼び出せないのもこれが理由。

まとめ

メンバ関数の種類 呼び出し規約
staticのメンバ関数 __cdecl
非staticのメンバ関数 __thiscall


_beginthreadの仕様では、呼び出し規約が__cdeclの為、staticのメンバ関数しか呼び出せない。
その為、非staticのメンバ関数を呼び出すには、上記のような小細工が必要。

参考サイトとか

ロベールのC++教室 - 第57章 メンバ関数ポインタ天国
ここ、良質な記事が多いのになんで閉鎖しちゃったんだろ。残念。

2007/7/23追記

コメントに頂いたように、ロベールのC++教室 さんは移転していただけの様です。
リンク修正しましたー。

2008/4/3追記

関数呼び出し規約の勘違いを修正。