C++ STL六大组件-5-Function object(函数对象) 

it2023-10-08  64

C++ STL六大组件-简析

------------------------------------------

C++ STL六大组件-1-Container(容器)                           

C++ STL六大组件-2-Adapter(适配器) 

C++ STL六大组件-3-Algorithm(算法) 

C++ STL六大组件-4-Iterator(迭代器) 

C++ STL六大组件-5-Function object(函数对象) 

C++ STL六大组件-6-Allocator(分配器)

----------------------------------------------------------------------------------

C++ STL Function object

如果一个类将()运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象。函数对象是一个对象,但是使用的形式看起来像函数调用,实际上也执行了函数调用,因而得名。

 

接下来看一个实际例子。

#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, 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 <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,2,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(), 0, SumSquares); cout << "2) 平方和:" << result << endl; result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(3)); cout << "3) 立方和:" << result << endl; result = accumulate(v.begin(), v.end(), 0, 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, int init, 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 中的函数对象类模板

STL 中有一些函数对象类模板,如表 1 所示。

表1:STL 中的函数对象类模板 函数对象类模板成员函数 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;

引入函数对象后 STL 中的“大”、“小”和“相等”概念

前面提到过,默认情况下,STL 中的容器和算法比较元素的大小是通过<运算符进行的。通过 10.3.4 节可知,sort 和 list::sort 都可以通过一个函数对象或函数自定义比较元素大小的规则。例如以下的 sort 版本:

template <class_RandIt, class Pred> void sort(_RandIt first, _RandIt last, Pred op);

实际调用 sort 时,和 op 对应的实参可以是一个函数对象或者函数的名字。sort 在执行过程中用 op(x, y) 比较 x 和 y 的大小,因此可以将 op 称为自定义的“比较器”。

函数对象有哪些好处

  (1)函数对象有自己的状态,即它可以携带自己的成员函数,而且这个函数对象在多次调用的过程中它的那些状态是共享的,而函数则不能做到这点(除非定义函数内部的静态变量或者全局变量)。

  (2)函数对象有自己的类型,而普通函数则没有。在使用STL的容器时可以将函数对象的类型传递给容器作为参数来实例化相应的模板,从而来定制自己的算法,如排序算法。

 

参考文档

http://c.biancheng.net/view/354.htmlhttps://www.cnblogs.com/gis-user/p/5086218.html
最新回复(0)