开篇:润墨网以专业的文秘视角,为您筛选了一篇函数对象在泛型算法中的应用范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!
摘要:C++中的函数对象是一种特殊的对象,使用起来特别灵活。掌握并使用好函数对象可以大大精简代码。该文在介绍函数对象概念的同时总结了函数对象的几点应用。
关键词:函数对象;泛型算法;函数模版; C++语言
中图分类号:TP312文献标识码:A文章编号:1009-3044(2011)09-2185-03
Application of Function Objects in the Generic Algorithm
DING Ya-guang
(Computer Science, Anhui University, Hefei 230000, China)
Abstract: Function objects are special object that could be applied flexibly. We can greatly simplify and compact the code by using function objects. This paper introduces the concept of function objects, as well, summarizes some applications.
Key words: function object; generic algorithm; function template; C++
学过javascript的同学可能会知道“函数对象“(javascript中的函数都是被维护为一个对象)这个词,但是C++中的函数对象和javascript中的却完全没有关系。
C++中的函数对象就是重载了操作符()的类的对象。那么它有什么特殊意义呢?《C++ Primer》中说了:更加灵活的在泛型算法中使用。究竟怎样更加灵活了呢?让我们一个个的来发现。
1 传统的函数重载方法
如果我们想对一个数组a[N](成员可能是非基本变量类型)进行排序,可以使用以下几种方法:
方法一:重载
如果数组元素的类型没有定义过
使用方法如下面的代码:
T a[N];
bool operator < (const Type &a,const Type &b)
{
/*这里写这种类型逻辑上的a < b运算的结果,
如果a小于b,返回true;否则返回false;注意如果a等于b,是返回false的!
因为stl中的判断相等是当 a
}
sort(a,a+N);
注:Type为元素类型,N是数组长度常数
如果希望从大到小排序,在重载操作符
当然,如果a[N]是int等基本数据类型,或者其他不适宜重载操作符
方法二:定义比较函数
如果没有重载操作符
sort(a.begin(),a.end(),cmp);
cmp的函数原型应该是:
bool cmp(const Type &a,const Type &b);
使用方法如下面的代码:
int a[N];
bool cmp (const int &a,const int &b)
{
return a>b;
}
sort(a,a+N,cmp);
这里是传递函数指针给sort函数,值得一提的是它的第三个参数也可以接受函数对象。这就是下面的方法了
2 使用函数对象的方法
使用函数对象结合模板类和模板函数更加简洁清晰地组织代码。函数对象就是重载了()的类对象,使用起来和函数很像,例如:
class cmp
{
public:
bool operator() (const int& a,const int &b )//重载()操作符
{
return a>b;
}}
使用方法如下面的代码:
int a[N];
class cmp
{
public:
bool operator() (cosnt int &a,const int& b )
{
return a>b;
}}
sort(a,a+N,cmp);
貌似在这里看不到有啥好处吧,和第二种方法不是一样的么?看起来也都一模一样。好处体现在使用了C++标准库STL提供的函数对象适配器(定义在头)之后:
标准库STL提供的函数对象适配器有很多,基本上所有的操作符都有对应的,就先举两个例子吧:
great 对应>
less 对应
相当于生成一个函数对象,操作符()函数返回的分别是>和
sort(a,a+N),less);//从小到大排序
sort(a,a+N,greater); // 从大到小排序
函数对象因为是一个对象,所以还可以作为参数传递(当然函数指针也可以)。
3 创建接受函数对象的函数
看到这里,大家可能已经对在STL中使用函数对象的方式有所了解了。大家可能会更进一步想知道STL中的函数,比如sort函数是如何做到既可以接受不同参数类型的函数又可以接受不同类型的函数对象的。看了下面的例子大家就知道了:
template
class Operation
{
public:
T operator()(T a,T b)
{
return a+b;
}
};
//普通的操作函数
int add(int a,int b)
{
return a+b;
}
//可接受函数对象和普通函数的模板函数
template
void dosomething(Vt a,Vt b,T &op)
{
cout
}
int main()
{
dosomething(1,2,add);
dosomething(1,2, Operation());
}
在如上代码中,我们生成了一个模板类,一个模板函数。这样就实现了接受不同类型的函数和函数对象了。
看起来用函数对象和用函数指针代码复杂度也差不多,但是当我们需要进行dosomething(1.111,2.222,add);时,用函数指针的方法,不得不再重载一个实型参数的add函数。
double add(double a,double b)
{
return a+b;
}
而用函数对象的方法,由于已经定义了模板类,只需要
dosomething(1,2, Operation());就ok了。感谢C++的模板机制。
总结完函数对象的好处之一,我们再看下面下一个好处。
4 函数对象处理参数更灵活
假设有一个整数数组a[]={2,,4,8,2,3,0,4,9}要统计其中大于N(N的值不确定)的和。再假设我们现在有一个求和函数
template
T sum(T *a,T *b,F f)
{
T *i,result=0;
for(i=a;i!=b;++i)
{
if(f(*i)) result+=*i;
}
return result;
}
用函数对象应该就可以这样写:
class isgreater
{
public:
isgreater(int l):limit(l){}
bool operator() (cosnt int &a)
{
return a>limit;
}
private:
int limit;
}
sum(a,a+n,isgreater(3));
看到这里很明显了,求大于3的数字的和,就用3作为参数构造一个函数对象,大于N就用N作为参数构造一个函数对象。同样,使用函数作为sum的第三个参数,不得不重新写函数。充分利用了对象可以有成员变量的性质。
5 结论
函数对象单独使用起来和定义函数没有太大区别,但是将函数对象与C++的模板机制结合起来灵活运用,可以是代码更加简洁清晰。利用好这些C++的特性,可以使代码风格更加清新、精炼。
参考文献:
[1] Lippman S B.C++ Primer[M].4版.北京:人民邮电出版社,2008:450.
[2] 沐枫小筑.C++指针探讨[EB/OL]./Muf/archive/2005/05/11/373734.aspx.
[3] 葛建芳.函数对象及其在STL中的应用[J].微型电脑应用,2006,22(10).