C++:函数对象,STL提供的函数对象,函数适配器详解
1 函数对象
1.函数对象是行为类似函数的对象。一个类对象,表现出一个函数的特征,即通过对象名+(参数列表)的方式使用一个类对象。
2.使用stl中提供的或自定义的迭代器和**函数对象,**配合stl的算法,组合出各种各样的功能。
3.通过函数对象而不使用函数指针,可以增加通用性,提高效率。
4.函数对象概念:泛化的函数
①将普通函数作为函数对象:传递函数名
#include <iostream> #include <numeric> //包含accumulate算法 #include <functional> #include <vector> using namespace std; int mult(int a, int b) { return a * b; } int main() { int a[] = { 1, 2, 3, 4, 5, 6, 7 }; const int n = sizeof(a) / sizeof(int); //用该式确定数组长度,定义为常量 cout << "所有数累乘为:" << accumulate(a, a + n, 1, mult) << endl; //将普通函数作为函数对象,传递函数名 //指针a,a + n也可以作为迭代器 return 0; }
②将重载了()运算符的类的对象作为函数对象:传递"类名()"
#include <numeric> #include <iostream> using namespace std; class multclass { public: int operator () (int a, int b) const { return a * b; } }; int main() { int a[] = { 1, 2, 3, 4, 5, 6, 7 }; const int n = sizeof(a) / sizeof(int); //确定数组a的长度 cout << "所有数乘积为:" << accumulate(a, a + n, 1, multclass()) << endl; //传输方式是类名(),输出5040 //指针a,a + n也可以作为迭代器 multclass ss; cout << ss(100, 100); //输出10000 return 0; }
2 stl提供的函数对象
1.系统提供函数对象帮助实现基本功能。
2.accmulate算法接受二元函数对象,transform算法接受一元函数对象。
①stl库的multiplies
#include <iostream> #include <functional> #include <numeric> using namespace std; int main(){ int a[] = { 1, 2, 3, 4, 5, 6, 7 }; const int n = sizeof(a) / sizeof(int); cout << accumulate(a, a + n, 1, multiplies<int>()) << endl;//通过stl自带的函数对象multiplies实现乘法,注意要写数据类型<int> //指针a,a + n也可以作为迭代器 return 0; }
②stl库的二元谓词greater
#include <iostream> #include <algorithm> #include <functional> //包含greater using namespace std; int main() { int arr[] = { 24, 43, 5, 4, 62, 34, 7654, 22 }; const int n = sizeof(arr) / sizeof(int); copy(arr, arr + n, ostream_iterator<int>(cout, "\t")); cout << endl; sort(arr, arr + n, greater<int>()); //包含在<algorithm>中,默认是升序 copy(arr, arr + n, ostream_iterator<int>(cout, "\t")); return 0; }
3 函数适配器
适配器顾名思义,让函数适配算法。
unary predicate:一元谓词
binary:二元的
bind:结合,(使)联合在一起
①找出第一个大于40的数,注意用数组和vector都可以
#include <iostream> #include <algorithm> #include <functional> #include <vector> using namespace std; int main() { int a[] = { 30, 40, 50, 90, 20, 10 }; const int n = sizeof(a) / sizeof(int); int *c = find_if(a, a + n, bind2nd(greater<int>(), 40)); cout << *c << endl; return 0; }
一般使用数组初始化向量vector,后续操作更方便
int main() { int a[] = { 30, 40, 50, 90, 20, 10 }; const int n = sizeof(a) / sizeof(int); vector<int> v (a, a + n); //用数组初始化vector vector<int>::iterator p = find_if (v.begin(), v.end(), bind2nd(greater<int>(), 40) ); if (p == v.end()) cout << "找不到" << endl; else cout << *p << endl; return 0; }
find_if算法在stl中的原型声明为: template<class inputiterator, class unarypredicate> inputiterator find_if(inputiterator first, inputiterator last, unarypredicate pred); 它的功能是查找数组[first, last)区间中第一个pred(x)为真的元素。 inputiterator、unarypredicate是用概念来做模板参数名
②利用prt_fun、not1、not2产生组合适配器
#include <iostream> #include <functional> #include <algorithm> #include <vector> using namespace std; int g(int x, int y) { //实现类似greater的功能 return x > y; } int main() { int a[] = { 30, 90, 10, 23, 432, 656, 7, 78 }; const int n = sizeof(a) / sizeof(int); vector<int> v(a, a + n); auto p1 = find_if(v.begin(), v.end(), bind2nd(ptr_fun(g), 40)); //找第一个大于40的数 //ptr_fun将函数指针转换为函数对象,bind2nd将40作为二元函数对象的第二个参数 if (p1 == v.end()) cout << "no element" << endl; else cout << *p1 << endl; auto p2 = find_if(v.begin(), v.end(), not1(bind2nd(ptr_fun(g), 15))); //找第一个不大于15的数 //not1对一元函数对象取逻辑反,find_if找到第一个令bind2nd取false的值 if (p2 == v.end()) cout << "no element" << endl; else cout << *p2 << endl; auto p3 = find_if(v.begin(), v.end(), bind2nd(not2(ptr_fun(g)), 15)); // 找第一个不大于15的数 //not2对二元函数取逻辑反 if (p3 == v.end()) cout << "no element" << endl; else cout << *p3 << endl; return 0; }
③成员函数适配器,类的成员函数要通过适配器转换为普通函数对象
#include <iostream> #include <vector> #include <functional> #include <algorithm> using namespace std; struct car { int id; car(int id) { this->id = id; } void display() const { cout << "car " << id << endl; } }; int main() { vector<car*> pcars; vector<car> cars; for (int i = 0; i < 5; i++) pcars.push_back(new car(i)); //push_back() 在vector最后添加一个元素(参数为要插入的值) for (int i = 5; i < 10; i++) cars.push_back(car(i)); cout << "elements in pcars: " << endl; for_each(pcars.begin(), pcars.end(), mem_fun(&car::display));//for_each算法对每一个迭代器范围中的元素进行函数对象计算 //men_fun适配后函数对象的参数为"对象的指针" cout << endl; for_each(cars.begin(), cars.end(), mem_fun_ref(&car::display)); //men_fun_ptr适配后函数对象的参数为"对象的引用" cout << endl; for (size_t i = 0; i < pcars.size(); ++i) delete pcars[i]; return 0; }
为什么不能同全局函数一样直接传递函数名而成员函数必须以 &类名::函数名 的方式,因为需要考虑static成员函数的情况。
mem_fun(member适配为function):将成员函数适配为普通函数对象,适配出来的函数需要对象的指针作为参数。
men_fun_ref:将成员函数适配为普通函数对象,适配出来的函数需要对象的引用作为参数。
总结
本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注的更多内容!
上一篇: 腊月初一吃汤圆的寓意
下一篇: c++ bitset详解