首页 > 编程语言 >C++的仿函数functor

C++的仿函数functor

时间:2024-10-15 17:15:00浏览次数:6  
标签:std 状态 调用 函数 int C++ functor operator

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 灵活。

标签:std,状态,调用,函数,int,C++,functor,operator
From: https://www.cnblogs.com/smartljy/p/18467951

相关文章

  • 【C/C++】速通某站上的经典“笔试”编程题
    【C/C++】速通某站上的经典“笔试”编程题一.题目描述:解题思路:代码实现:二.题目描述:解题思路:代码实现:三.题目描述:解题思路:代码实现:一.题目描述:解题思路:将区间里面的数依次取模10(%)、除10,作用是大于等于10的数单独拆开(如123,依次拆开为3,2,1),判断是否等于2,如果......
  • c++中,经常需要用来获取用户输入的写法,或者暂停【防止终端退出】
    目录1.使用`cin.get()`暂停程序2.使用`std::cin.ignore()`结合`std::cin.get()`暂停程序3.使用`system("pause")`(仅限Windows)4.使用循环和`cin.get()`结合等待任意输入5.使用`cin>>`获取用户输入为了防止终端窗口在程序结束后立即关闭,可以使用一些方......
  • Chromium 中HTML5 WebSocket收发消息分析c++(一)
    一、WebSocket前端接口定义:WebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的API。使用 WebSocket() 构造函数来构造一个 WebSocket。构造函数WebSocket(url[,protocols])返回一个 WebSocket 对象。常量ConstantValueWeb......
  • Chromium 中HTML5 WebSocket收发消息分析c++(二)
    看下websocket调用过程:基本定义参考上一篇:Chromium中HTML5WebSocket收发消息分析c++(一)-CSDN博客一、前端测试用例 参考:HTML5WebSocket|菜鸟教程(runoob.com) websocket.html文件如下:<!DOCTYPEHTML><html><head><metacharset="utf-8"><title>Web......
  • C++学习路线(十六)
    void类型指针void->空类型void*->空类型指针,只存储地址的值,丢失类型,无法访问,要访问里面的值我们必须对指针进行正确的类型转换,然后再间接引用指针所有其它类型的指针都可以隐式自动转换成void类型指针,反之需要强制转换。intarr[]={1,2,3,4,5};charch......
  • C++学习路线(十四)
    指针的自增操作查看数组与指针的关系#include<iostream>usingnamespacestd;intmain(){ intages[]={18,20,22,25,28}; intlen=sizeof(ages)/sizeof(ages[0]); cout<<"使用数组的方式访问元素"<<endl; for(inti=0;i<len;i++){ co......
  • C++学习路线(十五)
    多级指针#include<iostream>usingnamespacestd;intmain(){ intblock1=888; int*block2=&block1; int**block3=&block2; int***block4=&block3; int****block5=&block4; cout<<"block2:"<<*block2......
  • Ubuntu中VSCode配置CC++环境
    我的环境:Ubuntu22.04.5LTSVSCode版本:1.94.2参考文章:https://blog.csdn.net/zimuzi2019/article/details/106861692https://zhuanlan.zhihu.com/p/147366852一、安装gcc/g++和gdbsudoapt-getupdatesudoapt-getinstallgccsudoapt-getinstallg++sudoa......
  • OpenCV高级图形用户界面(11)检查是否有键盘事件发生而不阻塞当前线程函数pollKey()的
    操作系统:ubuntu22.04OpenCV版本:OpenCV4.9IDE:VisualStudioCode编程语言:C++11算法描述轮询已按下的键。函数pollKey无等待地轮询键盘事件。它返回已按下的键的代码或如果没有键自上次调用以来被按下则返回-1。若要等待按键被按下,请使用waitKey。注意waitKey......
  • OpenCV高级图形用户界面(8)在指定的窗口中显示一幅图像函数imshow()的使用
    操作系统:ubuntu22.04OpenCV版本:OpenCV4.9IDE:VisualStudioCode编程语言:C++11算法描述在指定的窗口中显示一幅图像。函数imshow在指定的窗口中显示一幅图像。如果窗口是以cv::WINDOW_AUTOSIZE标志创建的,图像将以原始大小显示,不过仍然受限于屏幕分辨率。否则,图像......