当前课程知识点:C++语言程序设计进阶 > 第十章 泛型程序设计与C++标准模板库 > 函数对象 > 函数适配器
绑定适配器:bind1st、bind2nd
将n元函数对象的指定参数绑定为一个常数,得到n-1元函数对象
组合适配器:not1、not2
将指定谓词的结果取反
函数指针适配器:ptr_fun
将一般函数指针转换为函数对象,使之能够作为其它函数适配器的输入。
在进行参数绑定或其他转换的时候,通常需要函数对象的类型信息,例如bind1st和bind2nd要求函数对象必须继承于binary_function类型。但如果传入的是函数指针形式的函数对象,则无法获得函数对象的类型信息。
成员函数适配器:ptrfun、ptrfun_ref
对成员函数指针使用,把n元成员函数适配为n + 1元函数对象,该函数对象的第一个参数为调用该成员函数时的目的对象
也就是需要将“object->method()”转为“method(object)”形式。将“object->method(arg1)”转为二元函数“method(object, arg1)”。
binder2nd的实例构造通常比较冗长,bind2nd函数用于辅助构造binder2nd,产生它的一个实例。
binder1st和bind1st,将一个具体值绑定到二元函数的第一个参数。
//10_17.cpp #include <functional> #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int intArr[] = { 30, 90, 10, 40, 70, 50, 20, 80 }; const int N = sizeof(intArr) / sizeof(int); vector<int> a(intArr, intArr + N); vector<int>::iterator p = find_if(a.begin(), a.end(), bind2nd(greater<int>(), 40)); if (p == a.end()) cout << "no element greater than 40" << endl; else cout << "first element greater than 40 is: " << *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)为真的元素。
对于一般的逻辑运算,有时可能还需要对结果求一次逻辑反。
unarynegate和binarynegate实现了这一适配功能。STL还提供了not1和not2辅助生成相应的函数对象实例,分别用于一元谓词和二元谓词的逻辑取反。
// 10_18.cpp #include <functional> #include<iostream> #include<vector> #include<algorithm> using namespace std; bool g(int x, int y) { return x > y; } int main() { int intArr[] = { 30, 90, 10, 40, 70, 50, 20, 80 }; const int N = sizeof(intArr) / sizeof(int); vector<int> a(intArr, intArr + N); vector<int>::iterator p; p = find_if(a.begin(), a.end(), bind2nd(ptr_fun(g), 40)); if (p == a.end()) cout << "no element greater than 40" << endl; else cout << "first element greater than 40 is: " << *p << endl; p = find_if(a.begin(), a.end(), not1(bind2nd(greater<int>(), 15))); if (p == a.end()) cout << "no element is not greater than 15" << endl; else cout << "first element that is not greater than 15 is: " << *p << endl; p = find_if(a.begin(), a.end(), bind2nd(not2(greater<int>()), 15)); if (p == a.end()) cout << "no element is not greater than 15" << endl; else cout << "first element that is not greater than 15 is: " << *p << endl; return 0; }
//10_19.cpp #include <functional> #include <iostream> #include <vector> #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)); for (int i = 5; i < 10; i++) cars.push_back(Car(i)); cout << "elements in pcars: " << endl; for_each(pcars.begin(), pcars.end(), std::mem_fun(&Car::display)); cout << endl; cout << "elements in cars: " << endl; for_each(cars.begin(), cars.end(), std::mem_fun_ref(&Car::display)); cout << endl; for (size_t i = 0; i < pcars.size(); ++i) delete pcars[i]; return 0; }
大家好
欢迎回来继续学习
C++语言程序设计
这一节我们来学习
函数适配器
函数适配器包括绑定适配器
组合适配器
函数指针适配器
和成员函数适配器
将n元函数对象的指定参数
绑定为一个常数
这样就得到了n-1元的函数对象
有bind1st bind2nd
组合适配器呢
能够将指定的谓词结果取反
有not1 not2
然而函数指针适配器
是干什么用的呢
是对一般的函数指针来使用的
我们知道在进行参数绑定
或者其他转换的时候
通常都需要函数对象的类型信息
例如这个bind1st和bind2nd
就要求函数对象
必须继承于binary_functian类型
但是如果传入的是
一个函数指针形式的函数
比如说
你实参传给它一个函数名
那么就无法获得
函数对象的类型信息
这个时候就需要用
函数指针适配器进行一下转换
还有呢
成员函数适配器
是对成员函数指针使用的
比如说
我们要使用成员函数的时候
那就得有对象指针
或者是对象引用
这样的函数调用
它就不方便放在某些
需要函数对象作参数的地方
这个时候我们可以用
成员函数适配器
将指向对象的指针
或者对象的引用
转换为这个函数的参数
这样这个函数
就可以当做一个
普通的函数对象来使用了
下面的例题
在数组中
查找第一个大于40的数
这里呢
我们还是先定义了一个数组
然后以数组为元素 为素材
构造了一个vector
接下来呢
我们要在这个vector上面
使用find_if算法去查找
序列中出现的第一个
大于40的元素
那么这个find_if算法
它的原型是这样的
我们列在底下这儿
这个算法它的最后一个参数
是要求一个一元谓词
但是我们要查找什么东西大于40
那么显然这要用二元谓词greater
现在我们就用这个bind2nd
去将这个谓词greater进行绑定
绑定它的第二个参数是40
然后它就变成了一元谓词了
就符合这个find_if算法的要求了
于是呢
这样我们就可以在这儿
找到大于40的第一个元素
也就是说这个一元谓词
返回值为真的那个元素
对于逻辑运算呢
有的时候可能需要对结果
再求一次逻辑反
这个时候就可以使用
组合适配器
unary_neate和binary_negate
就实现了这一适配功能
STL还提供了not1和not2
用来辅助生成
相应的函数对象实例
分别用于一元谓词
和二元谓词的逻辑反
下面我们就来看一个
使用组合适配器的实例
这里我们定义了一个普通函数g
实际上它实现的功能
跟那个函数对象greater
其实是一样的
好 接下来在主函数中
我们还是定义一个数组
然后以数组元素为素材
去构造了一个vector对象a
接下来呢
我们要在这个vector里面查找
首先我们要找到第一个
大于40的元素
但是这个地方呢
需要一个函数对象
可是我们这里只提供了
一个普通函数g 函数名
相当于一个指向函数的指针
那这个不符合
需要函数对象的这样一个要求
所以在这儿
用这个ptr_fun去构造一个
利用g构造这么一个函数对象
就满足要求了
可以找出第一个大于40的元素了
那接下来呢
在这个地方我们来看
我们希望找到第一个
不大于15的元素
那我们可用的函数对象
是一个greater
greater找到的应该是
第一个大于15的元素
我们要找到不大于15的元素
也就希望
将greater的返回值
真假给它返一下
所以呢
我们在这儿
要用到这个not1
针对一元谓词的这个取反的
这个bind2nd
把第二个参数绑定了
它就变成一元谓词了
把这个一元谓词它的返回结果
not取一下反
可以达到这样的效果
我们也可以用另外一种方法
先用这个not2
对这个二元谓词起作用
然后再把它绑定为
绑定它的第二个参数
把它绑定为一元谓词
那效果也是一样的
大家可以运行一下
看看它的运行结果
应该是一样的
接下来这个例子呢
为我们演示了
怎么样使用成员函数适配器
将类的成员函数
转换成普通的函数对象
这里我们定义了一个结构体
类型Car
它有构造函数
还有一个display函数
用来显示Car对象的信息
接下来在主函数中
定义了两个向量
一个pcars
用来存放
一系列的car对象的指针
另一个是cars
用来存放一系列的car对象
接下来呢
我们就用这样两个for循环
分别将car指针和car对象
存到这两个向量中去了
接下来呢
我们希望输出这两个向量中
所有成员
所有元素的信息
那用到这个for_each这个模板
这个for_each的作用是
可以从第一个参数
这个迭代器指向的位置开始
到第二个参数迭代器
指向的位置为止
对这一段区域内的元素
都使用第三个参数
这个函数对象
使用它的功能去遍历这个区间
去对每一个元素进行操作
那么这第三个位置呢
本身是需要一个函数对象的
现在我们希望它去调用
car里面定义的这个display函数
虽然display函数
也是一个函数对象
但是它要牵扯到
如果你调用它
就要通过对象指针
或者对象引用去调用它
现在呢
我们就使用
这个标准库里面的这个mem_fun去将这样一个成员函数
适配成普通的函数对象
那接下来对这个cars
这个向量的操作
也是一样的
也是用这么一个适配器
用的是mem_fun_ref适配器
它的差别是什么呢
如果用mem_fun适配器
适配出来的这个函数
它的参数就需要是对象的指针
而用mem_fun_ref这个适配器
适配出来的这个函数
它的参数要求是对象的引用
那我们这个cars
这个vector里面存的是对象
所以我们当然要用
mem_fun_ref来适配
这个pcars里面
存的是对象的指针
所以我们要用
mem_fun来进行适配
-导学
--导学
-继承的基本概念和语法
-第七章 继承与派生--继承的基本概念和语法习题
-继承方式
-第七章 继承与派生--继承方式
-基类与派生类类型转换
-第七章 继承与派生--基类与派生类类型转换
-派生类的构造和析构
--派生类的构造函数
--派生类的析构函数
--第七章 继承与派生--派生类的构造和析构
-派生类成员的标识与访问
--虚基类
-第七章 继承与派生--派生类成员的标识与访问
-小结
--小结
-综合实例
--第七章综合实例
-实验七
--实验七
-导学
--导学
-第八章 多态性--导学
-运算符重载
--运算符重载的规则
-第八章 多态性--运算符重载
-虚函数
--虚函数
--虚析构函数
--虚表与动态绑定
-第八章 多态性--虚函数
-抽象类
--抽象类
--第八章 多态性--抽象类
-override与final
-第八章 多态性--override与final
-小结
--第八章小结
-综合实例
--第八章综合实例
-实验八
--实验八
- 第八章讲义
-导学
--导学
-模板
--函数模板
--类模板
-第九章 模板与群体数据--模板
-线性群体
--线性群体的概念
-第九章 模板与群体数据--线性群体
-数组
--数组类模板
-链表
--链表类模板
-第九章 模板与群体数据--链表
-栈
--栈类模板
--栈类模板课后习题
--例9-9 栈的应用课后习题
-队列
--队列类模板
-第九章 模板与群体数据--队列
-排序
--排序概述
--插入排序
--选择排序
--交换排序
-第九章 模板与群体数据--排序
-查找
--查找
--查找课后习题
-小结
--小结
-综合实例
--综合实例
-实验九
--实验九
- 第九章讲义
-导学
--导学
-泛型程序设计及STL的结构
--STL简介
-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构
-迭代器
--迭代器
-第十章 泛型程序设计与C++标准模板库--迭代器
-容器的基本功能与分类
-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类
-顺序容器
--顺序容器的特征
--第十章 泛型程序设计与C++标准模板库--顺序容器
-关联容器
--集合
--映射
-第十章 泛型程序设计与C++标准模板库--关联容器
-函数对象
--函数对象
--函数适配器
-算法
--算法
-小结
--第十章小结
-综合实例
--综合实例
-实验十
--实验十
- 第十章讲义
-导学
--导学
-I/O流的概念及流类库结构
-第十一章 流类库与输入/输出--I/O流的概念及流类库结构
-输出流
--输出流概述
--向文本文件输出
--向二进制文件输出
--向字符串输出
-第十一章 流类库与输入/输出--输出流
-输入流
--输入流概述
--输入流应用举例
--从字符串输入
-第十一章 流类库与输入/输出--输入流
-输入/输出流
--输入/输出流
-第十一章 流类库与输入/输出--输入/输出流
-小结
--小结
-综合实例
--综合实例
-实验十一
--实验十一
- 第十一章讲义
-导学
--第12章导学
-异常处理的思想与程序实现
-第十二章 异常处理--异常处理的思想与程序实现
-异常处理中的构造与析构
-第十二章 异常处理--异常处理中的构造与析构
-标准程序库异常处理
-第十二章 异常处理--标准程序库异常处理
-小结
--第12章小结
-综合实例
--综合实例
-实验十二
--实验十二
- 第十二章讲义