函数对象、 函数对象与容器、函数对象与算法
一、函数对象
1、函数对象(function object)也称为仿函数(functor)
2、一个行为类似函数的对象,它可以没有参数,也可以带有若干参数。
3、任何重载了调用运算符operator()的类的对象都满足函数对象的特征
4、函数对象可以把它称之为smart function。
5、STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件<functional>。
二、自定义函数对象
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> using namespace std; class CFunObj { public: void operator()() { cout << "hello,function object!" << endl; } }; int main() { CFunObj fo; fo(); CFunObj()(); return 0; } |
注意:CFunObj()(); 表示先构造一个匿名对象,再调用operator();
C++ Code
1 2 3 4 5 6 7 8 9 10 |
// TEMPLATE CLASS map template < class _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty> > > class map : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false> > { // ordered red-black tree of {key, mapped} values, unique keys }; |
假设现在我们这样使用 map< int, string > mapTest; 那么默认的第三个参数 _Pr = less<int>,再者,map 继承的其中一个类
_Tmap_traits 中有个成员:
_Pr comp;// the comparator predicate for keys
跟踪进insert 函数,其中有这样一句:
if (_DEBUG_LT_PRED(this->comp, _Key(_Where._Mynode()), this->_Kfn(_Val)))
已知 #define _DEBUG_LT_PRED(pred, x, y) pred(x, y) 很明显地,comp 在这里当作函数对象使用,传入两个参数,回头看less 类的
模板实现:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// TEMPLATE STRUCT less template<class _Ty> struct less : public binary_function<_Ty, _Ty, bool> { // functor for operator< bool operator()(const _Ty &_Left, const _Ty &_Right) const { // apply operator< to operands return (_Left < _Right); } }; |
即实现了operator() 函数,左操作数小于右操作数时返回为真。
我们也可以在定义的时候传递第三个参数,如map< int, string, greater<int> > mapTest; 则插入时按key 值从大到小排序(less,
greater 都是STL内置的类,里面实现了operator() 函数),甚至也可以自己实现一个类传递进去,如下面例程所示:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <map> #include <string> #include <iostream> using namespace std; struct MyGreater { bool operator()(int left, int right) { return left > right; } }; int main(void) { map < int, string, /*greater<int> */MyGreater > mapTest; mapTest.insert(map<int, string>::value_type(1, "aaaa")); mapTest.insert(map<int, string>::value_type(3, "cccc")); mapTest.insert(map<int, string>::value_type(2, "bbbb")); for (map < int, string, /*greater<int> */MyGreater >::const_iterator it = mapTest.begin(); it != mapTest.end(); ++it) { cout << it->first << " " << it->second << endl; } return 0; } |
输出为:
3 cccc
2 bbbb
1 aaaa
MyGreater 类并不是以模板实现,只是比较key 值为int 类型的大小。
四、函数对象与算法
在STL一些算法中可以传入函数指针,实现自定义比较逻辑或者计算,同样地这些函数也可以使用函数对象来代替,直接看例程再稍
作分析:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
#include <vector> #include <string> #include <iostream> #include <algorithm> using namespace std; void PrintFun(int n) { cout << n << ' '; } void Add3(int &n) { n += 3; } class PrintObj { public: void operator()(int n) { cout << n << ' '; } }; class AddObj { public: AddObj(int number) : number_(number) { } void operator()(int &n) { n += number_; } private: int number_; }; class GreaterObj { public: GreaterObj(int number) : number_(number) { } bool operator()(int n) { return n > number_; } private: int number_; }; int main(void) { int a[] = {1, 2, 3, 4, 5}; vector<int> v(a, a + 5); /*for_each(v.begin(), v.end(), PrintFun); cout<<endl;*/ for_each(v.begin(), v.end(), PrintObj()); cout << endl; /*for_each(v.begin(), v.end(), Add3); for_each(v.begin(), v.end(), PrintFun); cout<<endl;*/ for_each(v.begin(), v.end(), AddObj(5)); for_each(v.begin(), v.end(), PrintFun); cout << endl; cout << count_if(a, a + 5, GreaterObj(3)) << endl; //计算大于3的元素个数 return 0; } |
输出为:
1 2 3 4 5
6 7 8 9 10
2
回顾for_each 的源码,其中有这样一句: _Func(*_ChkFirst); 也就是将遍历得到的元素当作参数传入函数。
上面程序使用了函数对象,实际上可以这样理解 PrintObj()(*_ChkFirst); 即 PrintObj() 是一个匿名的函数对象,传入参
count_if 中的 GreaterObj(3) 就类似了,将遍历的元素当作参数传递给operator(), 即若元素比3大则返回为真。
五、STL内置的函数对象类
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
- STL知识点(常用算法函数介绍 、容器、类属算法、迭代器、函数对象、适配器、分配器
- 从零开始学C++之STL(八):函数对象、 函数对象与容器、函数对象与算法
- 从零开始学C++之STL(八):函数对象、 函数对象与容器、函数对象与算法
- STL的6大组件:容器、类属算法、迭代器、函数对象、适配器、分配器。
- STL的6大组件:容器、类属算法、迭代器、函数对象、适配器、分配器。
- C++之STL(八):函数对象、 函数对象与容器、函数对象与算法
- 从零开始学C++之STL(八):函数对象、 函数对象与容器、函数对象与算法
- 简化以下程序,将函数对象 divide_by 转换为一个函数,并将 for 循环替换为用一个标准的 C++ 算法来输出数据
- STL容器 算法 函数表
- 使用STL中的泛型算法及函数对象
- 模板函数与模板类的区别。模板函数允许隐式调用,所以STL算法允许传入函数指针,也允许传入函数对象
- STL 查找vector容器中的指定对象:find()与find_if()算法
- 算法和函数对象
- [C++] 通用算法、函数对象、lambda表达式、bind
- STL 统计vector容器中指定对象元素出现的次数:count()与count_if()算法
- STL 算法中函数对象和谓词
- 8.9 编写函数打开文件用于输入,将文件内容读入 string 类型的 vector 容器,每一行存储为该容器对象 的一个元素。8.10 重写上面的程序,把文件中的每个单词存储为 容器的一个元素
- STL_算法_中使用的函数对象
- STL(八):函数对象、 函数对象与容器、函数对象与算法
- c++ 范型算法与函数对象 初认识