我們經常會把一些耗時的操作放到線程中去執行,當任務執行完畢后就需要通知主線程,通知的方式有很多,在windows平台上可以使用消息機制,如果不想依賴平台API,讓代碼具有良好移植性,使用回調函數也是一種方法。
(1)定義函數指針類型
typedef void(*pResult)(int);
(2)在類的內部定義一個函數指針對象
private:
pResult m_ResultEvent;
(3)添加一個函數用來指定回調函數
void setResultEvent(pResult event)
{
m_ResultEvent=event;
}
(4)在線程任務完成后回調函數通知主線程
void run()
{
//do something
if(m_ResultEvent)
m_ResultEvent(1);
}
(5)在主線程中定義回調處理函數
需要注意的是函數只能定義為靜態函數,只有全局函數或靜態函數才能作為函數指針傳遞。
class MainObject
{
public:
MainObject();
private:
ThreadObject m_Thread;
int m_Status;
static void doResult(int status);
}
MainObject::MainObject()
{
m_Thread.setResultEvent(doResult);
}
這樣回調的功能就基本實現了。但是如果回調函數只能傳靜態函數,那么在回調函數中如何與實際的對象聯系呢。
我們可以把對象作為回調函數的一個參數,這樣通過調用這個參數就可以實現對此對象的訪問了。可以將上面的回調函數做一下改造。
typedef void(*pResult)(const void *p,int);
修改線程設置函數,傳入對象指針,並保存
private:
void * m_Object;
void setResultEvent(void *p,pResult event)
{
m_ResultEvent=event;
m_Object=p;
}
在調用的時候將對象this指針傳入:
MainObject::MainObject()
{
m_Thread.setResultEvent(this,doResult);
}
//將對象指針作為參數傳入回調函數中
void run()
{
//do something
if(m_ResultEvent)
m_ResultEvent(m_Object,1);
}
//在處理函數中將void*指針強轉為需要的對象類型:
void MainObject::doResult(const void *p,int status)
{
MainObject *obj=(MainObject *)p;
obj->m_Status=status;
}
以上就是C++中對象回調通知的方式,回調函數主要使用了函數指針的概念,實際在C語言中就已存在,C++繼承了這種機制,但是由於函數只能傳入靜態的或全局的,所以封裝性並不好,類型強制轉換也顯得繁瑣。在C++中有新的機制可以實現相似的功能,就是利用std::function和std::bind來實現。