回调函数预备知识
在深入理解回调函数之前,我们需要先掌握一个基础概念:函数指针。C 语言的灵魂是指针,我们常接触整型、字符或结构体指针,但函数指针指向的是代码本身。
什么是函数指针
函数指针也是指针,但它存储的不是变量的地址,而是函数的入口地址。定义语法如下:
返回类型 (*指针变量名)(参数类型列表);
- 返回类型:被指向函数的返回值类型(如
int,void等)。 - 指针变量名:自定义的名称。
- 参数类型列表:函数接受的参数类型。
这里有个关键点:括号不能省略。(*p) 的优先级高于 *,如果写成 return_type *p(args),编译器会将其解析为'返回值为指针的函数声明',而非函数指针。
为了方便使用,通常配合 typedef 定义别名:
// 定义一个函数指针类型 Fun1,指向返回 int、接受一个 int 参数的函数
typedef int (*Fun1)(int);
// 定义一个函数指针类型 Fun2,指向返回 void、无参数的函数
typedef void (*Fun2)(void);
如何调用函数指针
赋值时,函数名本身就代表地址,无需加 &。调用时直接像普通函数一样使用即可。
int Func(int x) { return x * 2; }
int main() {
// 定义并初始化函数指针
int (*p)(int) = Func;
// 通过指针调用
int result = p(5); // 等价于 Func(5)
return 0;
}
函数指针作为参数和返回值
函数指针可以作为参数传递给其他函数,也可以作为函数的返回值。这在实现通用逻辑时非常有用。
#include <iostream>
using namespace std;
// 定义操作类型别名
typedef int (*Operation)(int, int);
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
// 接收函数指针作为参数
void calculate(int x, int y, Operation op) {
cout << "Result: " << op(x, y) << endl;
}
int main() {
calculate(10, 5, add); // 输出 Result: 15
calculate(10, 5, sub); // 输出 Result: 5
return 0;
}
此外,函数指针数组允许我们将多个函数组织在一起管理:
// 方法 1:直接定义
void (*func_array_1[5])(int, int, float);
// 方法 2:使用 typedef 简化
typedef void (*p_func_array)(int, int, float);
p_func_array func_array_2[5];
回调函数
什么是回调函数
回调函数本质上就是通过函数指针调用的函数。当你把函数的地址作为参数传给另一个函数,并在特定事件发生时由该函数调用这个地址指向的代码,这就构成了回调。
简单来说,就是把一段可执行的代码像参数一样传递出去,等待某个时刻被触发执行。如果立即执行是同步回调,稍后执行则是异步回调。
为什么要用回调函数
回调的核心价值在于解耦。调用者不需要知道具体是谁在执行任务,只需要约定好接口原型。这使得库函数可以处理通用逻辑,而将具体细节交给用户自定义的回调函数。
例如,标准库中的排序函数无法预知你要排序的对象结构,它可以通过回调函数让用户传入比较规则,从而实现灵活的排序策略。
实战示例
下面是一个完整的回调函数应用案例,展示了如何通过函数指针实现动态运算选择:
#include <iostream>
using namespace std;
// 定义操作函数指针类型
typedef float (*Operation)(float, float);
// 加法回调
float ADD(float a, float b) {
cout << "a+b=" << a + b << endl;
return a + b;
}
// 减法回调
float SUB(float a, float b) {
cout << "a-b=" << a - b << endl;
return a - b;
}
// 乘法回调
float MUL(float a, float b) {
cout << "a*b=" << a * b << endl;
return a * b;
}
// 除法回调
float DIV(float a, float b) {
if (b == 0) {
printf("Error: Division by zero!\n");
return 0;
}
cout << "a/b=" << a / b << endl;
return a / b;
}
// 通用处理函数,接收回调函数指针
float add_sub_mul_div(float a, float b, Operation op) {
return op(a, b);
}
int main() {
// 动态切换运算方式
add_sub_mul_div(1.1, 2.2, ADD);
add_sub_mul_div(1.1, 2.2, SUB);
add_sub_mul_div(1.1, 2.2, MUL);
add_sub_mul_div(1.1, 2.2, DIV);
return 0;
}
在这个例子中,add_sub_mul_div 并不关心具体做什么运算,它只负责调用传入的 op 指针。主程序通过传入不同的函数名(即函数地址),实现了运行时的行为切换。
总结
回调函数是 C/C++ 中实现灵活架构的重要工具。通过函数指针,我们可以将控制流反转,让底层库函数主动调用上层业务逻辑。掌握这一机制,对于理解事件驱动模型、GUI 编程以及各类框架设计都至关重要。


