回调函数callback
回调函数(Callback Function)是一种 通过函数指针或函数对象传递,并在特定事件发生时调用的函数。它用于 解耦逻辑,尤其适用于 事件驱动编程、异步操作、信号处理、线程池、多线程编程 等场景。
1. C语言方式
1.1 函数指针方式
在 C 语言中,回调函数通常是 通过函数指针传递,然后在需要的时候调用。
#include <stdio.h>
// 定义回调函数类型
typedef void (*CallBack_name)(int, const char *str);
// 回调函数的实现
void myCallbackFunc(int value, const char *info) {
printf("回调函数被调用,值: %d, info: %s\n", value, info);
}
// 一个接受回调函数的函数
void processData(int data, CallBack_name callback) {
printf("处理数据: %d\n", data);
callback(data, "process done!"); // 触发回调
}
int main() {
processData(42, myCallbackFunc); // 传入回调函数
return 0;
}
这里解释一下typedef void (*CallBack_name)(int);
的用法:
typedef void (*CallBack_name)(int, const char *str);
//是 C 语言 和 C++ 中 定义函数指针类型 的一种方式。它的作用是 定义一个新的类型 CallBack_name,该类型表示指向一个接受 int 参数并返回 void 的函数的指针。
// 1. void 表示函数的返回类型;
// 2. (*CallBack_name) 表示函数指针(CallBack_name 表示为函数指针的名称);
// 3. (int, const char *str) 表示函数的参数列表;
// 4. typedef 表示为这个复杂的类型起一个别名;相当于为函数指针: void (*CallBack_func)(int, const char *str); 起了一个别名CallBack_name,后续可以直接使用CallBack_name,就像使用普通类型那样。
// 若不使用typedef,则前面的代码与下面的代码等价:
#include <stdio.h>
void myCallbackFunc(int value, const char *info) {
printf("回调函数被调用,值: %d, info: %s\n", value, info);
}
void processData(int data, void (*func)(int value, const char *info)) {
printf("处理数据: %d\n", data);
func(data, "process done!");
}
int main() {
processData(42, myCallbackFunc);
return 0;
}
// 这样写可读性比较差,所以 typedef 可以 简化 代码,使代码更清晰易读。
// 代码更清晰,减少了冗长的函数指针写法。
// 可以像使用普通类型一样使用函数指针。
// 在 struct 或 class 里更方便使用。
更丰富一些的用法:
#include <stdio.h>
typedef int (*setInfoCB_t)(int, const char *);
int setInfoCbFunc(int age, const char *name) {
printf("callback: age: %d, name: %s\n", age, name);
return 10;
}
void processInfo(int age, setInfoCB_t callback) {
printf("get info: %d\n", age);
printf("callback ret = %d \n", callback(age * 2, "Rekko"));
}
int main() {
setInfoCB_t mInfoCb = NULL;
mInfoCb = setInfoCbFunc;
processInfo(12, mInfoCb);
return 0;
}
2. C++方式
2.1 函数指针方式
在 C++11 及以上版本,可以用 using
替代 typedef
来声明函数指针,写法更加直观:
如:using setInfoCB_t = int (*)(int, const char *);
#include <stdio.h>
using setInfoCB_t = int (*)(int, const char *);
int setInfoCbFunc(int age, const char *name) {
printf("callback: age: %d, name: %s\n", age, name);
return 10;
}
void processInfo(int age, setInfoCB_t callback) {
printf("get info: %d\n", age);
printf("callback ret = %d \n", callback(age * 2, "Rekko"));
}
int main() {
setInfoCB_t mInfoCb = nullptr;
mInfoCb = setInfoCbFunc;
processInfo(12, mInfoCb);
return 0;
}
2.2 std::function 方式
在 C++ 中,我们可以使用 std::function
作为回调函数的类型,它比传统的函数指针更灵活,可以接收 普通函数、Lambda 表达式、成员函数、仿函数等。
如:using setInfoCB_t = std::function<int(int, const char *)>;
#include <iostream>
#include <functional> // 引入std::function
using setInfoCB_t = std::function<int(int, const char *)>;
int setInfoCbFunc(int age, const char *name) {
std::cout << "callback: age: " << age << ", name: " << name << std::endl;
return 10;
}
void processInfo(int age, setInfoCB_t callback) {
std::cout << "get info: " << age << std::endl;
int ret = callback(age * 2, "Rekko");
std::cout << "callback ret = " << ret << std::endl;
}
#if 0 // 普通函数
int main() {
setInfoCB_t mInfoCb = nullptr;
mInfoCb = setInfoCbFunc;
processInfo(12, mInfoCb);
return 0;
}
#endif
#if 1 // Lambda表达式
int main() {
processInfo(12, [](int age, const char *name) {
std::cout << "Lambda callback: age: " << age << ", name: " << name << std::endl;
return 1;
});
return 0;
}
// or
//int main() {
// setInfoCB_t mInfoCb = nullptr;
// mInfoCb = [](int age, const char *name) {
// std::cout << "Lambda callback: age: " << age << ", name: " << name << std::endl;
// return 1;
// };
//
// processInfo(12, mInfoCb);
// return 0;
//}
#endif
2.3 C++成员函数作为回调
C++ 成员函数不能直接作为普通回调函数传递,因为它们有一个 隐式的 this
指针,需要使用 std::bind
或 Lambda 转换。
示例:使用 std::bind
传递成员函数
#include <iostream>
#include <functional>
class Processor {
public:
void memberCallback(int value) {
std::cout << "成员函数回调被调用,值: " << value << std::endl;
}
void run() {
// 绑定成员函数作为回调
processData(77, std::bind(&Processor::memberCallback, this, std::placeholders::_1));
}
private:
using Callback = std::function<void(int)>;
void processData(int data, Callback callback) {
std::cout << "处理数据: " << data << std::endl;
callback(data); // 调用回调
}
};
int main() {
Processor p;
p.run();
return 0;
}
2.4 C++仿函数(函数对象)作为回调
仿函数(Functors)是 重载 operator()
的类对象,可以像函数一样调用,并可以存储状态。
#include <iostream>
#include <functional>
// 定义仿函数
class FunctorCallback {
public:
void operator()(int value) const {
std::cout << "仿函数回调被调用,值: " << value << std::endl;
}
};
// 处理数据并调用回调
void processData(int data, std::function<void(int)> callback) {
std::cout << "处理数据: " << data << std::endl;
callback(data);
}
int main() {
FunctorCallback functor;
processData(55, functor); // 传递仿函数作为回调
return 0;
}
总结
方式 | 适用场景 | 特点 |
---|---|---|
C 函数指针 | 纯 C 代码、简单回调 | 轻量级,但不支持成员函数 |
std::function | C++ 回调函数 | 更灵活,支持 Lambda、成员函数、仿函数 |
成员函数回调 | 面向对象编程 | 需要 std::bind 或 Lambda 适配 |
仿函数 | 需要状态的回调 | 可存储状态,复用性强 |
Lambda | 一次性回调,简洁 | 适用于小型回调函数 |
回调函数是一种强大的编程技巧,在异步编程、事件驱动、网络编程、GUI 交互等场景中广泛应用。C++11 及更高版本中,std::function
和 std::bind
让回调更加灵活。