当前课程知识点:C++语言程序设计进阶 >  第十章 泛型程序设计与C++标准模板库 >  函数对象 >  函数适配器

返回《C++语言程序设计进阶》慕课在线视频课程列表

函数适配器在线视频

函数适配器

函数适配器

绑定适配器

例10-17:函数适配器实例——找到数组中第一个大于40的元素

//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)为真的元素。

组合适配器

例10-18 ptr_fun、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 成员函数适配器实例

//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++语言程序设计进阶》慕课在线视频列表

函数适配器课程教案、知识点、字幕

大家好

欢迎回来继续学习

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来进行适配

C++语言程序设计进阶课程列表:

第七章 继承与派生

-导学

--导学

-继承的基本概念和语法

--继承的基本概念和语法

-第七章 继承与派生--继承的基本概念和语法习题

-继承方式

--继承方式简介及公有继承

--私有继承和保护继承

-第七章 继承与派生--继承方式

-基类与派生类类型转换

--基类与派生类类型转换

-第七章 继承与派生--基类与派生类类型转换

-派生类的构造和析构

--派生类的构造函数

--派生类的构造函数举例

--派生类的复制构造函数

--派生类的析构函数

--第七章 继承与派生--派生类的构造和析构

-派生类成员的标识与访问

--访问从基类继承的成员

--虚基类

-第七章 继承与派生--派生类成员的标识与访问

-小结

--小结

-综合实例

--第七章综合实例

-实验七

--实验七

-第七章讲义

第八章 多态性

-导学

--导学

-第八章 多态性--导学

-运算符重载

--运算符重载的规则

--双目运算符重载为成员函数

--单目运算符重载为成员函数

--运算符重载为非成员函数

-第八章 多态性--运算符重载

-虚函数

--虚函数

--虚析构函数

--虚表与动态绑定

-第八章 多态性--虚函数

-抽象类

--抽象类

--第八章 多态性--抽象类

-override与final

--override与final

-第八章 多态性--override与final

-小结

--第八章小结

-综合实例

--第八章综合实例

-实验八

--实验八

- 第八章讲义

第九章 模板与群体数据

-导学

--导学

-模板

--函数模板

--类模板

-第九章 模板与群体数据--模板

-线性群体

--线性群体的概念

-第九章 模板与群体数据--线性群体

-数组

--数组类模板

--例9-4数组类应用举例

-链表

--链表的概念与结点类模板

--链表类模板

-第九章 模板与群体数据--链表

-栈

--栈类模板

--栈类模板课后习题

--例9-9 栈的应用

--例9-9 栈的应用课后习题

-队列

--队列类模板

-第九章 模板与群体数据--队列

-排序

--排序概述

--插入排序

--选择排序

--交换排序

-第九章 模板与群体数据--排序

-查找

--查找

--查找课后习题

-小结

--小结

-综合实例

--综合实例

-实验九

--实验九

- 第九章讲义

第十章 泛型程序设计与C++标准模板库

-导学

--导学

-泛型程序设计及STL的结构

--泛型程序设计的基本概念

--STL简介

-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构

-迭代器

--迭代器

-第十章 泛型程序设计与C++标准模板库--迭代器

-容器的基本功能与分类

--容器的基本功能与分类

-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类

-顺序容器

--顺序容器的基本功能

--顺序容器的特征

--顺序容器的插入迭代器与适配器

--第十章 泛型程序设计与C++标准模板库--顺序容器

-关联容器

--关联容器分类和基本功能

--集合

--映射

--多重集合和多重映射

-第十章 泛型程序设计与C++标准模板库--关联容器

-函数对象

--函数对象

--函数适配器

-算法

--算法

-小结

--第十章小结

-综合实例

--综合实例

-实验十

--实验十

- 第十章讲义

第十一章 流类库与输入/输出

-导学

--导学

-I/O流的概念及流类库结构

--I/O流的概念及流类库结构

-第十一章 流类库与输入/输出--I/O流的概念及流类库结构

-输出流

--输出流概述

--向文本文件输出

--向二进制文件输出

--向字符串输出

-第十一章 流类库与输入/输出--输出流

-输入流

--输入流概述

--输入流应用举例

--从字符串输入

-第十一章 流类库与输入/输出--输入流

-输入/输出流

--输入/输出流

-第十一章 流类库与输入/输出--输入/输出流

-小结

--小结

-综合实例

--综合实例

-实验十一

--实验十一

- 第十一章讲义

第十二章 异常处理

-导学

--第12章导学

-异常处理的思想与程序实现

--异常处理的思想与程序实现

-第十二章 异常处理--异常处理的思想与程序实现

-异常处理中的构造与析构

--异常处理中的构造与析构

-第十二章 异常处理--异常处理中的构造与析构

-标准程序库异常处理

--标准程序库异常处理

-第十二章 异常处理--标准程序库异常处理

-小结

--第12章小结

-综合实例

--综合实例

-实验十二

--实验十二

- 第十二章讲义

函数适配器笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。