我们经常会把一些耗时的操作放到线程中去执行,当任务执行完毕后就需要通知主线程,通知的方式有很多,在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来实现。