仿函数(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;
}
五、仿函数与普通函数的区别
特性 仿函数 普通函数
保存状态 支持(通过成员变量保存状态) 不支持(仅能用全局变量间接保存)
编译器优化 易内联,执行效率高 函数指针调用不易被编译器优化
模板适配 天然支持模板(可作为模板参数) 需单独定义模板函数或使用函数指针包装
灵活性 高(可自定义成员变量、成员函数) 低(仅能通过函数逻辑实现固定行为)
相关推荐
地平线开发者6 小时前
J6B vio scenario sample
算法
BothSavage18 小时前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn18 小时前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽19 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
郝学胜_神的一滴19 小时前
CMake 034:生成器表达式:解耦构建时序、精简分支逻辑的终极利器
c++·cmake
先吃饱再说1 天前
判断回文字符串,从一行代码到双指针优化
算法
见过夏天1 天前
C++ 基础入门完全指南
c++
黄敬峰2 天前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法