C++中std::functional 使用场景

 更新时间:2026年02月19日 10:19:16   作者:sTone87375  
std::functional是C++标准库中一个非常强大的工具,它提供了一种类型擦除机制,让你能够存储、传递和调用任何可调用对象,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

std::functional 是 C++ 标准库中一个非常强大的工具,它提供了一种**类型擦除(type erasure)**机制,让你能够存储、传递和调用任何可调用对象(callable)。

核心作用

1.统一的可调用对象包装器

std::function 可以包装任何可调用实体,只要签名匹配:

  • 普通函数
  • Lambda 表达式
  • 函数对象(仿函数)
  • 成员函数(通过 std::bind 或 lambda)
  • 甚至其他 std::function

2.类型擦除

隐藏具体类型,只暴露接口。这使得你可以:

  • 在容器中存储不同类型的可调用对象
  • 作为函数参数接受任意可调用对象
  • 实现回调机制而不需要模板

主要使用场景

场景 1:回调函数(Callbacks)

#include <functional>
#include <iostream>

class Button {
    std::function<void()> onClick_;
public:
    void setOnClick(std::function<void()> callback) {
        onClick_ = callback;
    }
    void click() { if (onClick_) onClick_(); }
};

// 使用
Button btn;
btn.setOnClick([]() { std::cout << "Clicked!\n"; });
btn.click();

场景 2:策略模式 / 算法注入

#include <functional>
#include <vector>
#include <algorithm>

void processData(std::vector<int>& data, 
                 std::function<bool(int)> filter,
                 std::function<int(int)> transform) {
    // 先过滤
    data.erase(std::remove_if(data.begin(), data.end(), 
              [&](int x) { return !filter(x); }), data.end());
    // 再转换
    for (auto& x : data) x = transform(x);
}

// 使用
std::vector<int> nums = {1, 2, 3, 4, 5, 6};
processData(nums,
    [](int x) { return x % 2 == 0; },  // 只保留偶数
    [](int x) { return x * x; }         // 平方
);

场景 3:事件系统 / 观察者模式

#include <functional>
#include <vector>
#include <string>

class EventSystem {
    std::vector<std::function<void(const std::string&)>> listeners_;
public:
    void subscribe(std::function<void(const std::string&)> listener) {
        listeners_.push_back(listener);
    }
    void emit(const std::string& event) {
        for (auto& listener : listeners_) {
            listener(event);
        }
    }
};

// 使用
EventSystem events;
events.subscribe([](const std::string& e) { 
    std::cout << "Logger: " << e << "\n"; 
});
events.subscribe([](const std::string& e) { 
    std::cout << "Metrics: recorded " << e << "\n"; 
});

场景 4:延迟执行 / 任务队列

#include <functional>
#include <queue>
#include <iostream>

class TaskQueue {
    std::queue<std::function<void()>> tasks_;
public:
    void addTask(std::function<void()> task) {
        tasks_.push(task);
    }
    void runAll() {
        while (!tasks_.empty()) {
            tasks_.front()();
            tasks_.pop();
        }
    }
};

// 使用
TaskQueue queue;
queue.addTask([]() { std::cout << "Task 1\n"; });
queue.addTask([]() { std::cout << "Task 2\n"; });
queue.runAll();

场景 5:绑定成员函数

#include <functional>
#include <iostream>

class Calculator {
public:
    int add(int a, int b) { return a + b; }
    int multiply(int a, int b) { return a * b; }
};

// 使用 std::bind
Calculator calc;
auto addFunc = std::bind(&Calculator::add, &calc, 
                         std::placeholders::_1, std::placeholders::_2);
std::cout << addFunc(3, 4); // 7

// 或者使用 lambda(更推荐,性能更好)
auto multiplyFunc = [&calc](int a, int b) { 
    return calc.multiply(a, b); 
};

std::functionvs 模板 vs 裸函数指针

特性std::function模板裸函数指针
类型擦除✅ 是❌ 否✅ 是(但只能指向函数)
存储 Lambda✅ 可以✅ 可以❌ 不行(除非无捕获)
运行时开销有(虚函数调用)
编译时类型检查弱(运行时可能抛 bad_function_call)
存储在容器中✅ 容易❌ 难(需要类型擦除)✅ 可以

最佳实践

  1. 优先使用模板:如果不需要存储可调用对象,用模板参数更高效

    // 更好:零开销
    template<typename Func>
    void execute(Func&& f) { f(); }
    
    // 有开销:类型擦除
    void execute(std::function<void()> f) { f(); }
    
  2. 检查空状态:调用前确保 std::function 不为空

    if (func) func();  // 或 if (func != nullptr)
    
  3. 注意开销std::function 通常使用小对象优化(SOO),但大对象会堆分配

  4. C++23 替代:考虑使用 std::move_only_function(仅移动)或 std::copyable_function

std::functional 的核心价值在于灵活性——当你需要在运行时决定调用什么、或者需要在容器中存储可调用对象时,它是不可或缺的工具。

到此这篇关于C++中std::functional 使用场景的文章就介绍到这了,更多相关C++ std::functional 使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文详解C语言操作符

    一文详解C语言操作符

    这篇文章主要详细介绍了C语言的操作符,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 一文带你学习C/C++中的<Windows.h>库

    一文带你学习C/C++中的<Windows.h>库

    c语言 #include<windows.h>是写window程序需要的重要头文件,下面这篇文章主要给大家介绍了C/C++中<Windows.h>库的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • C++程序代码的五大内存分区方式

    C++程序代码的五大内存分区方式

    这篇文章主要介绍了C++程序代码的五大内存分区方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • C语言强制类型转换规则实例详解

    C语言强制类型转换规则实例详解

    强制类型转换是把变量从一种类型转换为另一种数据类型,下面这篇文章主要给大家介绍了关于C语言强制类型转换的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • C++自定义(手撕)vector类实现过程

    C++自定义(手撕)vector类实现过程

    文章介绍了C++中std::vector的简化实现,涵盖模板类定义、动态数组管理、构造析构函数、深拷贝机制、迭代器及容量操作等核心内容,旨在通过手动实现理解其内存管理原理和底层实现逻辑
    2025-09-09
  • opencv C++模板匹配的简单实现

    opencv C++模板匹配的简单实现

    这篇文章主要介绍了opencv C++模板匹配的简单实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • Vscode中接入Deepseek的实现

    Vscode中接入Deepseek的实现

    本文主要介绍了Vscode中接入Deepseek的实现,包括登录Deepseek官网、申请APIKEY、安装和配置VSCode插件,具有一定的参考价值,感兴趣的可以了解一下
    2025-02-02
  • C++ 基础编程之十进制转换为任意进制及操作符重载

    C++ 基础编程之十进制转换为任意进制及操作符重载

    这篇文章主要介绍了C++ 基础编程之十进制转换为任意进制及操作符重载的相关资料,需要的朋友可以参考下
    2017-02-02
  • C++ set的使用方法详解

    C++ set的使用方法详解

    这篇文章主要介绍了C++ set的使用方法详解的相关资料,希望通过本文能帮助到大家,让大家理解掌握set的使用方法,需要的朋友可以参考下
    2017-10-10
  • C语言实现简单的学生学籍管理系统

    C语言实现简单的学生学籍管理系统

    这篇文章主要为大家详细介绍了C语言实现简单的学生学籍管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07

最新评论