许多程序员都发现,利用MFC或者其它的C++应用编写回调函数是非常麻烦的,其根本原因是回调函数是基于C编程的Windows SDK的技术,不是针对C++的,程序员可以将一个C函数直接作为回调函数,但是如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过。通过查询资料发现,其错误是普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递一个指向自身的指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为什么C++类的多个实例可以共享成员函数但是确有不同的数据成员。由于this指针的作用,使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数安装失败。要解决这一问题的关键就是不让this指针起作用,通过采用以下两种典型技术可以解决在C++中使用回调函数所遇到的问题。这种方法具有通用性,适合于任何C++。 1). 不使用成员函数,直接使用普通C函数,为了实现在C函数中可以访问类的成员变量,可以使用友元操作符(friend),在C++中将该C函数说明为类的友元即可。这种处理机制与普通的C编程中使用回调函数一样。 2). 使用静态成员函数,静态成员函数不使用this指针作为隐含参数,这样就可以作为回调函数了。静态成员函数具有两大特点:其一,可以在没有类实例的情况下使用;其二,只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数。由于在C++中使用类成员函数作为回调函数的目的就是为了访问所有的成员变量和成员函数,如果作不到这一点将不具有实际意义。解决的办法也很简单,就是使用一个静态类指针作为类成员,通过在类创建时初始化该静态指针,如pThis=this,然后在回调函数中通过该静态指针就可以访问所有成员变量和成员函数了。这种处理办法适用于只有一个类实例的情况,因为多个类实例将共享静态类成员和静态成员函数,这就导致静态指针指向最后创建的类实例。

 

1.回调函数的说明:

在进行软件开发的过程中,常会用到一些声明为CALLBACK的函数,这些函数就是回调函数。使用回调函数可以改善软件的结构、提高软件的复用性。比如,在一个规模较大的软件项目中,可以将一些资或相对独立的处理模块封装到动态连接库(DLL) 中,然后通过回调函数在不同的场合来使用这些资源和模块。利用回调函数还可以进行程序间复杂的通信,实现一些通知的功能,在某些场合它是比消息更合适的一种方式;在一些特殊的情况下,回调函数更有不可替代的作用。Win32 API 中有许多回调函数的应用,在进行软件设计时也会经常用到这种函数,而有些时候则需要编写自己的回调函数。因此,理解回调函数的原理并掌握它的基本用法是非常必要的。

C ++ 是当代使用最广泛的语言,从嵌入式系统到大型机系统、从Linux到Windows,在大型系统的编制中,到处都是它的身影。它以高效和易编程性获得了许多资深程序员的信赖。在DirectX Play 开发过程中,经常需要使用到回调函数,直接使用回调函数显得复杂麻烦,采用用C + + 实现对回调函数的封装, 使回调函数变得方便实用,对于DirectX Play 等编程就显得是非常有意义的。 
回调函数简单讲就是一个函数指针。写一个函数,然后把函数地址传递给这个函数指针就可以了。

回调函数的原形对C ++ 的成员函数用做回调函数的影响是什么? 
编写回调函数简单地说就是函数原形一致。函数的输入参数,输出参数一致是很容易保证的。要注意调用类型一致性。函数传参数有好几种类型,搞错了传参数的方式,系统必然运行错误。一般来说都是WINAPI 传参数方式。要注意C ++ 的类的成员函数和一般的C 函数的区别。C + + 类采用this 规则传递函数。在使用类的成员函数作为回调函数,要求该成员函数被声名为静态成员函数,并且注意函数声名的时候要同时声明好参数传递规则。 
  
2.我的回调函数的理解, 
  
模块A ,模块B,如果模块B 中调用模块A 的东西, 在模块A中发生一个事件或操作,调用B的函数处理,这就才用了回调函数的机制。

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码 http://www.linuxidc.com/Linux/2014-05/101227.htm

读C++ Primer 之构造函数陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

读C++ Primer 之智能指针 http://www.linuxidc.com/Linux/2011-08/40177.htm

读C++ Primer 之句柄类 http://www.linuxidc.com/Linux/2011-08/40175.htm

C++11 获取系统时间库函数 time since epoch http://www.linuxidc.com/Linux/2014-03/97446.htm

C++11中正则表达式测试 http://www.linuxidc.com/Linux/2012-08/69086.htm

3.例子的实现

模块A的代码 

#ifndef __A_H 
 #define __A_Hclass A 
 { 
 public: 
 A(void){} 
 public: 
 ~A(void){} typedef void (*perfect)(int );  //声明回调函数
 public: 
 void CallBackFunc(void (*perfect)(int ),int n)  //给模块B调用的函数 
 { 
   perfect(n);  //调用的函数 
 } 
 }; 
 #endif  //__A_H

模块B的代码

#include <iostream> 
 #include "A.h" 
 using namespace  std;void perfect(int n)  //这个函数要求是全局的,或者是类中的静态成员变量 
 { 
 cout<<n<<endl; 
 } int main() 
 { 
 A a; 
 a.CallBackFunc(perfect,100);    //调用模块A的代码。 return 0;
 }

静态成员函数调用非静态成员函数  应用于回调函数

代码如下 

模块A的代码 
 #ifndef __CALLBACKTEST_H 
 #define __CALLBACKTEST_H class CallBackTest 
 { 
 public: 
 CallBackTest(void); 
 public: 
 ~CallBackTest(void); 
 typedef void (*perfect)(void*,int );  //声明回调函数 
 public: 
   void CallBackFunc(void* pThisOBject,void (*perfect)(void*,int ),int n) 
 { 
 p=perfect; 
 m_n=n; 
 m_pThisObject=pThisOBject; 
 }   void ExecBackFunc() 
   { 
 p(m_pThisObject,m_n); 
   } private:  
 perfect  p; 
 int m_n; 
 void* m_pThisObject; 
 }; #endif //__CALLBACKTEST_H

模块B的代码

#include <iostream> 
 #include "CallBackTest.h" 
 using namespace std; class testMai 
 { 
 public: 
 static void perfect(void *pdata,int n) 
 { 
 testMai* pObject=(testMai*)pdata; 
 pObject->test(n); }
 void Exec() 
 { 
 CallBackTest callbackTest; 
 callbackTest.CallBackFunc(&this,perfect,100); cout<<"ni hao"<<endl;
 callbackTest.ExecBackFunc();
 }
 void test(int n) 
 { 
 int i=1; 
 int count=0; 
 m=9; 
 for(i=1;i<n;i++) 
 { if(0==n%i) 
 { 
 count+=i; 
 } 
 } 
 if(count==n) 
 //printf("%d是完数\n",n); 
 { cout<<n<<"是完数"<<endl; 
 } 
 else  
 { 
 cout<<n<<"bu shi de "<<endl; 
 } 
 } private: 
 int m; };
 
 int main() 
 { 
 testMai testMai; 
 testMai.Exec(); 
 return 0; 
 }

回调函数定义
就是被调用者回头调用的函数,它是通过函数指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所所指向的函数时,此时,就可以称它为回调函数。

进一步解释
回调函数不是由该函数的实现方直接调用的,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个被调用的函数。而被调用函数在需要的时候,利用传递的地址调用回调函数。

回调函数由程序员自己调用,当需要调用另一个函数时,这个函数的其中一个参数就是这个回调函数名。系统在必要的时候会调用程序员写的回调函数,这样就可以在回调函数里完成要做的事了。

回调函数实现
(1)声明

(2)定义

(3)设置触发条件,就是在函数中把回调函数名作为一个参数,以便系统调用

举例

typedef void(*FunPtr)(void);
//定义回调函数
class A {
    public:
//回调函数,必须是声明为static
        static void callBackFun(void) {
        ...
}
};
//设置触发条件
void Funtype(FunPtr p) {
    p();
}
void main(void) {
    Functype(A::callBackFun);
}

回调函数和API对比

相同点:
回调函数与应用程序接口(API)很相似,都是跨层调用的函数
不同点:
API是低层提供给高层的调用,一般这个函数对高层都是已知的。
回调函数是高层提供给低层的调用,对于低层它是未知的,必须由高层进行安装,这个安装函数就是一个低层提供的API,安装后低层不是道这个回调的名字,但它通过一个函数指针来保存这个回调函数,在需要调用时,只需引用这个函数指针和相关的参数指针
---------------------