C++的仿函数functor

C++的仿函数functor

详细内容

仿函数(Functor)是 C++ 中的一种设计模式,也叫函数对象。仿函数是一个重载了 operator() 的类或结构体,它可以像普通函数一样被调用。这使得它具有类似函数的行为,但实际上它是一个对象,因此可以拥有状态(成员变量)和更多的灵活性。

仿函数的主要用途是:

  • 可以像函数一样调用,并且可以存储状态。
  • 可以将仿函数对象传递给算法(如 std::sort)来代替普通函数或函数指针。
  • 可以实现更复杂的逻辑,且在多次调用时可以保持内部状态。

1. 仿函数的基本示例

一个简单的仿函数可以是这样:

#include <iostream>

// 定义一个仿函数类
struct Add {
    // 重载 operator() 使其成为仿函数
    int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    Add add;  // 创建仿函数对象
    int result = add(3, 4);  // 像调用函数一样调用仿函数
    std::cout << "Result: " << result << std::endl;  // 输出 7
    return 0;
}

在这个例子中,Add 是一个仿函数类,它重载了 operator(),因此我们可以像调用函数一样使用 Add 对象。

2. 仿函数的灵活性:保持状态

与普通函数不同,仿函数是类的实例,它可以保存状态。你可以通过成员变量来存储状态,并在 operator() 函数中使用这些状态。

例如,定义一个带有状态的仿函数:

#include <iostream>

// 带有状态的仿函数
struct Multiplier {
    int factor;  // 状态变量

    // 构造函数,用于设置初始状态
    Multiplier(int f) : factor(f) {}

    // 重载 operator(),可以访问成员变量 factor
    int operator()(int x) const {
        return x * factor;
    }
};

int main() {
    Multiplier timesTwo(2);  // 创建一个状态为 2 的仿函数对象
    Multiplier timesThree(3); // 创建一个状态为 3 的仿函数对象

    std::cout << "2 * 5 = " << timesTwo(5) << std::endl;   // 输出 10
    std::cout << "3 * 5 = " << timesThree(5) << std::endl; // 输出 15
    return 0;
}

在这个例子中,Multiplier 仿函数对象包含一个状态 factor,它可以在调用时影响运算结果。

3. 仿函数与标准算法

仿函数非常适合与 C++ 标准库中的算法配合使用。例如,可以将仿函数对象作为参数传递给 std::sort 等算法,而不是函数指针或 lambda 表达式。

例如,使用仿函数自定义排序:

#include <iostream>
#include <vector>
#include <algorithm>

// 定义一个仿函数,用于降序比较
struct CompareDesc {
    bool operator()(int a, int b) const {
        return a > b;
    }
};

int main() {
    std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2};

    // 使用仿函数进行降序排序
    std::sort(vec.begin(), vec.end(), CompareDesc());

    std::cout << "Sorted in descending order: ";
    for (int n : vec) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,CompareDesc 是一个仿函数,它用于自定义比较规则(降序排序),并传递给 std::sort

4. 仿函数的优势

  • 状态存储:与普通函数不同,仿函数可以通过类的成员变量保存状态,这使得仿函数更适合实现复杂的逻辑或多次调用时需要保存状态的情况。
  • 可组合性:仿函数可以在创建时初始化状态,并且可以像其他对象一样复制、传递和保存。
  • 高效:在某些情况下,仿函数的性能可能比 std::function 更好,因为仿函数没有类型擦除和动态分配的开销。

5. 仿函数与 std::function 的对比

  • 仿函数 是编译期决定的,它是一个类,编译器知道它的确切类型,并且可以进行内联优化。
  • std::function 是一个通用的可调用对象包装器,它可以持有任何类型的可调用对象(包括普通函数、lambda、仿函数等),但有一些运行时开销(如类型擦除和动态分配)。

仿函数通常用于需要最大化性能并且不需要 std::function 的灵活性时。

总结:

  • 仿函数是一个重载了 operator() 的类或结构体,能够像普通函数一样被调用。
  • 仿函数可以存储状态,非常适合需要在多次调用时保留状态的场景。
  • 仿函数可以与标准库算法配合使用,如 std::sort,用于自定义比较规则等。
  • std::function 相比,仿函数更加高效,但不如 std::function 灵活。

本文作者:Gold_stein

本文链接:https://www.cnblogs.com/smartljy/p/18467951

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Gold_stein  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
历史上的今天:
2023-10-15 北大编译实践踩坑
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 逃离地面 RAD & 三浦透子
逃离地面 - RAD & 三浦透子
00:00 / 00:00
An audio error has occurred.

作词 : 野田洋次郎

作曲 : 野田洋次郎

空飛ぶ羽根と引き換えに 繋ぎ合う手を選んだ僕ら

それでも空に魅せられて 夢を重ねるのは罪か

夏は秋の背中を見て その顔を思い浮かべる

憧れなのか、恋なのか 叶わぬと知っていながら

重力が眠りにつく 1000年に一度の今日

太陽の死角に立ち 僕らこの星を出よう

彼が眼を覚ました時 連れ戻せない場所へ

「せーの」で大地を蹴って ここではない星へ

行こう

もう少しで運命の向こう もう少しで文明の向こう

もう少しで運命の向こう もう少しで

夢に僕らで帆を張って 来たるべき日のために夜を超え

いざ期待だけ満タンで あとはどうにかなるさと 肩を組んだ

怖くないわけない でも止まんない

ピンチの先回りしたって 僕らじゃしょうがない

僕らの恋が言う 声が言う

「行け」と言う