如果一个类将()运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象。函数对象是一个对象,但是使用的形式看起来像函数调用,实际上也执行了函数调用,因而得名。
下面是一个函数对象的例子。
#include
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, 2, 3);
return 0;
}
程序的输出结果是:
2. 66667
()是目数不限的运算符,因此重载为成员函数时,有多少个参数都可以。
average 是一个对象,average(3, 2, 3) 实际上就是 average.operator(3, 2, 3),这使得 average 看上去像函数的名字,故称其为函数对象。
函数对象应用实例1:在 accumulate 算法中的应用
STL 中有以下实现“累加”功能的算法(函数模板):
template <class InIt, class T, class Pred>
T accumulate(InIt first, InIt last, T val, Pred op);
该模板的功能是对 [first, last) 中的每个迭代器 I 执行 val = op(val, *I),返回最终的 val。在 Dev C++ 中,numeric 头文件中 accumulate 的源代码如下:
template <class InIt, class T, 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
#include
#include //accumulate 在此头文件定义
using namespace std;
template
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 SumPowers
{
private:
int power;
public:
SumPowers(int p) :power§ { }
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,2,3,4,5,6,7,8,9,10 };
vector v(a1, a1 + SIZE);
cout << "1) "; PrintInterval(v.begin(), v.end());
int result = accumulate(v.begin(), v.end(), 0, SumSquares);
cout << “2) 平方和:” << result << endl;
result = accumulate(v.begin(), v.end(), 0, SumPowers(3));
cout << “3) 立方和:” << result << endl;
result = accumulate(v.begin(), v.end(), 0, SumPowers(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 ::iterator first, vector ::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(3)。SumPowers 是类模板的名字,SumPowers 就是类的名字。类的名字后面跟着构造函数的参数列表,就代表一个临时对象。因此 SumPowers(3) 就是一个 SumPowers 类的临时对象。
编译器在编译此行时,会将 accumulate 模板实例化成以下函数:
int accumulate(vector::iterator first, vector::iterator last, int init, SumPowers op)
{
for (; first != last; ++first)
init = op(init, *first);
return init;
}
形参 op 是一个函数对象,而op(init, *first)等价于:
op.operator()(init, *first);
即调用了 SumPowers 类的 operator() 成员函数。
对比 SumPowers 和 SumSquares 可以发现,函数对象的 operator() 成员函数可以根据对象内部的不同状态执行不同操作,而普通函数就无法做到这一点。因此函数对象的功能比普通函数更强大。
2万+

被折叠的 条评论
为什么被折叠?



