()
运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象。函数对象是一个对象,但是使用的形式看起来像函数调用,实际上也执行了函数调用,因而得名。下面是一个函数对象的例子。
#include <iostream>using namespace std;class CAverage{public: double operator()(int a1,int a2,int a3) { //重载()运算符 return (double)(a1 + a2 + a3) / 3; }};int main(){ CAverage average; //能够求三个整数平均数的函数对象 cout << average(3,2,3); //等价于 cout << average.operator(3,3); return 0;}程序的输出结果是:
2. 66667
()
是目数不限的运算符,因此重载为成员函数时,有多少个参数都可以。average 是一个对象,average(3,3) 实际上就是 average.operator(3,3),这使得 average 看上去像函数的名字,故称其为函数对象。函数对象应用实例1:在 accumulate 算法中的应用STL 中有以下实现“累加”功能的算法(函数模板):
template <class InIt,class T,class Pred>
T accumulate(InIt first,InIt last,T val,Pred op);
template <class InIt,class Pred>T accumulate(InIt first,Init last,T init,Pred op){ for (; first != last; ++first) init = op(init,*first); return init;};此模板被实例化后,
op(init,*first)
必须要有定义,则 op 只能是函数指针或者函数对象。因此调用该 accmulate 模板时,形参 op 对应的实参只能是函数名、函数指针或者函数对象。下面的程序通过 accumulate 模板求一个 vector 中元素的平方和,其中用到了函数对象。
#include <iostream>#include <vector>#include <numeric> //accumulate 在此头文件定义using namespace std;template <class T>voID PrintInterval(T first,T last){ //输出区间[first,last)中的元素 for (; first != last; ++first) cout << *first << " "; cout << endl;}int SumSquares(int total,int value){ return total + value * value;}template<class T>class SumPowers{private: int power;public: SumPowers(int p) :power(p) { } const T operator() (const T & total,const T & value) { //计算 value的power次方,加到total上 T v = value; for (int i = 0; i < power - 1; ++i) v = v * value; return total + v; }};int main(){ const int SIZE = 10; int a1[] = { 1,3,4,5,6,7,8,9,10 }; vector<int> v(a1,a1 + SIZE); cout << "1) "; PrintInterval(v.begin(),v.end()); int result = accumulate(v.begin(),v.end(),SumSquares); cout << "2) 平方和:" << result << endl; result = accumulate(v.begin(),SumPowers<int>(3)); cout << "3) 立方和:" << result << endl; result = accumulate(v.begin(),SumPowers<int>(4)); cout << "4) 4次方和:" << result; return 0;}程序的输出结果如下:
1)1 2 3 4 5 6 7 8 9 10
2)平方和:385
3)立方和3025
4)4次方和:25333
第 37 行,第四个参数是 SumSquares 函数的名字。函数名字的类型是函数指针,因此本行将 accumulate 模板实例化后得到的模板函数定义如下:
int accumulate(vector <int>::iterator first,vector <int>::iterator last,int init,int(*op)(int,int)){ for (; first != last; ++first) init = op(init,*first); return init;}形参 op 是一个函数指针,而
op(init,*first)
就调用了指针 op 指向的函数,在第 37 行的情况下就是函数 SumSquares。第 39 行,第四个参数是 SumPowers<int>(3)。SumPowers 是类模板的名字,SumPowers<int> 就是类的名字。类的名字后面跟着构造函数的参数列表,就代表一个临时对象。因此 SumPowers<int>(3) 就是一个 SumPowers<int> 类的临时对象。
编译器在编译此行时,会将 accumulate 模板实例化成以下函数:
int accumulate(vector<int>::iterator first,vector<int>::iterator last,SumPowers<int> op){ for (; first != last; ++first) init = op(init,*first); return init;}形参 op 是一个函数对象,而
op(init,*first)
等价于:op.operator()(init,*first);
即调用了 SumPowers<int> 类的 operator() 成员函数。对比 SumPowers 和 SumSquares 可以发现,函数对象的 operator() 成员函数可以根据对象内部的不同状态执行不同 *** 作,而普通函数就无法做到这一点。因此函数对象的功能比普通函数更强大。函数对象应用实例2:在sort算法中的应用STL 中的排序模板 sort 能将区间从小到大排序。sort 算法有两个版本。第一个版本的原型如下:
template <class_Randlt>
voID sort(_Randlt first,_RandIt last);
<
进行的。如果表达式a<b
的值为 true,则 a 排在 b 前面;如果a<b
的值为 false,则 b 未必排在 a 前面,还要看b<a
是否成立,成立的话 b 才排在 a 前面。要使用这个版本的 sort 算法,待排序的对象必须能用<
运算符进行比较。sort 算法第二个版本的原型如下:
template <class_Randlt,class Pred>
voID sort(_Randlt first,_RandIt last,Pred op);
op(a,b)
进行的。如果该表达式的值为 true,则 a 比 b 小;如果该表达式的值为 false,也不能认为 b 比 a 小,还要看op(b,a)
的值。总之,op 定义了元素比较大小的规则。下面是一个使用 sort 算法的例子。#include <iostream>#include <algorithm> //sort算法在此头文件中定义using namespace std;template <class T>voID Printlnterva1(T first,T last){ //用以输出 [first,last) 区间中的元素 for (; first != last; ++first) cout << *first << " "; cout << endl;}class A{public: int v; A(int n) : v(n) {}};bool operator < (const A & a1,const A & a2){ //重载为 A 的 const 成员函数也可以,重载为非 const 成员函数在某些编译器上会出错 return a1.v < a2.v;}bool Greatera(const A & a1,const A & a2){ //v值大的元素作为较小的数 return a1.v > a2.v;}struct LessA{ bool operator() (const A & a1,const A & a2) { //v的个位数小的元素就作为较小的数 return (a1.v % 10) < (a2.v % 10); }};ostream & operator << (ostream & o,const A & a){ o << a.v; return o;}int main(){ int a1[4] = { 5,1 }; A a2[5] = { 13,12,16 }; sort(a1,a1 + 4); cout << "1)"; Printlnterva1(a1,a1 + 4); //输出 1)1 2 4 5 sort(a2,a2 + 5); //按v的值从小到大排序 cout << "2)"; Printlnterva1(a2,a2 + 5); //输出 2)8 9 12 13 16 sort(a2,a2 + 5,Greatera); //按v的值从大到小排序 cout << "3)"; Printlnterva1(a2,a2 + 5); //输出 3)16 13 12 9 8 sort(a2,LessA()); //按v的个位数从小到大排序 cout << "4)"; Printlnterva1(a2,a2 + 5); //输出 4)12 13 16 8 9 return 0;}编译至第 45 行时,编译器将 sort 实例化得到的函数原型如下:
voID sort(A* first,A* last,bool (*op)(const A &,const A &) );
该函数在执行过程中,当要比较两个元素 a、b 的大小时,就是看 op(a,b) 和 op(b,a) 的返回值。本程序中 op 指向 Greatera,因此就用 Greatera 定义的规则来比较大小。编译至第 47 行时,编译器将 sort 实例化得到的函数原型如下:
voID sort( A* first,LessA op);
该函数在执行过程中,当要比较两个元素 a、b 的大小时,就是看 op(a,a) 的返回值。本程序中,op(a,b) 等价于 op.opeartor(a,b),因此就用 LessA 定义的规则来比较大小。STL 中定义了一些函数对象类模板,都位于头文件 functional 中。例如,greater 模板的源代码如下:
template <class T>struct greater{ bool operator()(const T& x,const T& y) const{ return x > y; }};假设有以下数组:
int a[4] = {3,34,8};
要将该数组从大到小排序,则只需写:sort( a,a+4,greater<int>() );
要使用 greater 模板,须确保>
运算符本来就有定义,或经过了适当的重载。List 容器的 sort 成员能将元素从小到大排序。它也有两个版本:一个是没有参数的函数,比较大小用
<
运算符;另一个是函数模板,原型如下:template <class Pred>
voID sort(Pred op);
List<int> lst;
如果希望将 lst 中的元素按其整数数值从大到小排序,只需写:lst.sort( greater<int>() );
在使用关联容器和许多算法时,都可以用函数对象来定义比较大小的规则,以及其他一些规则和 *** 作。STL 中的函数对象类模板STL 中有一些函数对象类模板,如表 1 所示。函数对象类模板 | 成员函数 T operator ( const T & x,const T & y) 的功能 |
---|---|
plus <T> | return x + y; |
minus < > | return x - y; |
multiplIEs <T> | return x * y; |
divIDes <T> | return x / y; |
modulus <T> | return x % y; |
成员函数 bool operator( const T & x,const T & y) 的功能 | |
equal_to <T> | return x == y; |
not_equal_to <T> | return x! = y; |
greater <T> | return x > y; |
less <T> | return x < y; |
greater_equal <T> | return x > = y; |
less_equal <T> | return x <= y; |
logical_and <T> | return x && y; |
logical_or <T> | return x || y; |
成员函数 T operator( const T & x) 的功能 | |
negate <T> | return - x; |
成员函数 bool operator( const T & x) 的功能 | |
logical_not <T> | return ! x; |
例如,如果要求两个 double 型变量 x、y 的乘积,可以写:
multiplIEs<double> () (x,y)
less 是 STL 中最常用的函数对象类模板,其定义如下:
template <class_Tp>struct less{ bool operator() (const_Tp & __x,const_Tp & __y) const { return __x < __y; }};要判断两个 int 变量 x、y 中 x 是否比 y 小,可以写:
if( less<int>()(x,y) ) { ... }
引入函数对象后 STL 中的“大”、“小”和“相等”概念前面提到过,默认情况下,STL 中的容器和算法比较元素的大小是通过<
运算符进行的。通过 10.3.4 节可知,sort 和 List::sort 都可以通过一个函数对象或函数自定义比较元素大小的规则。例如以下的 sort 版本:template <class_RandIt,class Pred>
voID sort(_RandIt first,Pred 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++函数对象详解(附带实例)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)