今天来简单的看看C++的回调函数

为什么需要回调函数

为什么需要回调函数?

  • 程序中有些逻辑无法提前写死(比如事件触发、异步操作)。
  • 希望把“做什么”和“什么时候做”分离开。

基础知识

定义:把一个函数作为参数传递给另一个函数,在合适的时机调用。

本质:控制反转(Inversion of Control, IoC),把做什么交给用户。

常见场景

  • 事件驱动(按钮点击、信号触发)。
  • 算法参数化(排序比较函数)。
  • 异步编程(网络、I/O)。

语法

使用函数指针

1
2
3
4
5
6
7
8
9
10
11
void callback(int result) {
std::cout << "Callback result: " << result << std::endl;
}

void process(int x, void (*cb)(int)) {
cb(x * 2);
}

int main() {
process(5, callback); // 传入函数指针
}

使用仿函数(函数对象)

1
2
3
4
5
6
7
8
9
struct Callback {
void operator()(int result) const {
std::cout << "Callback result: " << result << std::endl;
}
};

void process(int x, Callback cb) {
cb(x * 2);
}

使用functional

1
2
3
4
5
6
7
8
9
#include <functional>

void process(int x, std::function<void(int)> cb) {
cb(x * 2);
}

int main() {
process(5, [](int v){ std::cout << "Result: " << v << std::endl; });
}

使用Lambda表达式

1
process(5, [](int v){ std::cout << "Lambda result: " << v << std::endl; });

典型应用场景

  1. 排序自定义规则
1
std::sort(v.begin(), v.end(), [](int a, int b){ return a > b; });
  1. 事件驱动(GUI 框架中的按钮点击)
1
button.onClick([](){ std::cout << "Button clicked!" << std::endl; });
  1. 异步操作(如网络 I/O)
1
2
3
asyncRead("file.txt", [](std::string data){
std::cout << "Read content: " << data << std::endl;
});

回调函数的优点

  1. 解耦:模块之间减少依赖。
  2. 灵活性:调用者可以自由指定逻辑。
  3. 代码复用:相同框架代码可以复用在不同业务逻辑上。
  4. 支持异步、事件驱动编程

回调函数的缺点

  1. 可读性问题:回调层层嵌套时(Callback Hell)会让逻辑难以跟踪。
  2. 调试困难:执行时机由外部决定,不容易排查问题。
  3. 生命周期管理复杂:特别是在多线程和异步场景中,可能导致悬空指针或资源未释放。

http://yjmanman.github.io/2025/09/15/回调函数/
作者
玉佳 秦
发布于
2025年9月15日
许可协议