引子

先考虑一个简单的例子:假设有一个vector<string>,你的任务是统计长度小于5的string的个数,如果使用count_if函数的话,你的代码:

bool LessThan5Function(const string& str) {//寻找长度小于5的字符串return str.length() < 5;
}void test() {vector<string> sVec{ "sadaw","srfafas","12" };int count = count_if(sVec.begin(), sVec.end(), LessThan5Function);//寻找容器中长度小于5的字符串的数量
}

在这里count_if函数的第三个参数是一个函数指针,返回一个bool类型的值。一般的,如果需要指定这个长度len作为参数传入的话,我们可能将函数写成这样:

bool LessThan5Function(const string& str,size_t len) {//寻找长度小于5的字符串return str.length() < len;
}

这个函数看起来比前面一个版本看起来OK,因为更加具有可操作性,但是他不能满足这个泛型函数count_if的参数要求:count_if要求的函数是unary function(仅带有一个参数的函数)。

我们如何才能在只能传入一个参数的情况下使用这个count_if,并且指定自己想要的参数,而且,不需要改变这个函数本身,比如如果我们要小于7的字符串数量,就得将传入的函数写成这样的话,正常人都会崩溃的

bool LessThan7Function(const string& str) {return str.length() < 7;
}

一般这种情况怎么办?

我们应该会想到用一个全局变量

int maxLength = 5;
bool LessThan5Function(const string& str) {//寻找长度小于5的字符串return str.length() < maxLength;
}

但是全局变量的缺点相信大家都很清楚:

  • 污染命名空间(多人协同,冲突)
  • 每次修改功能还是需要去修改这个全局变量
  • 不具有重复使用的功能(比如多个要用到这个函数指针的泛函数)

所以,说了这么多,我们需要的是一个什么东西呢?

我们需要一个能够实现函数功能,并且可以携带我们需要的数据(比如上面的字符串长度),最后最重要的:不会因为多个人同时使用,而造成功能冲突和混乱,的这样的一个东西

这就是我将要介绍的仿函数:

仿函数

借用一下百度百科的解释:

仿函数(functor),就是使一个类的使用看上去像一个函数。其实现就是在类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。

将上面的那个函数,用仿函数的方式改写了之后是什么样子?

class LessThan5Functor {
public:bool operator ()(const string& str) {//寻找长度小于5的字符串return str.length() < 5;}
};

就是一个简单的operator ()操作符的重写,但是仿函数和上面的函数指针不同的一点就是:它是一个对象

什么意思呢?

就是这是一个可以被实例化的、具有内存的、可存储数据的实体

想一下,上面的函数指针,我们想要携带数据进入那个count_if是多么的麻烦和不具有普适性,而仿函数的出现,就是为了兼容STL的标准

仿函数的使用

int main()
{greater<int > gt;cout << gt(1, 2) << endl;//false;   (1)cout << greater<int >()(6, 4) << endl;//true;    (2)system("pause");return 0;
}

上面的代码,就是一个仿函数的使用例子,我们定义了一个greater<int>的对象gt,(1) 中gt(1, 2)就是直接调用了greater<int> gt的的operator ()函数

而(2)是定义了一个greater<int>的局部变量,然后调用其operator ()函数,在(2)的这行代码结束后,这个greater<int>的局部变量就被回收了(临时对象)

善用仿函数的成员变量

针对最开始我们说的多个参数问题,我们可以如何解决呢?

int count = count_if(sVec.begin(), sVec.end(), LessThan5Functor);//寻找容器中长度小于5的字符串的数量

我们可以传入一个LessThanLenFunctor的仿函数对象作为参数,这个对象内部保存了长度信息,LessThanLenFunctor的对象实现如下:

class LessThanLenFunctor {
public:bool operator ()(const string& str) {//寻找长度小于5的字符串return str.length() < len;}LessThanLenFunctor(int l):len(l) {}
private:int len ;
};

这样我们就避免了使用全局变量的那几个问题,而且,非常优雅且有用,我们如何去使用这个仿函数呢?

如下,假设我们想查找长度小于3的字符串:

void test() {vector<string> sVec{ "sadaw","srfafas","12" };int count = count_if(sVec.begin(), sVec.end(), LessThanLenFunctor(3));//寻找容器中长度小于3的字符串的数量
}

我们只需要传入一个内部成员变量len为3的仿函数对象就行了,无论长度如何变化,有多少人要使用多少个不同的仿函数,你的仿函数的功能都不会发生变化

它既能像普通函数一样传入给定数量的参数(一个或者多个),还能存储我们需要的控制信息

C++中的仿函数functor相关推荐

  1. c语言 谓词,C++ 谓词(predicate) 与 仿函数 ( functor (function object))

    #谓词与函数对象 谓词 predicate C++ 标准定义谓词如下: The Predicate parameter is used whenever an algorithm expects a ...

  2. c++仿函数 functor

    https://www.cnblogs.com/decade-dnbc66/p/5347088.html 内容整理自国外C++教材 先考虑一个简单的例子:假设有一个vector<string&g ...

  3. 2022-1-19 C++STL—— 仿函数 functor

    仿函数是为了算法而服务的. 我的理解是,相较于函数,仿函数能够实现泛型参数. 如果一个 class 里面重载小括号,这样的函数创建出来的对象就叫做函数对象. 如果想要自己写出的 functor 和 S ...

  4. 【转】C++中如何区分构造函数与重载operator()得到的仿函数?

    转自:C++中如何区分构造函数与重载operator()得到的仿函数?求大神!_360问答 此外,你觉得仿函数(functor)是否能完全取代function呢? 以下是个人使用C++仿函数,func ...

  5. C++新特性探究(9.1):functor仿函数探究

    相关博文:C++新特性探究(九):functor仿函数 Functor 对象模拟函数   把类对象,像函数名一样使用.   仿函数(functor),就是使一个类的使用看上去像一个函数.其实现就是类中 ...

  6. C++ functor 仿函数

    在C++中,仿函数不是一个函数,是一个类,这个类实现了函数的功能. 如果我想实现一个求和的功能:定义一个Sum类,让其中的()函数实现这个功能,代码如下: class Sum { public:Sum ...

  7. C++多线程并发中线程管理

    一.何为并发 刚开始接触计算机编程语言时,我们编写一个程序,在main入口函数中调用其它的函数,计算机按我们设定的调用逻辑来执行指令获得结果.如果我们想在程序中完成多个任务,可以将每个任务实现为一个函 ...

  8. C++11中的std::function

    文章转载自:http://www.jellythink.com/archives/771 看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard ...

  9. STL学习笔记(仿函数)

    仿函数(Functors) 仿函数(functor),就是使一个类的使用看上去象一个函数.其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了. 例如我们定义一个 ...

最新文章

  1. PL/SQL 中Returning Into的用法
  2. 用PyCharm Profile分析异步爬虫效率
  3. easyui不同的jsp页面之间混乱_16.jsp九大内置对象,四大作用域
  4. 手把手教你做产品经理,视频课教程已经发布,欢迎观看
  5. xmind-HTTP协议
  6. STM8单片机ADC单次采样模式
  7. python编程(supervisor程序管理)
  8. yml 后面的配置覆盖前面的
  9. 解决vue项目在ie浏览器缓存问题。
  10. 配置iSCSI部署网络存储
  11. 【SimpleITK】胸部CT数据3D space归一化,以及3D plot
  12. 蓝桥杯2020年第十一届C++省赛第六题-成绩统计
  13. js实现视频截图,并通过post请求发送图片
  14. 关于AXD调试的详细探索
  15. PS教程证件照底片更换颜色
  16. 2014中秋节,用java为QQ游戏美女找茬写辅助
  17. onlyoffice修改logo图标及开启https
  18. stream根据某个字段去重(对象的某个字段去重)
  19. 排列组合之插板法及变形
  20. API安全(二):API安全设计原则

热门文章

  1. 微服务和分布式的联系与区别什么?
  2. 关于苹果iOS应用审核4.3打回的解决方法
  3. SOHO帮客户找新品,如何拿到最优价?要不要选择大型机械类产品?
  4. 题解 | #字符串操作之substring_index提取#
  5. Android 安装包优化开启资源压缩
  6. AutoJs制作简易自动化脚本(持续更新)
  7. TagName的使用
  8. Invalid tag name “@vue-cli“: Tags may not have any characters that encodeURIComponen 解决
  9. Linux 内核交互图
  10. iOS--在应用内切换语言