C++|大话STL第九期——仿函数(函数对象)

今天来到我们STL系列的第九期:仿函数的讲解
C++|大话STL第九期——仿函数(函数对象)
文章图片


文章目录 什么是仿函数?
仿函数的特点:
STL仿函数的分类:
谓词:
内建的仿函数:
算数仿函数:
关系仿函数:
逻辑仿函数:(不常用)

什么是仿函数? 仿函数作为STL六大组件中的其中一个,也称为函数对象,仿函数是一个能行使函数功能的类,仿函数的语法几乎和普通函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。
仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。

仿函数的特点:

  1. 仿函数在使用时,可以像普通函数那样调用,可以有返回值
  2. 仿函数超出普通函数的概念,可以有自己的状态
  3. 函数对象可以作为参数传递
对于他的特点我们分别举例:
仿函数在使用时,可以像普通函数那样调用,可以有返回值class Mytest { public: int operator()(int v1, int v2) { return v1 + v2; } }; int main() { Mytest test01; cout << test01(1, 2) << endl; //输出3 return 0; }

仿函数超出普通函数的概念,可以有自己的状态 class Mytest { public: void operator()(string std) { cout << std << endl; this->count++; } int count=0; //记录函数调用多少次,内部自己状态 //正常需要定义静态或者全局变量 }; void test02() { Mytest test02; test02("okokok"); test02("okokok"); test02("okokok"); test02("okokok"); cout << test02.count << endl; //打印4次okokok } int main() { test02(); return 0; }

函数对象可以作为参数传递 class Mytest { public: void operator()(string std) { cout << std << endl; } }; void doPrint(Mytest &t,string std) { t(std); } int main() { Mytest t; doPrint(t, "okfun"); //输出okfun return 0; }

STL仿函数的分类: 以操作数(operand)的个数划分,分为一元和二元仿函数;
以功能划分,可分为算数运算(Arithmetic)、关系运算(Rational)和逻辑运算(Logical);
谓词:
  • 返回bool类型的仿函数称为谓词
  • 如果operator()接受一个参数就称为一元谓词
  • 如果operator()接受两个参数就称为二元谓词
示例:
一元谓词:利用find_if找到大于5的数字
class Mytest { public: bool operator()(int val) { return val > 5; } }; int main() { vector v{1,2,3,4,5,6,7,8,9 }; auto it = find_if(v.begin(), v.end(), Mytest()); if (it == v.end()) { cout << "没找到" << endl; } else { cout << "找到了:" << *it << endl; } return 0; }

二元谓词:sort排序,同前几期介绍的自定义规则排序
class Mytest { public: bool operator()(int val,int val2) { return val>val2; //从大到小排序 } }; template void Show(vector &v) { for (auto it = v.begin(); it != v.end(); it++) { cout << *it << endl; } } int main() { vector v{1,2,3,4,5,6,7,8,9 }; sort(v.begin(), v.end(), Mytest()); Show(v); return 0; }

内建的仿函数: STL内部提供了一些仿函数,重载了许多(),便于与STL许多算法搭配使用,使用时我们需要引入头文件#include
算数仿函数:
templateT plus 加法仿函数
templateT minus 减法仿函数
templateT multiplies 乘法仿函数
templateT divides 除法仿函数
templateT modulus 取模仿函数
templateT negate 取反仿函数
其中只有negate取反为一元运算,其余都为二元运算,下面我会以乘法和取反举例:
void test01() { negaten; cout << n(50.25) << endl; ; } void test02() { multipliesn; //对于二元运算只允许两个数据类型相同,所以只能写一种 cout << n(1.1, 2.5); } int main() { test01(); //输出-50.25 test02(); //输出1.1*2.5 return 0; }

关系仿函数:
templatebool equal_to 等于
templatenot bool equal_to 不等于
templatebool greater 大于
templatebool greater_equal 大于等于
templatebool less 小于
templatebool less_equal 小于等于

我们以大于来举例:
template void Show(vector &v) { for (auto it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } int main() { vectorv{ 1,2,3,4,5,6,7,8,9,10 }; Show(v); // sort(v.begin(), v.end(), greater()); //从大到小 Show(v); //等同于上面二元谓词的栗子 return 0; }

【C++|大话STL第九期——仿函数(函数对象)】主要实现对比的关系,最常用的为大于,因为默认的排序为小于,我们使用大于关系仿函数可以简单实现上面从大到小的自定义排序,观察sort源码也能发现:
查看sort的声明,STL声明了两种模板template //需要传入一个_Pr _Pred 自定义的规则 _CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast= _Get_unwrapped(_Last); _Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred)); }template //默认的排序 里面传入的是less<>{} 默认小于 _CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last) _STD sort(_First, _Last, less<>{}); }

逻辑仿函数:(不常用)
templatebool logical_and 逻辑与
templateboollogical_or 逻辑或
templatebool logical_not 逻辑非
我们用逻辑非举例:
template void Show(vector &v) { for (auto it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; }int main() { vectorv{ false,true,true,false }; Show(v); //0 1 1 0 vector v2; v2要提前开辟大小,不然没有空间存放数据 v2.resize(v.size()); //搬运算法----transform transform(v.begin(), v.end(), v2.begin(),logical_not()); Show(v2); //1 0 0 1 return 0; }

对于搬运算法transform,我们查看其源码声明
template _CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func)

FIRST对应源容器开始迭代器 LAST 对应源容器结束迭代器 DEST 对应目标容器开始迭代器 Func 对应函数或者函数对象

关于STL中的仿函数我们就到这里了,STL系列也马上结束了,下一期的算法和仿函数经常搭配使用,因此都要好好掌握,有兴趣的可以收藏整个系列,感谢观看!

    推荐阅读