C++函数对象详解附带实例
如果一个类将()运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象。函数对象是一个对象,但是使用的形式看起来像函数调用,实际上也执行了函数调用,因而得名。
下面是一个函数对象的例子。
#includeusingnamespacestd; classCAverage { public: doubleoperator()(inta1,inta2,inta3) {//重载()运算符 return(double)(a1+a2+a3)/3; } }; intmain() { CAverageaverage;//能够求三个整数平均数的函数对象 cout< 程序的输出结果是:
2.66667()是目数不限的运算符,因此重载为成员函数时,有多少个参数都可以。
average是一个对象,average(3,2,3)实际上就是average.operator(3,2,3),这使得average看上去像函数的名字,故称其为函数对象。
函数对象应用实例1:在accumulate算法中的应用
STL中有以下实现“累加”功能的算法(函数模板):
templateTaccumulate(InItfirst,InItlast,Tval,Predop); 该模板的功能是对[first,last)中的每个迭代器I执行val=op(val,*I),返回最终的val。在DevC++中,numeric头文件中accumulate的源代码如下:
templateTaccumulate(InItfirst,Initlast,Tinit,Predop) { for(;first!=last;++first) init=op(init,*first); returninit; }; 此模板被实例化后,op(init,*first)必须要有定义,则op只能是函数指针或者函数对象。因此调用该accmulate模板时,形参op对应的实参只能是函数名、函数指针或者函数对象。
下面的程序通过accumulate模板求一个vector中元素的平方和,其中用到了函数对象。
#include#include #include //accumulate在此头文件定义 usingnamespacestd; template voidPrintInterval(Tfirst,Tlast) {//输出区间[first,last)中的元素 for(;first!=last;++first) cout<<*first<<""; cout< classSumPowers { private: intpower; public: SumPowers(intp):power(p){} constToperator()(constT&total,constT&value) {//计算value的power次方,加到total上 Tv=value; for(inti=0;i v(a1,a1+SIZE); cout<<"1)";PrintInterval(v.begin(),v.end()); intresult=accumulate(v.begin(),v.end(),0,SumSquares); cout<<"2)平方和:"< (3)); cout<<"3)立方和:"< (4)); cout<<"4)4次方和:"< 程序的输出结果如下:
1)12345678910
2)平方和:385
3)立方和3025
4)4次方和:25333第37行,第四个参数是SumSquares函数的名字。函数名字的类型是函数指针,因此本行将accumulate模板实例化后得到的模板函数定义如下:
intaccumulate(vector::iteratorfirst,vector ::iteratorlast,intinit,int(*op)(int,int)) { for(;first!=last;++first) init=op(init,*first); returninit; } 形参op是一个函数指针,而op(init,*first)就调用了指针op指向的函数,在第37行的情况下就是函数SumSquares。
第39行,第四个参数是SumPowers
(3)。SumPowers是类模板的名字,SumPowers 就是类的名字。类的名字后面跟着构造函数的参数列表,就代表一个临时对象。因此SumPowers (3)就是一个SumPowers 类的临时对象。 编译器在编译此行时,会将accumulate模板实例化成以下函数:
intaccumulate(vector::iteratorfirst,vector ::iteratorlast,intinit,SumPowers op) { for(;first!=last;++first) init=op(init,*first); returninit; } 形参op是一个函数对象,而op(init,*first)等价于:
op.operator()(init,*first);即调用了SumPowers
类的operator()成员函数。 对比SumPowers和SumSquares可以发现,函数对象的operator()成员函数可以根据对象内部的不同状态执行不同操作,而普通函数就无法做到这一点。因此函数对象的功能比普通函数更强大。
函数对象应用实例2:在sort算法中的应用
STL中的排序模板sort能将区间从小到大排序。sort算法有两个版本。第一个版本的原型如下:
templatevoidsort(_Randltfirst,_RandItlast); 该模板可以用来将区间[first,last)中的元素从小到大排序,要求first、last是随机访问迭代器。元素比较大小是用<进行的。如果表达式a
sort算法第二个版本的原型如下:
templatevoidsort(_Randltfirst,_RandItlast,Predop); 这个版本和第一个版本的差别在于,元素a、b比较大小是通过表达式op(a,b)进行的。如果该表达式的值为true,则a比b小;如果该表达式的值为false,也不能认为b比a小,还要看op(b,a)的值。总之,op定义了元素比较大小的规则。下面是一个使用sort算法的例子。
#include#include //sort算法在此头文件中定义 usingnamespacestd; template voidPrintlnterva1(Tfirst,Tlast) {//用以输出[first,last)区间中的元素 for(;first!=last;++first) cout<<*first<<""; cout< a2.v; } structLessA { booloperator()(constA&a1,constA&a2) {//v的个位数小的元素就作为较小的数 return(a1.v%10)<(a2.v%10); } }; ostream&operator<<(ostream&o,constA&a) { o< 编译至第45行时,编译器将sort实例化得到的函数原型如下:
voidsort(A*first,A*last,bool(*op)(constA&,constA&));该函数在执行过程中,当要比较两个元素a、b的大小时,就是看op(a,b)和op(b,a)的返回值。本程序中op指向GreaterA,因此就用GreaterA定义的规则来比较大小。
编译至第47行时,编译器将sort实例化得到的函数原型如下:
voidsort(A*first,A*last,LessAop);该函数在执行过程中,当要比较两个元素a、b的大小时,就是看op(a,b)和op(b,a)的返回值。本程序中,op(a,b)等价于op.opeartor(a,b),因此就用LessA定义的规则来比较大小。
STL中定义了一些函数对象类模板,都位于头文件functional中。例如,greater模板的源代码如下:
templatestructgreater { booloperator()(constT&x,constT&y)const{ returnx>y; } }; 假设有以下数组:
inta[4]={3,5,34,8};要将该数组从大到小排序,则只需写:
sort(a,a+4,greater()); 要使用greater模板,须确保>运算符本来就有定义,或经过了适当的重载。
list容器的sort成员能将元素从小到大排序。它也有两个版本:一个是没有参数的函数,比较大小用<运算符;另一个是函数模板,原型如下:
templatevoidsort(Predop); sort函数允许自定义比较大小的规则,即op(x,y)为真就认为x比y小。例如,假设有:
listlst; 如果希望将lst中的元素按其整数数值从大到小排序,只需写:
lst.sort(greater()); 在使用关联容器和许多算法时,都可以用函数对象来定义比较大小的规则,以及其他一些规则和操作。
STL中的函数对象类模板
STL中有一些函数对象类模板,如表1所示。
表1:STL中的函数对象类模板
函数对象类模板 成员函数 Toperator(constT& x,constT& y)的功能 plus returnx+y; minus< > returnx-y; multiplies returnx*y; divides returnx/y; modulus returnx%y; 成员函数 booloperator(constT& x,constT& y)的功能 equal_to returnx==y; not_equal_to returnx!=y; greater returnx> y; less returnx< y; greater_equal returnx> =y; less_equal returnx<=y; logical_and returnx&& y; logical_or returnx|| y; 成员函数Toperator(constT& x)的功能 negate return-x; 成员函数 booloperator(constT& x)的功能 logical_not return!x; 例如,如果要求两个double型变量x、y的乘积,可以写:
multiplies()(x,y) less是STL中最常用的函数对象类模板,其定义如下:
templatestructless { booloperator()(const_Tp&__x,const_Tp&__y)const {return__x<__y;} }; 要判断两个int变量x、y中x是否比y小,可以写:
if(less()(x,y)){...} 引入函数对象后STL中的“大”、“小”和“相等”概念
前面提到过,默认情况下,STL中的容器和算法比较元素的大小是通过<运算符进行的。通过10.3.4节可知,sort和list::sort都可以通过一个函数对象或函数自定义比较元素大小的规则。例如以下的sort版本:
templatevoidsort(_RandItfirst,_RandItlast,Predop); 实际调用sort时,和op对应的实参可以是一个函数对象或者函数的名字。sort在执行过程中用op(x,y)比较x和y的大小,因此可以将op称为自定义的“比较器”。
关联容器中的元素是从小到大排序的。使用关联容器时,也可以用自定义的比较器取代<运算符,以规定元素之间的大小关系。STL中还有许多算法都可以自定义比较器。在自定义比较器op的情况下,以下三种说法是等价的:
- x小于y。
- op(x,y)的返回值为true。
- y大于x。
同样地,对关联容器的find和count成员函数以及其他一些在有序区间上的STL算法而言,在自定义比较器op的情况下,x和y相等与op(x,y)和op(y,x)都为假是等价的。
到此这篇关于C++函数对象详解附带实例的文章就介绍到这了,更多相关C++函数对象内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!