当前位置: 首页 > news >正文

C++初阶-仿函数

仿函数是C++的一种特殊的对象它可以像函数一样被调用。本质上,仿函数是一个重载了 operator() 的类或结构体。

仿函数并不是一个函数,而是一个类,只是类似函数一样可以被调用而已,但是这个类或结构体里面只有一个函数:重载函数调用操作符operator(),这种说法并不是很全面,因为仿函数如果只有一个函数的话可能不是那么稳定,可以在这个类里面定义一些成员变量使得该类保持状态。也可以用模板来延伸它更多的用法。仿函数可以:

//(1)
template<class T>
class big
{
public:T operator()(T x, T y) const{return x > y ? x : y;}
};
//(2)
template<class T>
class Less
{
public:bool operator()(T x, T y) const{return x < y;}
};

我们也可以不把它写成模板,直接写成普通类也是可以的!

对于上述代码,我们可以测试一下:

#include<iostream>
using namespace std;
int main()
{big<int> B;cout << B(5, 10) << endl;cout << B.operator()(39, 45) << endl;Less<int> l;if (l(4, 5)){cout << "4<5" << endl;}else{cout << "4>5" << endl;}return 0;
}

那么运行结果就是:

这个仿函数调用如big B;那么B(3,4)相当于B.operator()(3,4);在堆这种可以排序的容器也会用到仿函数,仿函数在我们现在看了用处确实不是很大,比如:我们比较大小直接用x<y这种就可以了,为什么还要用一个类,其实这个仿函数相当于函数优势可大多了。

最常用的一个方面就是在容器中作为模板参数,比如我们之前学过的堆:

其中的Compare就是用来接收仿函数的,如果学到后期的map和set这种高阶的容器:

都会用到仿函数,到我们学到map和set的时候,仿函数就是我们写的比较多的一个部分了,现阶段我们仅仅只是通过堆来简单了解了这个仿函数,比如我之前写的一篇博客:

C++初阶-priority_queue(优先级队列)(堆)-CSDN博客文章浏览阅读274次,点赞5次,收藏6次。在C++官网中,链接为:搜索queue,会出现:在左下角可以看到priority_queue这个容器,它和queue放在同一个头文件,只要在使用它时#include 即可使用这个容器。我们知道queue是队列,在数据结构中,队列是有先进先出的性质的,而在priority_queue(优先级队列)中也有同样的性质,但是它是优先级高的先出,默认情况下是大的优先级高,不过我们可以通过仿函数让小的优先级高。通过这些性质我们发现这个容器很像我们之前学过的数据结构-堆,实际上它的底层就是堆。 https://blog.csdn.net/2401_86446710/article/details/149242986?spm=1011.2415.3001.10575&sharefrom=mp_manage_link这个就是接触仿函数的一个比较重要的部分。

此外,仿函数是对象,可以存储内部状态,而普通函数是无状态的(static 变量除外)。

struct Counter 
{int count = 0;void operator()() { ++count; std::cout << "调用次数: " << count << std::endl;}
};Counter c;
c(); // 输出 "调用次数: 1"
c(); // 输出 "调用次数: 2"(普通函数无法实现这种计数)

这个仿函数可以通过存储成员变量来得到调用仿函数的次数,这个在普通函数时只能用static静态变量来实现,这表明仿函数:可携带状态

仿函数可以为类型,故可以作为模板参数:STL 算法和容器(如 std::sortstd::priority_queue)要求比较函数必须是类型,而仿函数是类型,普通函数不行:

//可以
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap; 
//不可以
bool compare(int a, int b) { return a > b; }
// std::priority_queue<int, std::vector<int>, compare> heap;

所以表明仿函数:可作为模板参数

此外,我们在C++进阶会学到:多态,在多态中用仿函数的次数是比较多的,可以说多态中没有仿函数就不会产生多态,比如:

struct Base 
{virtual void operator()() = 0;
};
struct Derived : Base
{void operator()() override { std::cout << "Derived\n"; }
};Base* f = new Derived();
(*f)(); 

那么这个代码的运行结果就是:Derived

所以仿函数:支持多态

STL 算法直接支持仿函数,而函数指针需要适配,如:

std::sort(v.begin(), v.end(), std::greater<int>()); // 仿函数
std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; }); // Lambda(本质是仿函数)bool compare(int a, int b) { return a > b; }
std::sort(v.begin(), v.end(), compare); // 函数指针(需退化为指针)

在C++11将进行讲解:Lambda,这个也是仿函数,可以说仿函数比普通函数好太多,以后的很多地方都要用到仿函数!

那么哪些情况要用到仿函数还是用普通函数?

  • 用仿函数:需要状态、作为模板参数、高性能场景

  • 用普通函数:简单无状态操作、C风格API兼容

仿函数是C++泛型编程的核心工具之一,理解其优势能显著提升代码质量和性能。

但在C++11之后引入了Lambda表达式,可以用Lambda表达式替代一些仿函数,在一些简单的场景下我们可以用之后学的Lambda表达式来解决一部分可以用仿函数解决的问题,但是这个Lambda部分可能要放到C++进阶最后才能进行讲解了,不过在学完C++之后可以将仿函数与 Lambda 表达式互补使用。Lambda并不是现阶段能讲解的,如果感兴趣的可以到其他博客去了解哦。

仿函数的更多知识我将在C++进阶部分讲解,因为之后的C++进阶部分用仿函数更多。

好了,这一讲就到这里,下一讲将讲解:C++初阶-模板进阶。喜欢的可以一键三连哦,下讲再见!

http://www.dtcms.com/a/272870.html

相关文章:

  • 利萨如图形详解:原理与Python动态绘制
  • 数据库常见元数据表
  • .NET Framework 安装失败及异常情况 常用处理方法
  • 【前端】【Echarts】【Liquidfill 水球图】深入理解 ECharts Liquidfill 水球图:从入门到进阶
  • 解决飞牛 NAS 安装 OpenResty时的端口被占用问题!(如何解决飞牛Nas 80 443 端口被占用的问题)
  • C++ 模板参数展开
  • AI测试革命:从智能缺陷检测到自愈式测试框架的工业实践
  • 谷粒商城高级篇
  • 用GNU Radio生成Frank信号
  • Redisson 的分布式锁
  • 动态物体滤除算法
  • 全连接神经网络
  • AI教学设计助手:生成好教案的Prompt技术实战(二)
  • Java中实现线程安全的几种方式
  • 我做了一个在线工具导航网站!
  • Apache
  • 一招解决Win11桌面右键刷新BUG问题!
  • 高通跃龙IoT-IQ系列芯片深度解析:定位、特性与应用全景
  • 智能音视频-搭建可视化智能体
  • 机器学10——集成学习
  • 北京-4年功能测试2年空窗-报培训班学测开-第四十七天
  • 汽车功能安全-软件集成和验证(Software Integration Verification)【目的、验证输入、集成验证要求】9
  • Synopsys 逻辑综合之 MultiBit Flip-Flop 与 ICG
  • 【TCP/IP】9. 域名系统(DNS)
  • Agent自动化与代码智能
  • 【更新至2023年】1998-2023年各地级市第一产业占GDP比重数据(全市)
  • 防爬虫君子协定 Robots.txt 文件
  • jetson agx orin 刷机、cuda、pytorch配置指南【亲测有效】
  • 【AI】人工智能领域关键术语全解析
  • [C#] 使用TextBox换行失败的原因与解决方案:换用RichTextBox的实战经验