C++中的仿函数Functor
在C++中,有仿函数Functor的概念,首先要明白,它叫做仿函数,就说明它本身肯定不是一个函数 => 事实上,它是一个类的对象,但是可以像函数一样来进行调用
怎么来理解这句话呢 “仿函数是一个类的对象,但是它可以像函数一样来进行调用”?
是这样的 => 本质是在这个类里面实现一个operator(), 实现这个operator之后呢,这个类就有了类似函数的行为, 此时实例化这个类的一个对象时,我们可以像调用函数一样来调用类的这个实例化对象。 => 这个类就叫做 仿函数类
我们来看一个很直观的例子:
class TestAdd { public: int operator()(int x, int y) const // 类 TestAdd中实现了operator, 它就是一个方法函数类,operator操作符可以接受任意数量和类型的参数,还可以有返回值 { return x + y; } }; int main() { TestAdd add; // 创建类TestAdd的一个实例化对象 add int addResult = add(1,2); //像调用函数一样去调用这个仿函数类的对象add std::count << "Result: " << addResult << std::end1; return 0; }
我们再来看另一个仿函数operator的类子
Class Point { public: Point() { _a = _b = 1; } //在类Point中定义仿函数操作符operator Point &operator() (int aa, int bb) { _a += aa; _b += bb; return *this; } private: int _a, _b; } int main() { Point pt; pt(4,5); return 0; }
现在,我们来重点说一下,仿函数类中的重载运算符operator() => operator()函数运算符重载
C++中,仿函数类中重载的operator()函数是仿函数的关键部分,它使得这个类对象可以像函数一样被调用. 通过重载operator()函数,我们可以来定义仿函数类的行为,使它在被调用时执行特定的操作
operator()函数的作用
operator()函数是仿函数类中的函数调用运算符, 它决定了仿函数对象在被调用时的行为
当我们像调用函数一样调用(使用)仿函数对象时, 实际上是在调用该仿函数类对象中重载的operator()函数
operator()函数的语法
operator()函数的语法类似于普通成员函数的语法,但是函数名是operator()
一般情况下,operator()函数可以被重载为const成员函数,以确保对象的状态不被修改
operator()函数的参数和返回值
operator()函数可以接受任意数量和类型的参数
operator()函数可以定义返回值,可以根据需求返回不同类型的值
仿函数重载运算符operator()除了可以在类里面使用外,也可以在结构体struct里面进行使用
最后,我们来看一下仿函数在C++中最大的应用 => 仿函数在STL中的使用,它是STL六大组件之一
接下来我们主要是想讲讲仿函数的使用,仿函数的使用主要是在STL中,包括以下3点
1. 仿函数在使用时,可以像普通函数那样使用,可以有参数,可以有返回值
2. 仿函数超出普通函数的概念,仿函数对象(本质是实现了operator的类对象)可以有自己的状态
3. 仿函数可以作为参数传递 => 这个是仿函数最大的使用
在多数的使用场景中,仿函数最大的用处是作为参数传递, 我们来看一个例子
#include<string> //1. 仿函数在使用时,函数对象可以像普通函数那样调用,可以有参数和返回值 class TestAdd { int operator()(int a, int b) { return a + b; } } void testFunctor1() { TestAdd testAdd; //下面的cout语句中,对仿函数进行调用,它本质上就是类对象在调用重载的operator函数 cout << testAdd(5,5) <<end1; } //2. 仿函数可以有自己的状态 class TestState { public: TestState() { count = 0; } void operator()(string str) { cout << str <<end1; count++; //统计状态次数 } int count; //内部自己的状态 } void testFunctor2() { TestState testState; testState("I am from China"); testState("I am from China"); testState("I am from China"); cout << "testState的调用次数: " << testState.count << end1; } //3. 最大的应用,仿函数对象可以作为参数传递 void FunctorAsArg(TestState &tState, string testValue) { tState(testValue); } void testFunctor3() { TestState testState; FunctorAsArg(testState, "Learn C_++"); }
仿函数中的谓词概念
在仿函数中,有一种仿函数称为谓词,就是返回值为bool类型的仿函数称为谓词, 如果operator()接受一个参数,就是一元谓词,如果operator()接受2个参数,就是2元谓词
谓词最常用的地方,和仿函数最常用的地方一样,都是作为函数的参数传递使用,谓词最常用的地方就是在STL算法中作为参数使用
一元谓词
#include<vector> #include<algorithm> // 一元谓词 class GreaterThanOne { public: bool operator()(int val) { return val > 1; } } void testFunctor1() { vector<int> vt; for(int i = 0; i < 15; i ++) { vt.push_back(i); } //现在我们可以把上面的一元谓词作为参数使用 // 参数GreaterThanOne()是GreaterThanOne类的匿名对象 //因为它里面重载了operator(), 所以我们又叫它为仿函数或者函数对象 vector<int>::iterator it = find_if(vt.begin(),vt.end(),GreaterThanOne()); // 这句话也可以写成 auto it = find_if(vt.begin(),vt.end(),GreaterThanOne())
if(it == v.end())
{
cout << "Not Found" <<end1;
}
else
{
cout << "Found" << *it <<end1;
} }
int main()
{
testFunctor1();
return 0;
}
上面的例子中,有用到一个std::find_if()函数的调用,我们正好趁这个机会来了解一下这个函数
std::find_if()函数功能: 按条件查找元素 函数原型 find_if(iterator begin, iterator end, _pred) 按值查找元素,找到的话就返回指定位置的迭代器,找不到就返回结束迭代器的位置 begin: 开始迭代器 end: 结束迭代器 _pred: 函数或者谓词 (返回bool类型的仿函数-谓词)
二元谓词
除了一元谓词外,还有二元谓词,顾名思义,二元谓词就是有2个参数返回值为bool类型的operator()
#include <vector> #include <algorithm> //二元谓词例子 class CompareTwoValue { public: bool operator(int x, int y) { return x > y; } } void testFunctor2() { vector<int> vec; vec.push_back(100); vec.push_back(200); vec.push_back(300); vec.push_back(400); vec_push_back(500); //默认从小到大排序 sort(vec.begin(),vec.end()); for(vector<int>::iterator it = vec.begin(); it != vec.end() it++) { cout << *it << " "; } cout << end1; //使用函数对象(仿函数)改变算法,使sort方法从大到小排序 sort(vec.begin(),vec.end(),CompareTwoValue()); for(vector<int>::iterator it = vec.begin(); it != vec.end() it++) { cout << *it << " "; } cout << end1; } int main() { testFunctor2(); return 0; }
最后,我们大概来看一看仿函数在STL中的其他应用
STL中的内建函数对象 (仿函数)
要使用STL中的内建仿函数,需要包括头文件
#include <functional> => 它里面包括的仿函数如下
算术仿函数
仿函数原型 template<class T> T plus<T> //加法仿函数 template<class T> T minus<T> //减法仿函数 template<class T> T multiplies<T> //乘法仿函数 template<class T> T divides<T> //除法仿函数 template<class T> T modulus<T> //取模仿函数 template<class T> T negate<T> //取反仿函数
关系仿函数
template<class T> bool equal_to<T> //等于 template<class T> bool not_equal_to<T> //不等于 template<class T> bool greater<T> //大于 template<class T> bool greater_equal<T> //大于等于 template<class T> bool less<T> //小于 template<class T> bool less_equal<T> //小于等于
逻辑仿函数
template<class T> bool logical_and<T> //逻辑与 template<class T> bool logical_or<T> //逻辑或 template<class T> bool logical_not<T> //逻辑非
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具