C++仿函数以及STL内置仿函数

仿函数又称函数对象,本质是重载了operator()运算符的类的对象,可以和普通函数一样被调用。

一、仿函数基础概念

1. 什么是仿函数

仿函数不是函数,而是一个类类型的对象 。当我们给这个对象加上()调用运算符时,它会触发类中重载的operator(),从而实现类似函数的行为。

最简单的仿函数示例

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

// 定义仿函数类
struct Add {
    // 重载函数调用运算符
    int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    Add add; // 创建仿函数对象
    cout << add(3, 5) << endl; // 像函数一样调用,输出8
    cout << Add()(10, 20) << endl; // 临时对象调用,输出30
    return 0;
}

2. 仿函数的核心优势(为什么不用普通函数?)

仿函数解决了普通函数和函数指针的诸多局限性,是 STL 首选的可调用对象形式:

特性 普通函数 函数指针 仿函数
携带状态 ❌ 只能通过全局变量 ❌ 只能通过全局变量 ✅ 可以作为类成员变量存储状态
性能 可内联 ❌ 间接调用,无法内联 ✅ 编译器可直接内联operator()
类型安全 ❌ 类型擦除,易出错 ✅ 每个仿函数都是独立类型
泛型支持 ✅ 完美适配模板元编程
可组合性 ✅ 可通过适配器灵活组合

3. 仿函数的分类

根据operator()接受的参数个数,仿函数分为:

  • 一元仿函数 :接受 1 个参数,如negate<int>
  • 二元仿函数 :接受 2 个参数,如plus<int>
  • 多元仿函数:C++11 后支持,但 STL 内置仿函数最多二元

二、STL 内置仿函数全解

STL 在<functional>头文件中提供了一套完整的通用仿函数,覆盖了所有基础运算,无需我们重复编写。它们都是模板类,可以适配任意数值类型。

1. 算术运算仿函数

用于执行基本的算术计算,全部是二元仿函数(除了negate是一元)。

仿函数 功能 等价表达式
plus<T> 加法 a + b
minus<T> 减法 a - b
multiplies<T> 乘法 a * b
divides<T> 除法 a / b
modulus<T> 取模 a % b
negate<T> 取反(一元) -a

使用示例

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

int main() {
    vector<int> a = {1, 2, 3, 4};
    vector<int> b = {10, 20, 30, 40};
    vector<int> c(4);

    // 两个数组对应元素相加
    transform(a.begin(), a.end(), b.begin(), c.begin(), plus<int>());
    // c = {11, 22, 33, 44}

    // 所有元素取反
    transform(a.begin(), a.end(), a.begin(), negate<int>());
    // a = {-1, -2, -3, -4}

    return 0;
}

2. 关系运算仿函数

用于比较两个值的大小关系,全部是二元仿函数,返回bool类型。

仿函数 功能 等价表达式
equal_to<T> 等于 a == b
not_equal_to<T> 不等于 a != b
less<T> 小于 a < b
greater<T> 大于 a > b
less_equal<T> 小于等于 a <= b
greater_equal<T> 大于等于 a >= b

高频使用场景

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

int main() {
    vector<int> v = {3, 1, 4, 1, 5, 9};

    // 降序排序(默认是less<int>()升序)
    sort(v.begin(), v.end(), greater<int>());
    // v = {9, 5, 4, 3, 1, 1}

    // 统计大于5的元素个数
    int cnt = count_if(v.begin(), v.end(), bind(greater<int>(), placeholders::_1, 5));
    // cnt = 1

    return 0;
}

⚠️ 面试重点std::sort默认使用less<T>(),实现升序排列;std::map/std::set默认也使用less<T>作为比较器,保证元素按升序存储。

3. 逻辑运算仿函数

用于执行布尔逻辑运算,返回bool类型。

仿函数 功能 等价表达式
logical_and<T> 逻辑与 a && b
logical_or<T> 逻辑或 `a b`
logical_not<T> 逻辑非(一元) !a

使用示例

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

int main() {
    vector<int> v = {1, 6, 12, 18, 25};

    // 查找大于5且小于20的第一个元素
    auto it = find_if(v.begin(), v.end(), [](int x) {
        return logical_and<int>()(greater<int>()(x, 5), less<int>()(x, 20));
    });
    // it指向6

    return 0;
}

4. 位运算仿函数(C++11 新增)

用于执行整数的位运算。

仿函数 功能 等价表达式
bit_and<T> 按位与 a & b
bit_or<T> 按位或 `a b`
bit_xor<T> 按位异或 a ^ b
bit_not<T> 按位取反(C++14) ~a
相关推荐
0x3F(小茶)1 小时前
嵌入式C设计模式完全指南(基于《C嵌入式编程设计模式》)
c语言·开发语言·单片机·嵌入式硬件·设计模式
王璐WL1 小时前
【C++进阶】map/multimap 容器详解:从基础使用到底层实现与高频面试题
c++
灰鲸广告联盟1 小时前
新老用户广告价值不同?差异化策略如何实现收益最大化
android·开发语言·flutter·ios
周杰伦fans1 小时前
C# CAD 二次开发:无需启动 AutoCAD 实现 DWG 转 DXF 的完整技术指南
开发语言·c#
qq_283720051 小时前
2026 最新 Python+AI 零基础入门全教程 :从零搭建人工智能完整项目
开发语言·人工智能·python
时尚IT男2 小时前
Python发票识别实战:从PDF中精准提取发票号与(小写)¥金额
开发语言·python·pdf
basketball6162 小时前
Go 语言从入门到进阶:6. 一文彻底吃透结构体(Struct)
开发语言·unity·golang
ch.ju2 小时前
Java Programming Chapter 4——Private attribute
java·开发语言