C++ 仿函数

article/2025/9/7 16:24:04

在这里插入图片描述

文章目录

  • 1.由来
  • 2.定义
  • 3.实例
  • 参考文献

1.由来

我们先从一个非常简单的问题入手,来了解为什么要有仿函数。

假设我们现在有一个数组,数组中存有任意数量的数字,我们希望能够统计出这个数组中大于 10 的数字的数量,你的代码很可能是这样的:

#include <iostream>
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<<result<<endl;return 0;
}

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

bool IsGreaterThanThreshold(int num, int threshold) {return num>threshold ? 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<typename _Tp> struct less : public binary_function<_Tp, _Tp, bool> {bool operator()(const _Tp& __x, const _Tp& __y) const{ return __x < __y; }
};// set 的申明
template<typename _Key, typename _Compare = std::less<_Key>,typename _Alloc = std::allocator<_Key>> class set;

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

3.实例

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

class StringAppend {
public:explicit StringAppend(const string& str) : ss(str){}void operator() (const string& str) const {cout << str << ' ' << ss << endl;}
private:const string ss;
};int main() {StringAppend myFunctor2("and world!");myFunctor2("Hello");
}

编译运行输出:

Hello and world!

这个例子应该可以让您体会到仿函数的一些作用:它既能像普通函数一样传入给定数量的参数,还能存储或者处理更多我们需要的有用信息。于是仿函数提供了第四种解决方案:成员变量。成员函数可以很自然地访问成员变量,从而可以解决第一节“1.为什么要有仿函数”中提到的问题:计算出数组中大于指定阈值的数字数量。

#include <iostream>
using namespace std;class IsGreaterThanThresholdFunctor {
public:explicit IsGreaterThanThresholdFunctor(int t):threshold(t){}bool operator() (int num) const {return num > threshold ? 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) ? count + 1 : count;}return count;
}int main() {int a[5] = {10,100,11,5,19};int result = RecallFunc(a, a + 4, IsGreaterThanThresholdFunctor(10));cout << result << endl;
}

编译运行输出:

3

参考文献

百度百科.仿函数


http://chatgpt.dhexx.cn/article/raS82hDw.shtml

相关文章

心形函数的几种表达式

用两个函数表示&#xff1a; f(x)sqrt(1-(abs(x)-1)^2) h(x)-2*sqrt(1-0.5*abs(x)) 也可以根据图中的q(x)画出心形的内部&#xff1a; q(x)(f(x)-h(x))/2*cos(200*x)(f(x)h(x))/2 带入得&#xff1a; 用一个函数表示&#xff0c;我拟合了很久才画出来的&#xff1a; f(x)…

共轭函数

共轭函数在最近火的不行的Gan生成对抗神经网络进阶版本的数学推理中有着神奇的作用&#xff0c;因此在这边记录下。 共轭函数的定义为&#xff1a; f ∗ ( t ) max ⁡ x ∈ dom ⁡ ( f ) { x t − f ( x ) } f ^ { * } ( t ) \max _ { x \in \operatorname { dom } ( f ) }…

高斯函数解析

高斯函数广泛应用于统计学领域&#xff0c;用于表述正态分布&#xff0c;在信号处理领域&#xff0c;用于定义高斯滤波器&#xff0c;在图像处理领域&#xff0c;二维高斯核函数常用于高斯模糊&#xff0c;在数学领域&#xff0c;主要用于解决热力方程和扩散方程。 https://blo…

PostgreSQL 函数

PostgreSQL 函数 函数的定义 使用函数&#xff0c;可以极大的提高用户对数据库的管理效率。函数表示输入参数表示一个具有特定关系的值。 一、数学函数 绝对值函数、三角函数、对数函数、随机函数等&#xff0c;当有错误产生时&#xff0c;数学函数会返回null值。 二、函数…

EXCEL IFS函数简单使用

IFS函数的使用&#xff1a; 在学生成绩以及绩效考核中&#xff0c;我们需要对每个范围的成绩打分。比如【A】,【B】,【C】,【D】。可以使用【IFS()函数】完成操作。 1&#xff1a;选择单元格【C2】&#xff0c;输入【】&#xff0c;点击【fx】&#xff0c;弹出【插入函数】对话…

函数的返回值

1.什么是函数的返回值? print 和 return 的区别,print 仅仅是打印在控制台,而 return 则是将 return 后面的部分作为返回值作为函数的输出 可以用变量接走,继续使用该返回值做其它事 函数需要先定义后调用,函数体中 return 语句的结果就是返回值 如果一个函数没有 reutrn…

反双曲函数

Chapter10&#xff1a;反双曲函数 10.3 反双曲函数10.3.1 反双曲正弦函数【 yarsinh(x) 】反双曲正弦函数图像反双曲正弦函数的指数形式反双曲正弦函数的对数形式推导反双曲正弦函数的导数推导 10.3.2 反双曲余弦函数【 yarcosh(x) 】反双曲余弦函数图像反双曲余弦函数的指数形…

损失函数作用

前言&#xff1a;损失函数是机器学习里最基础也是最为关键的一个要素&#xff0c;通过对损失函数的定义、优化&#xff0c;就可以衍生到我们现在常用的机器学习等算法中 损失函数的作用&#xff1a;衡量模型模型预测的好坏。 正文&#xff1a; 首先我们假设要预测一个公司某商品…

Python自定义函数

一、自定义函数的固定语句 def contrast(a,b) : #使用def来定义一个名称为contrast的方法,a与b的值是两个变量&#xff0c;称为形参if a>b : #使用条件语句进行判定return a #返回a的值elif b>a :return b #返回b的值else:return (ab) …

可测函数

1 定义 可测函数:设是定义在可测集上的实函数,称为上的可测函数,如果满足: a])=b_{a})" class="mathcode" src="https://private.codecogs.com/gif.latex?%5Cforall%20a%5Cin%20R%2C%20%7Ca%7C%20%3C%20&plus;%5Cinfty%2C%5Cexists%20b_%7Ba%7D…

虚函数详解

文章目录 一、多态与重载1、多态的概念2、重载---编译期多态的体现3、虚函数---运行期多态的体现 二、虚函数实例三、虚函数的实现&#xff08;内存布局&#xff09;1、无继承情况2、单继承情况&#xff08;无虚函数覆盖&#xff09;3、单继承情况&#xff08;有虚函数覆盖&…

Java教程之NIO的基本用法

NIO的基本用法 NIO是New I/O的简称&#xff0c;与旧式基于流的I/O相对&#xff0c;从名字上来看&#xff0c;它表示新的一套I/O标准。它是从JDK1.4中被纳入到JDK中的。 与旧式的IO流相比&#xff0c;NIO是基于Block的&#xff0c;它以块为单位来处理数据&#xff0c;最为重要…

关于vp8,vp8与264比较总结

1 Other Codecs l MSN 使用的video codec “x-rtvc1”,09之前的版本使用的ML20.参考网址&#xff1a; http://www.amsn-project.net/forums/index.php?topic6612.0 l Yahoo messenger 使用GIPS的LSVX codec. l 这两个codecs技术保密性强&#xff0c;找不到有用的信息&#xff…

PCM(脉冲编码调制)、iLBC编解码、opus(声音编码格式)、VP8视频压缩格式、H.264数字视频压缩格式

目录 PCM&#xff08;脉冲编码调制&#xff09; 发展史 工作原理 iLBC编解码 基本介绍 技术优势 Opus&#xff08;声音编码格式&#xff09; 特性 播放 技术细节 VP8视频压缩格式 简介 突破创新 技术分析 H.264数字视频压缩格式 背景介绍 优势 特点 PCM&…

JavaCV音视频开发宝典:录制vp8和vp9编码的webm格式视频,以mp4转webm为例

《JavaCV音视频开发宝典》专栏目录导航 《JavaCV音视频开发宝典》专栏介绍和目录 ​ 前言 由于现代浏览器对webm格式的视频支持较好,如下图: 因此使用webm格式来作为主要的存储和回放视频格式。本章将使用mp4文件转webm为例,来讲一下JavaCV如何录制webm格式视频。 webm…

有关 VP8 的一些帧 Golden AltRef 的说明

---------------------------------------------------------------------------------------------------------------------- 一分钟快速搭建 rtmpd 服务器: https://blog.csdn.net/freeabc/article/details/102880984 软件下载地址: http://www.qiyicc.com/download/rtmpd…

主流编解码器(H.264 AVC, H.265 HEVC, VP8, VP9)比较

主流编解码器&#xff08;H.264 AVC, H.265 HEVC, VP8, VP9&#xff09;比较 本文转自&#xff1a;http://houh-1984.blog.163.com/blog/static/31127834201321995354105/ 概述 H.264(MPEG 4, class 10 )是目前嵌入式和移动设备中采用最多的视频编解码算法标准。目前超过50家…

即时通讯音视频开发(十七):视频编码H.264、VP8的前世今生

前言 目前从开发者的角度来说&#xff0c;音视频编码选H.264还是VP8几乎没有悬念&#xff08;个人认为这当然是H.264了&#xff09;。本文重在为读者从技术角度讲解H.264和VP8的发展渊源以及现时所面临的问题&#xff0c;相信读完此文后&#xff0c;对于即时通讯&#xff08;IM…

WebRTC 视频编解码类型的选择 VP8 H264 还是其他?(openh264编码,ffmpeg解码)

在你的WebRTC应用中,选择正确的视频编解码器很重要,但是如何选择又是一个棘手的问题。 WebRTC 视频编解码器 – 简要回顾 WebRTC 曾经很容易。你有 VP8、Opus 和 G.711。 G.711 被删除是因为我不想让你使用它。真的没有理由这样做。 后来,H.264 被添加为强制实现视频编解码器…

视音频编解码H264,265,MPEG-4,VP8,VP9知识总结

首先澄清几个基础知识&#xff1a; 一&#xff1a;封装格式&#xff1a; 我们常见的音视频文件格式例如&#xff1a;mp4 &#xff0c;flv,rmvb,avi等称为封装格式。封装格式里面封装了各种编码器编码的视频源信息的宽高比&#xff0c;视频轨&#xff0c;音频轨。例如视频源为…