回调函数、函数指针和函数对象

  对于回调函数的编写始终是写特殊处理功能程序时用到的技巧之一。先介绍一下回调的使用基本方法与原理。

  在这里设:回调函数为A()(这是最简单的情况,不带参数,但我们应用的实际情况常常很会复杂),使用回调函数的操作函数为B(), 但B函数是需要参数的,这个参数就是指向函数A的地址变量,这个变量一般就是函数指针。使用方法为:

  int A(char *p); // 回调函数

  typedef int(*CallBack)(char *p) ; // 声明CallBack 类型的函数指针

  CallBack myCallBack ; // 声明函数指针变量

  myCallBack = A; // 得到了函数A的地址  

B函数一般会写为 B(CallBack lpCall,char * P,........); // 此处省略了p后的参数形式 。

所以回调机制可理解为,函数B要完成一定功能,但他自己是无法实现全部功能的。 需要借助于函数A来完成,也就是回调函数。B的实现为:
B(CallBack lpCall,char *pProvide)
{
........... // B 的自己实现功能语句
lpCall(PpProvide); // 借助回调完成的功能 ,也就是A函数来处理的。
........... // B 的自己实现功能语句
}

(1)基于函数指针的回调函数:

#include < iostream >
using   namespace  std;

typedef 
int  ( * CallBack)( char * );//定义函数指针,该指针指向参数为 char *返回 int的函数
int  A( char *  str)
{
    cout
<< " function A starts " << endl;
    cout
<< str << endl;
    cout
<< " function A ends " << endl;
    
return   0 ;
}
void  B(CallBack call, char *  str)
{
    cout
<< " function B starts " << endl;
    call(str);
    cout
<< " function B ends " << endl;
}

int  main()
{
    
char *  str = " hello,world! " ;
    B(A,str);
    
return   0 ;
}

结果:

function B starts

function A starts

hello,world!

function A ends

function B ends

(2)回调函数还有另外一种方式:函数对象。

函数对象(也称“算符”)是重载了“()”操作符的普通类对象。因此从语法上讲,函数对象与普通的函数行为类似。

用函数对象代替函数指针有几个优点:

首先,因为对象可以在内部修改而不用改动外部接口,因此设计更灵活,更富有弹性。函数对象也具备有存储先前调用结果的数据成员。在使用普通函数时需要将先前调用的结果存储在全程或者本地静态变量中,但是全程或者本地静态变量有某些我们不愿意看到的缺陷。

其次,在函数对象中编译器能实现内联调用,从而更进一步增强了性能。这在函数指针中几乎是不可能实现的。

下面的例子说明使用函数指针和函数对象实现整数求负数的的方法。

#include < iostream >
using   namespace  std;

// 使用函数对象
class  CallBack
{
public :
    
int   operator ()( int );
};
int  CallBack:: operator ()( int  arg) //第一个圆括弧总是空的,因为它代表重载的操作符名;第二个圆括弧是参数列表。
{
    
return  ( - arg);
}

int  fun(CallBack call, int  arg) //注意call是对象,而不是函数。
{
    
return  call(arg); //编译器将语句call(arg)转化为call.operator()(arg);
}

// 使用函数指针
typedef  int  ( * callback)( int );
int  callfun( int  arg)
{
    
return  ( - arg);
}

int  fun2(callback call, int  arg)
{
    
return  call(arg);
}

int  main()
{
    cout
<< fun(CallBack(), 3 ) << endl;
    cout
<< fun2(callfun, 3 ) << endl;
}

结果:

-3

-3

从上面的例子中可以看出,函数对象数据类型被限制在int,而通用性是函数对象的优势之一,如何创建具有通用性的函数对象呢?方法是使用模板,也就是将重载的操作符“()”定义为类成员模板,以便函数对象适用于任何数据类型:如double,_int64或char:

#include < iostream >
using   namespace  std;

// 使用函数对象类模板
template < class  T >
class  CallBack2
{
public :
    T 
operator ()(T);
};
template
< class  T >
T CallBack2
< T > :: operator ()(T arg)
{
    
return  ( - arg);
}

int  main()
{
    
// 使用函数对象类模板
    cout << CallBack2 < int > ()( 3 ) << endl;
    cout
<< CallBack2 < double > ()( 3.333 ) << endl;    
}

结果:

-3

-3.333

标准库中函数对象 
C++标准库定义了几个有用的函数对象,它们可以被放到STL算法中。例如,sort()算法以判断对象(predicate object)作为其第三个参数。判断对象是一个返回Boolean型结果的模板化的函数对象。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值