您的位置:首页 > 编程语言 > C语言/C++

C++ STL/ (12) 函数对象适配器

2017-04-11 15:08 489 查看
我们在前一节介绍了函数对象的概念,本节介绍基于函数对象的一个概念–函数对象适配器。

在讲函数对象适配器之前,我们来讲一讲普通函数,函数对象和函数对象适配器的关系。

普通函数是对程序功能的一种封装。这种封装只提供了方法,却没有提供属性。所以当我们希望使用某些属性时,我们往往使用普通函数的升级版–函数对象。我们可以将常用算法和函数对象结合起来使用,这样能完成更复杂的功能。当我们定义了一个函数对象,而这个函数对象又跟我们的需求有一定的偏差时,我们就需要函数对象适配器了。函数对象适配器本质上任然是一个函数;函数对象适配器提供了对函数对象或者普通函数的操作,使其能够根据我们的需求来修改函数对象或者普通函数的功能。下面我们从一个案例开始讲起。

创建一个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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: