C++ STL/ (12) 函数对象适配器
来源:互联网 发布:电魂网络官网 编辑:程序博客网 时间:2024/04/28 18:21
我们在前一节介绍了函数对象的概念,本节介绍基于函数对象的一个概念–函数对象适配器。
在讲函数对象适配器之前,我们来讲一讲普通函数,函数对象和函数对象适配器的关系。
普通函数是对程序功能的一种封装。这种封装只提供了方法,却没有提供属性。所以当我们希望使用某些属性时,我们往往使用普通函数的升级版–函数对象。我们可以将常用算法和函数对象结合起来使用,这样能完成更复杂的功能。当我们定义了一个函数对象,而这个函数对象又跟我们的需求有一定的偏差时,我们就需要函数对象适配器了。函数对象适配器本质上任然是一个函数;函数对象适配器提供了对函数对象或者普通函数的操作,使其能够根据我们的需求来修改函数对象或者普通函数的功能。下面我们从一个案例开始讲起。
创建一个vector和一个函数对象print,打印vector中的所有元素。
#include <iostream>#include <vector>#include <algorithm>#include <functional>using namespace std;class print_int{public: void operator()(int i){ cout << i << " "; }};int main(){ vector <int> v; for (int i = 0; i < 10; i++){ v.push_back(i + 1); } for_each(v.begin(), v.end(), print_int()); cout << endl; return 0;}
我们现在又有了一个新的需求,打印vector中所有大于5的元素。
我们对以上代码进行微调,就可以完成该功能。#include <iostream>#include <vector>#include <algorithm>#include <functional>using namespace std;class print_int{public: void operator()(int i){ cout << i << " "; }};class print_int_5{public: void operator()(int i){ if (i > 5){ cout << i << " "; } }};int main(){ vector <int> v; for (int i = 0; i < 10; i++){ v.push_back(i + 1); } for_each(v.begin(), v.end(), print_int_5()); cout << endl; return 0;}
我们现在又有需求了,打印vector中所有大于2的元素。如果我们不停的更改需求,我们就要不停的更改源代码,这是我们不愿意看到的。
那么我们有没有什么好的方法去应对这些需求呢?
答案就是:函数对象适配器
我们现在已经有个打印元素的一元函数对象print_int,我们使用函数对象适配器修改该函数对象,便能完成打印指定指定元素的功能。我们如何使用一个函数对象适配器呢?
- 首先让自定义的函数对象public继承一个父类。这里有两个选择:binary_function 和 unary_function。如果有两个参数选择前者。
- 定义一个函数对象作为参数传入函数对象适配器。常见的函数对象适配器有:
- 绑定适配器 bind1st bind2nd (bind1st绑定第一个参数, bind2nd绑定第二个参数)
- 取反适配器 not1 not2 (not1作用于一元函数对象,not2作用于二元函数对象)
- 普通函数适配器 ptr_fun
- 作用于类中方法的适配器 mem_fun mem_fun_ref
加const
//打印小于指定数字的vector容器中的元素#include <iostream>#include <vector>#include <algorithm>#include <functional>using namespace std;class print_int:public binary_function<int,int,void>{public: void operator()(int i,int num)const{ if (i < num){ cout << i << " "; } }};int main(){ vector <int> v; for (int i = 0; i < 10; i++){ v.push_back(i + 1); } for_each(v.begin(), v.end(), bind2nd(print_int(),5)); //绑定第二个参数5 cout << endl; return 0;}
取反适配器的例子:
#include <iostream>#include <vector>#include <algorithm>#include <functional>using namespace std;class compare_num:public binary_function<int,int,bool>{public: bool operator()(int i, int num) const { return i > num; }};class compare_5:public unary_function<int,bool>{public: bool operator()(int i) const { return i > 5; }};int main(){ vector <int> v; for (int i = 0; i < 10; i++){ v.push_back(i + 1); } cout << endl; vector<int>::iterator i = find_if(v.begin(), v.end(), bind2nd(compare_num(),6)); if (i == v.end()){ cout << "cannot find the number!" << endl; } else{ cout << "find num: " << *i << endl; } auto j = find_if(v.begin(), v.end(), not1(compare_5())); //取反适配器的用法 if (j == v.end()){ cout << "cannot find the number!" << endl; } else{ cout << "find num: " << *j << endl; } return 0;}
普通函数适配器——ptr_fun
#include <iostream>#include <vector>#include <algorithm>#include <functional>using namespace std;void print(int i,int j){ if (i > j){ cout << i << " "; }}void test02(){ vector<int> v; for (int i = 0; i < 10; i++){ v.push_back(i); } for_each(v.begin(), v.end(), bind2nd(ptr_fun(print),5)); //使用ptr_fun将普通函数转换为函数对象,然后给函数对象绑定参数。 cout << endl;}int main(){ test02(); return 0;}
最后,我们介绍mem_fun 和 mem_fun_ref
我们看一下场景。我们在以上的事例中使用的都是vector<int>
数据类型实际上vector可以存放标准数据类型,对象和指针。当我们存放的是对象时,对象本身具有方法。这个方法是定义在类中的成员函数。那么如何将成员函数转换成函数对象呢?
这个时候就要使用mem_fun_ref
扩展:如果容器中存放的是指针,那么就是使用方法mem_fun
#include <iostream>#include <vector>#include <algorithm>#include <functional>using namespace std;class Teacher{public: int id; int age; Teacher(int id, int age) :id(id), age(age){} void print(){ cout << "id: " << this->id << " age: " << this->age << endl; } void operator()(Teacher &t){ cout << "id: " << t.id << " age: " << t.age << endl; }};class Teacher_print{public: void operator()(Teacher &t){ cout << "id: " << t.id << " age: " << t.age << endl; }};int main(){ vector<Teacher> v; vector<Teacher *>v2; Teacher t1(1, 2), t2(3, 4), t3(5, 6); v.push_back(t1); v.push_back(t2); v.push_back(t3); for_each(v.begin(), v.end(), Teacher_print()); //这里的匿名函数对象Teacher_print()可以替换成t1。因为我在class Teacher中重载了函数调用运算符。t1即是一个类定义的对象,同时也是一个函数对象 cout << endl; for_each(v.begin(), v.end(),mem_fun_ref(&Teacher::print)); cout << endl; v2.push_back(&t1); v2.push_back(&t2); v2.push_back(&t3); for_each(v2.begin(), v2.end(), mem_fun(&Teacher::print)); cout << endl; return 0;}
- STL-函数对象适配器
- STL-函数对象适配器
- C++ STL/ (12) 函数对象适配器
- STL函数对象及函数对象适配器
- STL-函数对象及函数对象适配器
- STL函数对象及函数对象适配器
- STL函数对象及函数对象适配器
- STL函数对象及函数对象适配器
- STL函数对象及函数对象适配器
- STL 函数适配器
- STL 函数适配器
- 【STL】函数适配器
- STL之函数适配器
- STL之函数适配器
- C++STL之函数对象及谓词
- C++STL之函数对象及谓词
- C++STL之函数对象及谓词
- C++STL之函数对象及谓词
- install Homebrew for Mac [官网]
- Android内部存储和外部存储以及缓存清理和内存清理!
- [Github]watch和star的区别
- css3 translateX,translateY,translate,transform,transition
- BZOJ1552/3506 robotic sort (Splay 离散化)
- C++ STL/ (12) 函数对象适配器
- linux如何查找大文件或目录
- 背景色渐变处理-linear-gradient
- DownloadManager升级APK并且进度显示
- 基于Opencv3和Qt5的图像处理GUI
- 关于android api的 getLayoutParams()方法报空指针异常!
- 文章标题
- Intellij IDEA 自动生成 serialVersionUID
- React 入门例子