热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

浅析C++仿函数

这篇文章主要介绍了C++仿函数的相关资料,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下

1.为什么要有仿函数

我们先从一个非常简单的问题入手。假设我们现在有一个数组,数组中存有任意数量的数字,我们希望能够计数出这个数组中大于10的数字的数量,你的代码很可能是这样的:

#include 
using namespace std;

int RecallFunc(int *start, int *end, bool (*pf)(int))
{
  int count=0;
  for(int *i=start;i!=end+1;i++)
  {
  	count = pf(*i) ? count+1 : count;
  }
  return count;
}

bool IsGreaterThanTen(int num)
{
	return num>10 ? true : false;
}

int main()
{
	int a[5] = {10,100,11,5,19};
  int result = RecallFunc(a,a+4,IsGreaterThanTen);
  cout<

RecallFunc()函数的第三个参数是一个函数指针,用于外部调用,而IsGreaterThanTen()函数通常也是外部已经定义好的,它只接受一个参数的函数。如果此时希望将判定的阈值也作为一个变量传入,变为如下函数就不可行了:

bool IsGreaterThanThreshold(int num, int threshold) 
{
	return num>threshold &#63; true : false;
}

虽然这个函数看起来比前面一个版本更具有一般性,但是它不能满足已经定义好的函数指针参数的要求,因为函数指针参数的类型是bool (*)(int),与函数bool IsGreaterThanThreshold(int num, int threshold)的类型不相符。如果一定要完成这个任务,按照以往的经验,我们可以考虑如下可能途径:

(1)阈值作为函数的局部变量。局部变量不能在函数调用中传递,故不可行;
(2)函数传参。这种方法我们已经讨论过了,多个参数不适用于已定义好的RecallFunc函数。
(3)全局变量。我们可以将阈值设置成一个全局变量。这种方法虽然可行,但是不优雅,且非常容易引入Bug,比如全局变量容易同名,造成命名空间污染。

那么有什么好的处理方法呢?仿函数应运而生。

2.仿函数的定义

仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符。因为调用仿函数,实际上就是通过类对象调用重载后的operator()运算符。

如果编程者要将某种“操作”当做算法的参数,一般有两种方法:
(1)一个办法就是先将该“操作”设计为一个函数,再将函数指针当做算法的一个参数。上面的实例就是该做法;
(2)将该“操作”设计为一个仿函数(就语言层面而言是个class),再以该仿函数产生一个对象,并以此对象作为算法的一个参数。

很明显第二种方法会更优秀,原因也在上一小节有所阐述。正如上面的例子,在我们写代码时有时会发现有些功能代码,会不断地被使用。为了复用这些代码,实现为一个公共的函数是一个解决方法。不过函数用到的一些变量,可能是公共的全局变量。引入全局变量,容易出现同名冲突,不方便维护。

这时就可以用仿函数了,写一个简单类,除了维护类的基本成员函数外,只需要重载operator()运算符 。这样既可以免去对一些公共变量的维护,也可以使重复使用的代码独立出来,以便下次复用。而且相对于函数更优秀的性质,仿函数,还可以进行依赖、组合与继承等,这样有利于资源的管理。如果再配合模板技术和Policy编程思想,那就更是威力无穷了,大家可以慢慢体会。Policy表述了泛型函数和泛型类的一些可配置行为(通常都具有被经常使用的缺省值)。

STL中也大量涉及到仿函数,有时仿函数的使用是为了函数拥有类的性质,以达到安全传递函数指针、依据函数生成对象、甚至是让函数之间有继承关系、对函数进行运算和操作的效果。比如STL中的容器set就使用了仿函数less ,而less继承的binary_function,就可以看作是对于一类函数的总体声明了,这是函数做不到的。

//less的定义
template struct less : public binary_function<_Tp, _Tp, bool>
{
   bool operator()(const _Tp& __x, const _Tp& __y) const
   { return __x <__y; }
};
 
//set的申明
template,
				typename _Alloc = std::allocator<_Key>>
  			class set;

仿函数中的变量可以是static的,同时仿函数还给出了static的替代方案,仿函数内的静态变量可以改成类的私有成员,这样可以明确地在析构函数中清除所用的内容,如果用到了指针,那么这个是不错的选择。有人说这样的类已经不是仿函数了,但其实,封装后从外界观察,可以明显地发现,它依然有函数的性质。

3.仿函数实例

我们先来看一个仿函数的例子:

#include 
#include 
using namespace std;

class Functor
{
public:
	void operator() (const string& str) const
	{
		cout <

程序输出:

Hello world!。

可以见到,仿函数提供了第四种解决方案:成员变量。成员函数可以很自然的访问成员变量,从而解决上文最开始的那个问题。

class StringAppend
{
public:
  explicit StringAppend(const string& str) : ss(str){}
  void operator() (const string& str) const
  {
     cout<

程序输出:

Hello and world!。

这个例子应该可以让您体会到仿函数的一些作用:它既能像普通函数一样传入给定数量的参数,还能存储或者处理更多我们需要的有用信息。于是本小节开头的问题就迎刃而解了:

#include 
using namespace std;
class IsGreaterThanThresholdFunctor
{
public:
	explicit IsLessThanTenFunctor(int tmp_threshold) : threshold(tmp_threshold{}
  bool operator() (int num) const
  {
      return num>10 &#63; true : false;
  }
private:
  const int threshold;
};

int RecallFunc(int *start, int *end, IsGreaterThanThresholdFunctor myFunctor)
{
  int count=0;
  for(int *i=start;i!=end+1;i++)
  {
    count = myFunctor(*i) &#63; count+1 : count;
  }
  return count;
}
int main()
{
  int a[5] = {10,100,11,5,19};
  int result = RecallFunc(a,a+4,IsLessThanTenFunctor(10));
  cout<

以上就是浅析C++ 仿函数的详细内容,更多关于C++ 仿函数的资料请关注其它相关文章!


推荐阅读
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 探索1000以内的完美数:因数和等于自身
    本文探讨了如何在1000以内找到所有完美数,即一个数的因数(不包括自身)之和等于该数本身。例如,6是一个完美数,因为1 + 2 + 3 = 6。通过编程实现这一过程,可以更好地理解完美数的特性。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • 作为一名专业的Web前端工程师,掌握HTML和CSS的命名规范是至关重要的。良好的命名习惯不仅有助于提高代码的可读性和维护性,还能促进团队协作。本文将详细介绍Web前端开发中常用的HTML和CSS命名规范,并提供实用的建议。 ... [详细]
  • 配置Windows操作系统以确保DAW(数字音频工作站)硬件和软件的高效运行可能是一个复杂且令人沮丧的过程。本文提供了一系列专业建议,帮助你优化Windows系统,确保录音和音频处理的流畅性。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • 科研单位信息系统中的DevOps实践与优化
    本文探讨了某科研单位通过引入云原生平台实现DevOps开发和运维一体化,显著提升了项目交付效率和产品质量。详细介绍了如何在实际项目中应用DevOps理念,解决了传统开发模式下的诸多痛点。 ... [详细]
  • 本文详细介绍了 Flink 和 YARN 的交互机制。YARN 是 Hadoop 生态系统中的资源管理组件,类似于 Spark on YARN 的配置方式。我们将基于官方文档,深入探讨如何在 YARN 上部署和运行 Flink 任务。 ... [详细]
  • 如何优化现货铝投资以实现更大收益?
    本文探讨了通过优化交易策略和风险管理,如何在现货铝市场中获得更高的收益。我们将详细介绍技术分析、风险控制等关键要素。 ... [详细]
author-avatar
阿INK
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有