而如果我们用回调函数,这个过程就变成了这样:
// C++Test.cpp : 定义控制台应用程序的入口点。
//
//#include “stdafx.h”
//#include
//#include
//#include
using namespace std;
//声明一种回调函数
typedef void (*CallBackFunc)(void);
class Baker
{
private:
int m_iTime; //做蛋糕的时间
static const int m_iMaxTime = 10;//假设10分钟做完
CallBackFunc m_pfCallBack;//回调函数
public:
//注册:留下买蛋糕的人的联系方式
void Invoke(CallBackFunc);
//打电话通知买蛋糕的人
void Notify();
//做蛋糕,如果做好了,直接通知客户
void MakeCake();
//构造函数
Baker();
};
Baker::Baker() : m_iTime(0){}
void Baker::MakeCake()
{
while(m_iTime < m_iMaxTime)
{
//假设每次调用该函数,m_iTime+1
m_iTime += 1;
}
cout << “蛋糕做好了! ” << endl;
Notify();
}
void Baker::Invoke(CallBackFunc pfunc)
{
//注册过程
m_pfCallBack = pfunc;
cout << “留下了您的联系方式!” << endl;
}
void Baker::Notify()
{
if (m_pfCallBack)
m_pfCallBack();
}
//客户函数
void GetMyCake()
{
cout << “我来取蛋糕啦!” << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
//创建一个蛋糕店
Baker baker;
//注册:留下联系方式
baker.Invoke(GetMyCake);
//注册之后,客户就不需要实时查询了
cout << “好了叫我就好,我去玩儿啦!” << endl;
//做蛋糕
baker.MakeCake();
system("pause");
return 0;
}
结果:
留下了您的联系方式!
好了叫我就好,我去玩儿啦!
蛋糕做好了!
我来取蛋糕啦!
请按任意键继续…
通过函数回调,虽然实现过程比较麻烦,先得注册,然后再类对象内部进行判断。但是这样做是有好处的,就是客户在注册之后,完全不需要再管蛋糕做没做好了,只要蛋糕做好了,蛋糕店会立刻通知客户。比如我们做异步加载时,如果我们需要资源,就可以主线程去加载线程注册一下,然后主线程继续做其他工作,加载线程加载完所需要的东西之后,反过来通过回调函数通知主线程,这样,加载和主要功能就可以同时进行,大大的提升了用户体验。
其实函数指针回调在C#中的实现就是代理,C#将回调这件事做得特别简单,可惜C++中没有代理,所以我们做起来还是比较麻烦的,不过回调真的灰常有用。
五.其他问题
函数指针和指针函数
函数指针和指针函数仅仅是名字比较像,写法容易搞混,其他并没有什么联系,二者可以共存。
函数指针我们说过了,就是指向函数的指针,其本质是一个指针。
指针函数,指的是函数的返回值是一个指针,其本质是一个函数。
两者容易搞混的地方就在于写法:
//定义一个函数指针
typedef int (*pFunc)(void);
//定义一个指针函数
int* PointerFunc(void)
{
int a = 1;
return &a;
}
函数指针和名字是放在一起的,而指针函数是和返回值放在一起的。
当然,我们也可以定义一个指针函数的函数指针:
//定义一个指针函数的函数指针
typedef int* (*pFUN)(void);