编程中,在处理功能相互独立但又需要协调的某些工作的时候,有时会用到回调函数来实现这些需
求。回调函数的实现实质是使用函数指针来调用相关的功能函数。这里简析一下回调函数基本的实
现框架。
一般比如进度显示的功能,有一个业务工作类和一个界面显示类,界面需要实时的来显示工作类的
进度。基本框架可以设计如下:
//
//业务工作类
//
class CAutoAdd;
//定义函数指针,这里该函数使用两个参数
typedef void (*AUTOSHOW) (int nCount, //函数所用到的参数数据
void *pCustomParam); //用于指示相关的调用类
class CAutoAdd
{
public:
void Stop(); //暂停工作
void Run(); //工作函数
void SetCallback(AUTOSHOW pa, void *pCustomParam);
int m_nCount;
bool m_bStop;
CAutoAdd();
virtual ~CAutoAdd();
private:
AUTOSHOW _pAutoShow;
void* _pCustomParam;
};
//
//界面显示类
//
#include "AutoAdd.h"
class CCallBackDlg : public CDialog
{
// Construction
public:
CAutoAdd m_auto; //业务工作类的一个实例
static void Set(int n,void *pCustomParam);//业务类中所要调用的界面显示函数
void UpdateUI(CString ss);
CCallBackDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CCallBackDlg)
enum { IDD = IDD_CALLBACK_DIALOG };
CButton m_btnShow;
CButton m_btnStart;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCallBackDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CCallBackDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButton1();
afx_msg void OnButton2();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
解析一下关键的几点:
1)函数指针中用到的void *pCustomParam参数,该指针用于指示调用者;
typedef void (*AUTOSHOW) (int nCount, void *pCustomParam/*指示调用者*/);
2)CAutoAdd::SetCallback函数,在界面类初始化时调用该函数,pa传递相关的回调函数,
pCustomParam传递该界面类自身的指针;
void CAutoAdd::SetCallback(AUTOSHOW pa, void *pCustomParam)
{
_pAutoShow = pa;
_pCustomParam = pCustomParam;
}
3)void CCallBackDlg::Set(int n,void *pCustomParam)
该函数在声明时须指定为static类型。否则将会产生编译错误:
rror C2664: 'SetCallback' : cannot convert parameter 1 from 'void (int,void *)' to
'void (__cdecl *)(int,void *)'
None of the functions with this name in scope match the target type
4)CCallBackDlg::Set的实现;
void CCallBackDlg::Set(int n,void *pCustomParam)
{
MSG msg;
CString str;
str.Format("%d", n);
//
//由于static成员不能访问非static成员,所以通过pCustomParam指针得到当前界面
CCallBackDlg *pDlg = (CCallBackDlg *)pCustomParam;
pDlg->UpdateUI(str);
//
//使在执行业务逻辑处理的时候程序还能有暇去照顾其他消息响应
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
相关代码