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,我们使用函数对象适配器修改该函数对象,便能完成打印指定指定元素的功能。

    我们如何使用一个函数对象适配器呢?

    1. 首先让自定义的函数对象public继承一个父类。这里有两个选择:binary_function 和 unary_function。如果有两个参数选择前者。
    2. 定义一个函数对象作为参数传入函数对象适配器。常见的函数对象适配器有:
      • 绑定适配器 bind1st bind2nd (bind1st绑定第一个参数, bind2nd绑定第二个参数)
      • 取反适配器 not1 not2 (not1作用于一元函数对象,not2作用于二元函数对象)
      • 普通函数适配器 ptr_fun
      • 作用于类中方法的适配器 mem_fun mem_fun_ref
    3. 加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;}
0 0
原创粉丝点击