仿函数(Functor)详解 + 代码示例

仿函数(也叫函数对象 )是C++中一种重载****了 () 运算符的类/结构体,它看起来像函数调用,却拥有类的特性(可以保存状态、支持模板、可被编译器优化),常配合STL算法(如 sort 、 lower_bound )使用,比普通函数/函数指针更灵活。

一、仿函数的核心特点
  1. 本质是类对象: 重载 operator() 后,可像函数一样调用;
  2. 可保存状态:类的成员变量可以存储上下文信息(普通函数做不到);
  3. 编译器优化友好:比函数指针更容易被编译器内联,效率更高;
  4. 支持模板:可以编写通用的仿函数,适配不同类型。
二、基础示例:简单仿函数
  1. 无状态仿函数(最基础)

重载 operator() ,实现简单的运算/判断逻辑:

cpp 复制代码
  
#include <iostream>
using namespace std;

// 定义仿函数:加法仿函数
struct Add
{
    // 重载()运算符,参数为两个int,返回和
    int operator()(int a, int b) const
    {
        return a + b;
    }
};

// 定义仿函数:判断是否为偶数
struct IsEven
{
    bool operator()(int num) const
    {
        return num % 2 == 0;
    }
};

int main()
{
    // 1. 创建仿函数对象,像调用函数一样使用
    Add add_func;
    cout << "3 + 5 = " << add_func(3, 5) << endl; // 输出:8

    // 2. 也可以直接创建临时对象调用
    cout << "7 + 2 = " << Add()(7, 2) << endl; // 输出:9

    // 3. 偶数判断仿函数
    IsEven is_even;
    cout << "6是否为偶数:" << boolalpha << is_even(6) << endl; // 输出:true
    cout << "5是否为偶数:" << boolalpha << is_even(5) << endl; // 输出:false

    return 0;
}
  1. 有状态仿函数(核心优势)

仿函数可以通过成员变量保存状态,这是普通函数无法实现的:

cpp 复制代码
  
#include <iostream>
using namespace std;

// 仿函数:累加器,保存累加的结果
struct Accumulator
{
    // 成员变量:保存累加状态
    int sum = 0;

    // 重载(),每次调用累加一个数
    void operator()(int num)
    {
        sum += num;
        cout << "当前累加值:" << sum << endl;
    }
};

int main()
{
    Accumulator acc;
    // 多次调用,状态会持续保存
    acc(1);  // sum=1
    acc(2);  // sum=3
    acc(3);  // sum=6
    acc(4);  // sum=10

    // 访问仿函数的状态
    cout << "最终累加结果:" << acc.sum << endl; // 输出:10

    return 0;
}
 
三、仿函数的核心应用:配合STL算法

仿函数是STL算法的"灵魂",常用于自定义排序、查找、遍历规则,这里举几个高频场景:

  1. 配合 sort 实现自定义排序
cpp 复制代码
  
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 仿函数:降序排序
struct Greater
{
    bool operator()(int a, int b) const
    {
        return a > b;
    }
};

// 仿函数:按字符串长度排序
struct StrLenCompare
{
    bool operator()(const string& s1, const string& s2) const
    {
        return s1.size() < s2.size();
    }
};

int main()
{
    // 1. 整数降序排序
    vector<int> nums = {3, 1, 4, 2, 5};
    sort(nums.begin(), nums.end(), Greater()); // 传入仿函数对象
    for (int num : nums) cout << num << " ";  // 输出:5 4 3 2 1
    cout << endl;

    // 2. 字符串按长度升序排序
    vector<string> strs = {"apple", "cat", "banana", "dog"};
    sort(strs.begin(), strs.end(), StrLenCompare());
    for (const string& s : strs) cout << s << " "; // 输出:cat dog apple banana
    cout << endl;

    return 0;
}
  1. 配合 lower_bound 实现自定义查找(降序序列)

结合之前聊的 lower_bound ,用仿函数实现降序序列的二分查找:

cpp 复制代码
  
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
    // 降序序列
    vector<int> vec = {9, 7, 5, 3, 3, 3, 1};
    int target = 3;

    // greater<int>() 是STL自带的仿函数,实现a > b的比较
    auto lower_it = lower_bound(vec.begin(), vec.end(), target, greater<int>());
    cout << "lower_bound找到的位置:" << lower_it - vec.begin() << endl; // 输出:3
    cout << "对应元素:" << *lower_it << endl; // 输出:3

    return 0;
}
  1. 配合 for_each 遍历并处理元素
cpp 复制代码
  
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 仿函数:打印元素并计数
struct PrintAndCount
{
    int count = 0;
    void operator()(int num)
    {
        cout << num << " ";
        count++;
    }
};

int main()
{
    vector<int> nums = {1, 2, 3, 4, 5};
    // for_each返回仿函数对象,可获取其状态
    PrintAndCount pac = for_each(nums.begin(), nums.end(), PrintAndCount());
    cout << endl << "遍历的元素个数:" << pac.count << endl; // 输出:5

    return 0;
}
 
四、STL自带的仿函数

C++标准库在 中提供了常用的仿函数,无需自己定义,直接使用:

仿函数 功能 示例
加法(如std::plus) 执行两个参数的加法运算 std::plus()(3,5)→8;(或自定义Add: [](int a,int b){return a+b;})
减法(如std::minus) 执行两个参数的减法运算 std::minus()(10,4)→6;(或自定义Sub: [](int a,int b){return a-b;})
大于比较(如std::greater) 判断第一个参数是否大于第二个参数 std::greater()(7,3)→true;(或自定义Greater: [](int a,int b){return a>b;})
小于比较(如std::less) 判断第一个参数是否小于第二个参数 std::less()(2,9)→true;(或自定义Less: [](int a,int b){return a<b;})
等于比较(如std::equal_to) 判断两个参数是否相等 std::equal_to()(5,5)→true;(或自定义Equal: [](int a,int b){return a==b;})
示例:
cpp 复制代码
  
#include <iostream>
#include <functional>
using namespace std;

int main()
{
    plus<int> add;
    cout << "2 + 6 = " << add(2, 6) << endl; // 输出:8

    greater<int> gt;
    cout << "5 > 3 ? " << boolalpha << gt(5, 3) << endl; // 输出:true

    return 0;
}
五、仿函数与普通函数的区别
特性 仿函数 普通函数
保存状态 支持(通过成员变量保存状态) 不支持(仅能用全局变量间接保存)
编译器优化 易内联,执行效率高 函数指针调用不易被编译器优化
模板适配 天然支持模板(可作为模板参数) 需单独定义模板函数或使用函数指针包装
灵活性 高(可自定义成员变量、成员函数) 低(仅能通过函数逻辑实现固定行为)
相关推荐
2501_944525544 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 预算详情页面
android·开发语言·前端·javascript·flutter·ecmascript
zhuqiyua5 小时前
第一次课程家庭作业
c++
5 小时前
java关于内部类
java·开发语言
好好沉淀5 小时前
Java 项目中的 .idea 与 target 文件夹
java·开发语言·intellij-idea
只是懒得想了5 小时前
C++实现密码破解工具:从MD5暴力破解到现代哈希安全实践
c++·算法·安全·哈希算法
lsx2024065 小时前
FastAPI 交互式 API 文档
开发语言
VCR__5 小时前
python第三次作业
开发语言·python
码农水水5 小时前
得物Java面试被问:消息队列的死信队列和重试机制
java·开发语言·jvm·数据结构·机器学习·面试·职场和发展
wkd_0075 小时前
【Qt | QTableWidget】QTableWidget 类的详细解析与代码实践
开发语言·qt·qtablewidget·qt5.12.12·qt表格
东东5165 小时前
高校智能排课系统 (ssm+vue)
java·开发语言