您的位置:首页 > 其它

回调函数,函数指针与函数对象

2010-05-25 14:07 309 查看

以下转自:http://shudingbo.spaces.live.com/blog/cns!C33400475B08F157!423.entry?wa=wsignin1.0&sa=246515118

1. 
什么是回调函数

    回调函数(callback Function),顾名思义,用于回调的函数。 
回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数。回调函数是一个工作流的一部分,由工作流来决定函数的调用(回调)时机。回调函
数包含下面几个特性:
    属于工作流的一个部分;

    必须按照工作流指定的调用约定来申明(定义);

    他的调用时机由工作流决定,回调函数的实现者不能直接调用回调函数来实现工作流的功能;

   

2. 回调机制

   
回调机制是一种常见的设计模型,他把工作流内的某个功能,按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。



    
如上图所示,工作流提供了两个对外接口(获取参数、显示结果),以回调函数的形式实现。
 “获取参数”回调函数,需要工作流使用者设定工作流计算需要的参数。

 “显示结果”回调函数,提供计算结果给工作流使用者。

2.  回调机制应用

   使用回调机制,可以为工作流实现扩展。
可以把工作流中需要用户干预的,或需要提供给用户的数据以回调的模式提供给用户。而用户不需要知道整个工作的流程,只需知道回调函数的说明就可以使用工作
流模块提供的功能,这对信息的隐藏也是有作用的。

3. 回调机制的实现形式

    回调函数

    虚拟函数

    事件

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

以下转自:http://www.cnblogs.com/heyutao/archive/2009/05/21/1486647.html

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

  在这里设:回调函数为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型结果的模板化的函数对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息