//c语言回调函数
/**************************************************************************************************
Description:回调函数将调用者于被调用者分开,调用者不关心谁是被调用者。回调函数就好像是一个中断处理函数,系统在符合你设定的条件时自动调用。为此,需要做三件事:
1. 声明;
2. 定义;
3. 设置触发条件,就是把要调用函数的地址作为一个参数传递给回调函数,以便于系统调用
Author:songqingxi
Date: 2010/9/20 13:53
**************************************************************************************************/
#include <iostream>
using namespace std;
//声明回调函数原型
typedef int (*AddCallback)(int ,int );
//定义调用函数
int Add(int a,int b)
{
cout<<"a+b="<<a+b<<endl;
return a+b;
}
//定义回调函数
int Function(AddCallback function,int x,int y)
{
return function(x,y);
}
int main()
{
//触发回调函数,传入调用函数的地址
return Function(Add,1,6);
}
也可以这么做,意思跟上面做法是一致的:
//定义调用函数
int Add(int a,int b)
{
cout<<"a+b="<<a+b<<endl;
return a+b;
}
//定义回调函数
int Function(int (*callback)(int , int ),int x,int y)
{
return callback(x,y);
}
int main()
{
//触发回调函数,传入调用函数的地址
return Function(Add,1,6);
}
//C++ 回调函数
回调函数源自C语言,而在C++中,只在与C代码建立接口,或与已有的回调接口打交道时,才使用回调函数。C++中使用虚拟方法或函数符(functor),而不是回调函数。C++应用编写回调函数是非常麻烦的,其根本原因是回调函数是基于C编程的Windows SDK的技术,不是针对C++的,程序员可以将一个C函数直接作为回调函数,但是如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过。
(1)分析
普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递一个指向自身的指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为什么C++类的多个实例可以共享成员函数但是确有不同的数据成员。由于this指针的作用,使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数安装失败。
(2)解决方法:
要解决这一问题的关键就是不让this指针起作用,通过采用以下两种典型技术可以解决在C++中使用回调函数所遇到的问题。这种方法具有通用性,适合于任何C++。
1). 不使用成员函数,直接使用普通C函数,为了实现在C函数中可以访问类的成员变量,可以使用友元操作符(friend),在C++中将该C函数说明为类的友元即可。这种处理机制与普通的C编程中使用回调函数一样。
2). 使用静态成员函数,静态成员函数不使用this指针作为隐含参数,这样就可以作为回调函数了。静态成员函数具有两大特点:其一,可以在没有类实例的情况下使用;其二,只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数。由于在C++中使用类成员函数作为回调函数的目的就是为了访问所有的成员变量和成员函数,如果作不到这一点将不具有实际意义。解决的办法也很简单,就是使用一个静态类指针作为类成员,通过在类创建时初始化该静态指针,如pThis=this,然后在回调函数中通过该静态指针就可以访问所有成员变量和成员函数了。这种处理办法适用于只有一个类实例的情况,因为多个类实例将共享静态类成员和静态成员函数,这就导致静态指针指向最后创建的类实例。为了避免这种情况,可以使用回调函数的一个参数来传递this指针,从而实现数据成员共享。
(本段描述源自:http://bbs.rosoo.net/viewthread.php?tid=5922&extra=&ordertype=1)
实例1 参数传递方式:
class Test
{
public:
Test(){};
virtual ~Test(){};
void sum()
{
printf("%s\n" , "class Test sum() is running!");
}
int sub(int a, int b)
{
printf("%s%d\n" , "a- b =" , a-b);
return a-b;
}
static int proc_function(void* p2Object , int a , int b)
{
Test* test = (Test*)p2Object;
return test->sub(a,b);
}
};
int callbacksub(void* p2object ,int (*pfun)(void * p2object , int x, int y) , int a , int b)
{
return pfun(p2object , a , b);
}
void callbacksum(void* p2object , int a , int b)
{
Test* sum_test =(Test*)p2object;
sum_test->sum();
sum_test->sub(a , b);
}
void callbacksum(void* p2object)
{
Test* sum_test =(Test*)p2object;
sum_test->sum();
}
int main()
{
Test mytest;
callbacksub((void*)&mytest , Test::proc_function , 100, 20);
callbacksum(&mytest , 50 , 10);
callbacksum(&mytest);
return 0;
}
实例2 全局变量方式:
当回调函数宿主函数作为接口不可改动时,使用全局变量的方式比较有效:
void* p2Object;
class Test
{
public:
Test(){};
virtual ~Test(){};
void sum()
{
printf("%s\n" , "class Test sum() is running!");
}
int sub(int a, int b)
{
printf("%s%d\n" , "a- b =" , a-b);
return a-b;
}
static int proc_function(int a , int b)
{
Test* test = (Test*)p2Object;
return test->sub(a,b);
}
};
//回调函数宿主函数
int callbacksub(int (*pfun)( int x, int y) , int a , int b)
{
return pfun( a , b);
}
//回调函数宿主函数
void callbacksum(int a , int b)
{
Test* sum_test =(Test*)p2Object;
sum_test->sum();
sum_test->sub(a , b);
}
//回调函数宿主函数
void callbacksum()
{
Test* sum_test =(Test*)p2Object;
sum_test->sum();
}
int main()
{
Test mytest;
//类型转换
p2Object = (void*)&mytest;
callbacksub(Test::proc_function , 100, 20);
callbacksum( 50 , 10);
callbacksum();
return 0;
}