C++ STL/ (12) 函数对象适配器
2017-04-11 15:08
489 查看
我们在前一节介绍了函数对象的概念,本节介绍基于函数对象的一个概念–函数对象适配器。
在讲函数对象适配器之前,我们来讲一讲普通函数,函数对象和函数对象适配器的关系。
普通函数是对程序功能的一种封装。这种封装只提供了方法,却没有提供属性。所以当我们希望使用某些属性时,我们往往使用普通函数的升级版–函数对象。我们可以将常用算法和函数对象结合起来使用,这样能完成更复杂的功能。当我们定义了一个函数对象,而这个函数对象又跟我们的需求有一定的偏差时,我们就需要函数对象适配器了。函数对象适配器本质上任然是一个函数;函数对象适配器提供了对函数对象或者普通函数的操作,使其能够根据我们的需求来修改函数对象或者普通函数的功能。下面我们从一个案例开始讲起。
创建一个vector和一个函数对象print,打印vector中的所有元素。
我们现在又有了一个新的需求,打印vector中所有大于5的元素。
我们对以上代码进行微调,就可以完成该功能。
我们现在又有需求了,打印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
取反适配器的例子:
普通函数适配器——ptr_fun
最后,我们介绍mem_fun 和 mem_fun_ref
我们看一下场景。我们在以上的事例中使用的都是
这个时候就要使用mem_fun_ref
扩展:如果容器中存放的是指针,那么就是使用方法mem_fun
在讲函数对象适配器之前,我们来讲一讲普通函数,函数对象和函数对象适配器的关系。
普通函数是对程序功能的一种封装。这种封装只提供了方法,却没有提供属性。所以当我们希望使用某些属性时,我们往往使用普通函数的升级版–函数对象。我们可以将常用算法和函数对象结合起来使用,这样能完成更复杂的功能。当我们定义了一个函数对象,而这个函数对象又跟我们的需求有一定的偏差时,我们就需要函数对象适配器了。函数对象适配器本质上任然是一个函数;函数对象适配器提供了对函数对象或者普通函数的操作,使其能够根据我们的需求来修改函数对象或者普通函数的功能。下面我们从一个案例开始讲起。
创建一个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> 4000 #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; }
相关文章推荐
- C++ STL(29):Function Object Adapter(函数对象适配器)
- C++ Primer Plus学习笔记之STL函数对象
- STL运用的C++技术(6)——函数对象
- 拓展C++ STL功能,函数适配器,复合函数composite
- C++适配器功能实现及函数对象
- STL的6大组件:容器、类属算法、迭代器、函数对象、适配器、分配器。
- STL函数对象及函数对象适配器
- C++语法基础--函数对象,函数对象的函数适配器(绑定器,求反器)
- C++ 预定义函数对象以及函数适配器(一)
- c++中STL怎样编写自己的函数对象
- STL函数对象及函数对象适配器
- C++ 11 - STL - 函数对象(Function Object) (下)
- 从零开始学C++之STL(八):函数对象、 函数对象与容器、函数对象与算法
- C++STL之函数对象及谓词
- 【学习笔记】C++高级程序设计:STL:函数对象
- C++ 11 - STL - 函数对象(Function Object) (上)
- C++ 11 - STL - 函数对象(Function Object) (中)
- STL知识点(常用算法函数介绍 、容器、类属算法、迭代器、函数对象、适配器、分配器
- STL的6大组件:容器、类属算法、迭代器、函数对象、适配器、分配器。
- C++STL之函数对象及谓词