回调函数、函数指针和函数对象
2009-11-30 22:27
176 查看
回调函数,函数指针与函数对象
对于回调函数的编写始终是写特殊处理功能程序时用到的技巧之一。先介绍一下回调的使用基本方法与原理。
在这里设:回调函数为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型结果的模板化的函数对象。
对于回调函数的编写始终是写特殊处理功能程序时用到的技巧之一。先介绍一下回调的使用基本方法与原理。
在这里设:回调函数为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型结果的模板化的函数对象。
相关文章推荐
- 封装回调函数——为对象方法(Object Method,参数中带this指针的函数) 构造 普通函数(参数中无this指针的函数)形式 的入口
- 回调函数,函数指针与函数对象
- 封装回调函数——为对象方法(Object Method,参数中带this指针的函数) 构造 普通函数(参数中无this指针的函数)形式 的入口
- c函数指针和回调函数
- C函数指针应用之回调函数
- C++对象模型之成员函数的指针
- 指向派生类对象的基类指针与虚函数
- 回调函数与函数指针
- 建立一个对象数组,内放5个学生的数据(学号,成绩),用指向对象的指针做函数参数,在max函数中找出5个学生中成绩最高者,并输出其学号。
- this指针在普通函数、对象方法、定时器、构造函数、事件函数、call()、apply()中的执行
- 函数指针和回调函数
- 参量与变量、指针、函数、对象
- 指向对象的指针访问成员函数
- 函数指针、回调函数与 GObject 闭包
- 神奇的虚函数:用基类指针访问对象的protected成员函数
- stl编程概述和函数对象、函数指针
- STL算法之回调函数和函数对象的理解及设计
- this 指针的地址--调用成员函数的所在对象的起始地址
- [OC]对象、指针/方法、函数
- Self Summary: C++函数返回引用和指针的问题,局部对象与new对象的问题