在《定製一個eVC上的中文模擬器》一文回複中,bxianch朋友問到“EVC中的線程,為什麼要聲明稱 static呢,而在靜態函數中藥調用非靜態成員還不能調用,必須把這些成員也設定成靜態,不怎麼方便,有好的解決方案嗎”。
其原因是把CALLBACK函數封裝成C++類的非靜態成員後,需要有建立對象,再通過對象才能去找到這個成員函數。而系統調用這個CALLBACK函數的時候,才不管你有沒有建立對象呢。典型的解決方案是需要用靜態成員函數給系統CALL。然後設法把THIS指標傳給這個STATIC函數,讓這個STATIC函數通過THIS指標訪問到當前對象裡的成員函數,那麼這個成員函數就可以輕鬆操作所有成員變數了。這種方法適用於所有系統CALLBACK。
以CreateThread為例,
class CTest
{
public:
CTest();
~CTest();
static DWORD WINAPI ThreadCallback(PVOID pParam); //這個是系統要的東東,沒有對象也能直接存取STATIC成員函數
DWORD MyProc();
private:
HANDLE m_hThread;
};
CTest::CTest()
:m_hThread(NULL)
{
m_hThread = CreateThread(NULL, 0, ThreadCallback, (LPVOID)this, 0, NULL); //注意把THIS指標當做PARAM傳進去,沒這個我們就不用玩了
ASSERT(m_hThread);
}
CTest::~CTest()
{
if(m_hThread)
{
TerminateThread(m_hThread, 1);
m_hThread = NULL;
}
}
static DWORD WINAPI CTest::ThreadCallback(PVOID pParam)
{
((CTest*)pParam)->ThreadProc(); //把pParam還原成指向當前對象的指標,然後曲線救國一下
}
DWORD CTest::MyProc() //這個就是對象裡的東西了,在裡面可以為所欲為
{
//do whatever you want
//even visit the private member
}
如果在ThreadCallback函數裡拿到this指標後,通過this指標去訪問對象裡的東西也是可以的,就不需要多一個MyProc函數了。但是MyProc可以直接引用所有成員變數,而ThreadCallback裡每次都得用this->xxxx訪問,多一次地址跳轉,在效率上會比MyProc裡直接調用稍低一些。所以還是推薦用上面代碼的實現方式