函数指针详解
什么是函数指针
函数指针是指向函数地址的指针变量。与普通指针存储变量地址不同,函数指针存储的是函数在内存中的地址。
cpp
// 普通指针:存储变量地址
int a = 10;
int* p = &a;
// 函数指针:存储函数地址
void test() { std::cout << "hello" << std::endl; }
void (*p)() = test; // p存储test函数的地址
为什么需要函数指针
函数指针的核心价值是让函数像变量一样被传递,实现运行时动态选择执行的函数。
cpp
void A() {}
void B() {}
void run(void (*f)()) {
f(); // 执行传入的函数
}
run(A); // 执行A
run(B); // 执行B
这是工厂模式、策略模式等多种设计模式的基础。
直观理解
- 普通变量:存储数据
- 函数指针:存储行为(操作步骤)
核心区别:
数据指针指向数据,函数指针指向行为
应用场景
函数指针可以像数据一样存储在各种容器中:
map:实现注册模式(如插件系统)vector:存储多个函数- 数组:实现简单的命令分发
语法
基本形式
cpp
int add(int a, int b) { return a + b; }
// 函数指针定义
int (*p)(int, int) = add;
// 调用
int result = p(2, 3);
简化写法(typedef/using)
cpp
// 传统写法
typedef int (*FuncType)(int, int);
// C++11+ 现代写法
using FuncType = int(*)(int, int);
FuncType p = add;
无参数/无返回值
cpp
void hello() { std::cout << "Hello" << std::endl; }
void (*fptr)() = hello;
fptr();
作为参数
cpp
void execute(void (*func)()) {
func();
}
execute(hello);
作为返回值
推荐写法(使用typedef/using简化):
cpp
using FuncType = int(*)(int, int);
FuncType getFunc() {
return add;
}
// 1. 调用getFunc函数,获取add函数的指针
FuncType p = getFunc();
// 2. 调用add函数
int result = p(1, 2);
形式总结
| 场景 | 形式 | 示例 |
|---|---|---|
| 指针变量 | 返回类型 (*指针名)(参数列表) |
int (*p)(int, int) = add; |
| typedef/using | typedef 返回类型 (*类型名)(参数列表) |
typedef int(*FuncType)(int, int); |
| 作为参数 | void f(返回类型 (*param)(参数列表)) |
void run(int (*func)(int, int)) |
| 作为返回值 | typedef/using类型名 f() |
FuncType getFunc() { return add; } |
关键规律 :(*名字) 必须用括号包起来,否则编译器会认为是函数声明。
本质
函数指针的本质是把函数当成"任务"传递:
cpp
void life(void (*f)()) {
f(); // 执行传入的任务
}
void eat() { std::cout << "吃饭" << std::endl; }
life(eat); // 传递"吃饭"任务
简单来说:
普通参数传数据,函数指针传动作
实际应用
你可能已经在使用函数指针的概念,只是换了个名字:
- 虚函数
std::function- Lambda表达式
- 回调函数
这些底层都基于函数指针的思想。
复杂声明解析
对于复杂的函数指针声明:
cpp
Plugin* (*FactoryFunc)();
解析:FactoryFunc 是一个返回 Plugin* 且无参数的函数指针。
总结
函数指针是C++中强大的特性,它允许我们:
- 动态选择执行的函数
- 实现回调机制
- 构建灵活的设计模式
- 提高代码的模块化和可扩展性
核心理解:普通指针指向数据,函数指针指向代码。