既然说到了函数指针,我们先说说指针。指针其实就是存放对象的内存地址单元。在c语言中,指针的重要性是不言而喻的,不过指针引发的错误也很悲壮,用编程专家们的话说,再有经验的c程序员也可以在使用指针事出问题。虽然在c++中很多地方为了提高效率和避免出错用引用去代替指针,但是他们的区别还是很大的。
1.引用在定义的时候必须初始化,而指针先定义时可以不初始化。2.引用不可以为空,而指针可以为空NULL。3.引用一当被初始化,后面就不可以再被修改指向别的对象,而指针可以任意修改。其实引用是通过指针来实现的,只是这些都是编译器完成的。
函数说白了其实就是一系列指令的组合。编译器会为函数在内存中分配一块连续的存储区域,这块存储区域单元的首地址就是函数的入口地址,在编程时用函数名来标识。加入我们定义了一个变量用于存放函数首地址的指针,那么此指针变量就是指向函数的指针。
函数指针的定义形式是这样的:函数返回值类型 (*指针变量名)(形参);这样在使用的时候很麻烦,每次用都需要这样写(*指针变量名)(实参),为了方便使用,我们使用typedef定义同义词,typedef 函数返回值类型 (*指针变量名) (形参),以后使用这种函数指针类型时,就可以直接使用指针变量名定义变量了。ps:那个括号是必须的,否则就变成了函数的返回值类型的指针了。它主要有三个用处:调用函数、作为函数的参数和转换表。
首先看看typedef定义的简化好处:
#include <iostream>
using namespace std;
int test_return(int);
int test_return_add(int);
int main() {
//不使用typedef
int (*p_f_return)(int); //声明函数指针变量p_f_return
p_f_return = test_return; //函数指针变量初始化为指向函数test_return的入口地址
int (*p_f_return_add)(int); //声明函数指针变量时又将函数声明重复了一遍
p_f_return_add = test_return_add;
//使用typedef时
typedef int (*func_ptr)(int); //定义函数指针的同义词func_ptr,以后直接使用同义词定义函数指针变量
func_ptr p_f_return = test_return;
func_ptr p_f_return_add = test_return_add;
system("pause");
return 0;
}
int test_return(int i) {
return i;
}
int test_return_add(int i) {
return i + 1;
}
一看代码就明白了吧,使用typedef后定义函数指针变量简单的多了。
看看使用函数指针如何调用函数
#include <iostream>
using namespace std;
int test_return(int);
int main() {
//使用typedef时
typedef int (*func_ptr)(int); //定义函数指针的同义词func_ptr,以后直接使用同义词定义函数指针变量
func_ptr p_f_return = test_return;
//使用函数指针调用函数
cout << p_f_return(1);
system("pause");
return 0;
}
int test_return(int i) {
return i;
}
呵呵,这样使用起来和函数一模一样了,很舒服吧。
继续看看函数指针作为参数的情况,此时调用函数时需要传递一个函数指针实参,回调函数就是这种原理。
#include <iostream>
using namespace std;
int test_return(int (*)(int), int);
int test_param(int);
int main() {
typedef int (*func_ptr)(int); //定义函数指针的同义词func_ptr,以后直接使用同义词定义函数指针变量
func_ptr p_f_param = test_param;
//调用函数时,传递函数地址
cout << test_return(p_f_param, 2);
system("pause");
return 0;
}
//函数指针作为形参
int test_return(int (*p_f_param)(int), int i) {
return (*p_f_param)(i);
}
int test_param(int i) {
return i;
}
最后看看转换表的情形,比如一个计算器的程序,传入两个操作数和一个操作符,类似于下面的代码
switch (oper)
{
case ADD:
result = add(op1, op2);
break;
case SUB:
result = sub(op1, op2);
break;
case MUL:
result = mul(op1, op2);
break;
case DIV:
result = div(op1, op2);
break;
}
这样有很大的不好,假设操作符很多,岂不是要写很长。这时候将所有的操作放到一个函数指针数组中去,这样直接选择正确的函数指针就能执行相应的函数了。如下代码
#include <iostream>
using namespace std;
double add(double, double);
double sub(double, double);
double mul(double, double);
double div(double, double);
//函数指针数组,保存所有的操作函数
double (*oper_func[])(double, double) = {add, sub, mul, div};
int main() {
//测试add方法
double result = oper_func[0](1.0, 2.0);
cout << result;
system("pause");
return 0;
}
double add(double d1, double d2) {
return d1 + d2;
}
double sub(double d1, double d2) {
return d1 - d2;
}
double mul(double d1, double d2) {
return d1 * d2;
}
double div(double d1, double d2) {
return d1 / d2;
}
转换表的那块来自《c和指针》。函数指针用的最多的就是回调函数了,Windows系统的消息机制大量使用了回调。函数指针的用途较广,还是需要好好理解下。