19.1 C++STL标准模板库大局观-STL总述、发展史、组成与数据结构谈
19.2 C++STL标准模板库大局观-容器分类与array、vector容器精解
19.3 C++STL标准模板库大局观-容器的说明和简单应用例续
19.4 C++STL标准模板库大局观-分配器简介、使用与工作原理说
19.5 C++STL标准模板库大局观-迭代器的概念和分类
19.6 C++STL标准模板库大局观-算法简介、内部处理与使用范例
19.7 C++STL标准模板库大局观-函数对象回顾、系统函数对象与范例
19.8 C++STL标准模板库大局观-适配器概念、分类、范例与总结
文章目录
7.函数对象回顾、系统函数对象与范例
7.1 函数对象/仿函数回顾
上一节讲解了算法,举了几个例子,在针对sort这个算法举例的时候可以注意到,sort的第三个参数是一个函数对象(functionobjects)或者叫仿函数(functors),用来指定一个排序的规则。仿函数其实就是函数对象,只不过仿函数这个称呼比较老,新称呼是函数对象。
这种函数对象在STL里面一般都是用来跟算法配合使用以实现一些特定的功能。换句话来说,这些函数对象主要用来服务于算法,这一点读者要明确。
为什么要引入函数对象这种概念,就是因为它们的调用方式很统一。跟调用函数的语法是一样的,如下:
名字(参数列表)
实际上,函数对象的各种形式虽然可以细分为图19.29中的几种形式,但在叫法上可以统一叫成函数对象。
7.2 标准库中定义的函数对象
前面演示的都是自己写的函数对象,其实,标准库中也提供了许多可以现成拿来使用的函数对象。使用它们之前,要在.cpp源文件前面包含一个头文件:
#include <functional>
在main主函数中加入如下代码:
在这里,先不用管这些标准库中定义的函数对象怎样使用,先看一看都有哪些,怎样分类。下面的内容取材于官方的资料,笔者以表格形式给出,方便读者参考。
(1)算术运算类
(2)关系运算类
(3)逻辑运算类
(4)位运算类
这里随便看一个算术运算类的函数对象,如plus<类型>(),看起来这是用来将两个参数相加。在main主函数中,找个位置输入plus并按F12键,能够看到plus到底是什么。能够观察到,这其实是一个类模板,然后里面重载了operator()。简化一下它的源码,大概如下:
template<class _Ty = void>
struct plus
{
constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator+ to operands
return (_Left + _Right);
}
};
看起来,plus的源码比较简单,重载operator()并在其中实现两个参数相加,仅此而已。
所以,实例化该类模板并生成一个相关的类对象,这个对象就是可调用对象或者叫函数对象。读者理解时就理解成:是一个对象,但又可以像函数调用一样调用。
看下面这行代码:
cout << plus<int>()(4, 5) << endl;
(1)plus 是一个实例化了的类。
(2)类名后面加一个圆括号也就是“plus()”代表生成一个类plus的临时对象(因为plus中重载了operator(),所以这个临时对象是一个可调用对象)。
(3)为了调用这个可调用对象,在临时对象后面,增加圆括号(),之后plus类模板的operator()中有什么参数,这个圆括号中就要有什么参数。因为plus类模板的operator()中需要两个参数,所以要写成:
上面这行代码就是调用可调用对象,实际就是等价于执行了类plus的operator()。执行的结果是两个形参的和值,因此,上面代码的输出结果是9。
7.3 标准库中定义的函数对象范例
19.6.3节中演示了sort算法对一个vector容器中的数据进行从大到小排序,当时为了实现此目的专门写了一个函数——myfuncsort。其实,用系统提供的可调用对象也可以实现相同的功能,这样就没有必要书写自己的myfuncsort函数(可调用对象)了。
在main主函数中加入如下代码:
{
vector<int> myvector3 = { 50,15,80,30,46 };
//数据元素从大到小排序
sort(myvector3.begin(), myvector3.end(), greater<int>()); //最后一个参数是产生一个临时对象,这里int就是容器中的元素类型
//数据元素从小到大排序
sort(myvector3.begin(), myvector3.end(), less<int>());
cout << "断点设置在这里" << endl;
}
上述代码用到了greater()和less()两个可调用对象。读者不要忘记,这两个可调用对象在调用的时候需要两个形参,这一点和myfuncsort函数一样。