当前位置: 首页 > news >正文

C++八股——函数对象

文章目录

    • 一、仿函数
    • 二、Lambda表达式
    • 三、bind
    • 四、function

一、仿函数

仿函数:重载了操作符()的类,也叫函数对象

特征:可以有状态,通过类的成员变量来存储;(有状态的函数对象称之为闭包

样例

class Add {
public:void operator() (int count) {i += count;cout << "i:" << i << endl;}int operator() (int a, int b) {return a + b;}int i = 0; // 状态
};

二、Lambda表达式

Lambda表达式是一种方便创建匿名函数的语法糖,简化函数对象的创建,常用于需要短小逻辑的场景(如 STL 算法)。

语法

[捕获列表](参数列表) mutable -> 返回类型 { 函数体 }

  • 捕获列表:定义如何捕获外部变量,本质是将外部变量转变为类的成员变量
    • [=]:值捕获所有外部变量,只可读,不能修改
    • [&]:引用捕获所有外部变量,可读可写
    • [a, &b]:显示指定,值捕获a,引用捕获b
  • mutable:加上此关键字,允许修改值捕获的变量(值捕获的外部变量成为函数的状态,并不会改变实际的外部变量值)
  • 返回值类型:由于有类型推导,所以可以省略

底层原理

编译器将 lambda 转换为一个仿函数,重载 operator()。例如:

/*
int i = 0;
auto func = [i](int count) mutable -> void {i++;cout << "count:" << count << " i:" << i << endl;
};
*/
class LambdaFun {
public:LambdaFun(int _i) : i(_i) {}void operator() (int count) {i++;cout << "count:" << count << " i:" << i << endl;}
private:int i;
};

例子

std::vector<int> nums = {3, 1, 4};
std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; });
// 降序排序

三、bind

std::bind是用来通过绑定可调用对象以及参数生成新的可调用对象,支持参数顺序调整和部分参数绑定。

用法

#include <functional>
auto new_callable = std::bind(原函数, 绑定参数列表);
  • 占位符std::placeholders::_1, _2, ... 表示未绑定的参数位置

底层原理

编译器将 bind 转换为一个仿函数,重载 operator()。例如:

// auto f = std::bind(add, 10, 20);
class BindFun {
public:BindFun(function<int(int, int)> _fn, int _a, int _b) : fn(_fn), a(_a), b(_b) {}int operator()() const {return fn(a, b);}
private:function<int(int, int)> fn;int a, b;
};// auto f = std::bind(&Add::add, &tmp, 10, std::placeholders::_1);
class BindCFun {
public:// 此处定义了一个类型别名Fn为指向Add类中参数为(int, int),返回值为int的成员函数的指针typedef int (Add::*Fn)(int, int);BindCFun(Fn _fn, Add *_c, int _a) : fn(_fn), c(_c), a(_a) {}int operator()(int b) const {return (c->*fn)(a, b);}
private:Fn fn;Add *c;int a;
};

样例

  • 绑定普通函数

    int add(int a, int b) {return a + b; 
    }
    auto f = std::bind(add, 10, std::placeholders::_1);
    int c = f(20); // c = 30
    
  • 绑定类成员函数

    class Add {
    public:int add(int a, int b) {return a + b;}
    };
    Add tmp;
    auto f = std::bind(&Add::add, &tmp, 10, std::placeholders::_1);
    int c = f(20) // c = 30
    

四、function

std::function是一个抽象了函数参数和返回值的类模板(多态函数包装器)。

用途

把任意函数包装成一个对象,该对象可以保存、传递、复制。

其可以包装:普通函数、类的成员函数和静态成员函数、仿函数、lambda表达式、bind返回的函数对象。

头文件:<functional>

用法:std::function<返回值类型(参数类型列表)> func;

样例

  1. 包装普通函数:

    #include <functional>int add(int a, int b) {return a + b;
    }// 包装普通函数
    std::function<int(int, int)> f_add = add; // f_add1 = &add 效果一样
    int c = f_add(1, 2); // c = 3
    
  2. 包装类静态成员函数:

    class StaticFunc {
    public:static int add(int a, int b) {return a + b;}
    };// 包装类静态成员函数
    std::function<int(int, int)> f_add = &StaticFunc::hello;
    int c = f_add(1, 2); // c = 3
    
  3. 包装态成员函数:

    class Add {
    public:int add(int a, int b) {return a + b;}
    };// 包装类成员函数
    std::function<int(Add *, int, int)> f_add = &Add::hello;
    Add tmp;
    int c = f_add(&tmp, 1, 2); // c = 3
    
  4. 包装仿函数:

    // 包装一中的仿函数Add
    std::function<void(int)> f_add1 = Add();
    std::function<int(int, int)> f_add2 = Add();
    f_add1(1); // 打印 i:1
    f_add1(2); // 打印 i:3, 因为仿函数保存了状态i的值
    int c = f_add2(1, 2); // c = 3
    
  5. 包装Lambda:

    int i = 0;
    auto func = [i](int count) mutable -> void {i++;cout << "count:" << count << " i:" << i << endl;
    };
    // auto 实际为编译器生成的匿名类型(非 std::function)
    // 等效的 std::function 类型为 std::function<void(int)>func(1); // 打印 count:1 i:1
    func(1); // 打印 count:1 i:2
    cout << i << endl; // 打印 0, 因为mutable关键字,所以不会修改外部变量实际的值
    
  6. 包装bind绑定的可调用对象

    三中的样例auto可显示转换为:std::function<int(int)>


总结C++11中function、Lambda、bind之间的关系

function用来描述函数对象的类型;Lambda表达式用来生成函数对象(可以访问外部变量的匿名函数);bind也是用来生成函数对象(函数和参数进行绑定的形式生成)

参考:

  • 【C++面试题】面试官:请简述function,lambda,bind之间的关系_哔哩哔哩_bilibili
  • DeepSeek

相关文章:

  • 基于大模型研究报告清单
  • 【软件测试】基于项目驱动的功能测试报告
  • K8S cgroups详解
  • JS | 正则 · 常用正则表达式速查表
  • spring中的@Value注解详解
  • 【网络原理】数据链路层
  • 一文了解B+树的删除原理
  • SpringBoot 整合 Langchain4j 构建AI智能体应用
  • 英语时态--中英文对“时间”的不同理解
  • 在Python中计算函数耗时并超时自动退出
  • 总结C/C++中程序内存区域划分
  • C++.IP协议通信
  • 【数据结构】前言
  • DEEPPOLAR:通过深度学习发明非线性大核极坐标码(1)
  • Day 5:Warp高级定制与自动化
  • Unity3D仿星露谷物语开发42之粒子系统
  • OBS studio 减少音频中的杂音(噪音)
  • OSCP备战-kioptrixvm3详细解法
  • CMOS内存的地址空间在主内存空间中吗?
  • sunset:Solstice靶场
  • 盖茨说对中国技术封锁起到反作用
  • 普京提议恢复直接谈判,泽连斯基:望俄明日停火,乌愿谈判
  • 山西忻州市人大常委会副主任郭建平接受审查调查
  • 名帅大挪移提前开启,意属皇马的阿隆索会是齐达内第二吗
  • 比特币价格重返10万美元,哪些因素使然?
  • 秦洪看盘|交易型资金收缩,释放短线压力