函数指针详解
来源:互联网 发布:云尚数据 编辑:程序博客网 时间:2024/06/06 12:45
选自《C++ Primer Plus(第六版)》
与数据项类似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。
1.函数指针的基础知识
首先通过一个例子来阐述这一过程。假设要设计一个名为estimate()的函数,估算编写指定行数的代码所需的时间,并且希望不同的程序员都将使用该函数。对于所有的用户来说,estimate()中一部分代码都是相同的,但该函数允许每个程序员提供自己的算法来估算时间。为了实现这种目标,采用的机制是,将程序员要使用的算法函数的地址传递给estimate()。为此,必须能够完成下面的工作:
- 获取一个函数的地址;
- 声明一个函数指针;
- 使用函数指针来调用函数
1.获取函数的地址
获取函数的地址很简单:只要使用函数名(后面不跟参数)即可。注意传递的是函数地址还是函数的返回值,假如think()是一个函数,那么有:
process(think); //passes address of think() to processthought(think()); //passes return value of think() to thought
2.声明函数的指针
声明函数指针时,必须要指定函数的返回类型以及函数的特征标(参数列表)。例如:
double pam(int); //prototype
则正确的指针类型声明如下:
double (*pf)(int); //pf points to function that takes one int //argument and that returns type doublepf=pam; //pf now points to the pam() function
这时pf就是函数指针,(*pf)就是函数。注意pam()的特征标和返回类型必须与pf相同。
ps:区分函数指针和返回指针的函数:
因为括号的优先级比*运算符高,因此*pf(int)意味着pf()是一个返回指针的函数,而(*pf)(int)意味着pf是一个指向函数的指针。
double (*pf)(int); //pf points to a function that returns doubledouble *pf(int); //pf() a function that returns a pointer-to-double
3.使用函数指针来调用函数
这步比较简单,如下:
double pam(int); double (*pf)(int);pf=pam; //pf now points to the pam() function double x=pam(4); //call pam() using the function namedouble y=(*pf)(5); //call pam() using the pointer pf
实际上,C++也允许像使用函数名那样使用of:
double y=pf(5); //also call pam() using the pointer pf
第一种格式虽然不太好看,但它给出了强有力的提示——代码正在使用函数指针。
2.函数指针示例
程序清单:
#include<iostream>double betsy(int);double pam(int);void estimate(int lines,double (*pf)(int));int main(){ using namespace std; int code; cout<<"How many lines of code do you need? "; cin>>code; cout<<"Here's Betsy's estimate:\n"; estimate(code,betsy); cout<<"Here's Pam's estimate:\n"; estimate(code,pam);}double betsy(int lns){ return 0.05*lns;}double pam(int lns){ return 0.03*lns+0.0004*lns*lns;}void estimate(int lines,double (*pf)(int)){ using namespace std; cout<<lines<<" lines will take: "; cout<<(*pf)(lines)<<" hour(s)\n";}
简要解释:该程序两次调用estimate()函数,一次传递betsy()函数的地址,另一次传递pam()函数的地址。
运行结果:
3.深入探讨函数指针
const double* f1(const double ar[],int n);const double* f2(const double [],int);const double* f3(const double *,int);//这些函数实际上是相同的const double* (*p1)(const double *,int);//可在声明的同时进行初始化:const double* (*p1)(const double *,int)=f1;//使用C++11的自动类型推断功能,代码要简单的多auto p2=f2; //C++11 automatic type deductioncout<<(*p1)(av,3)<<": "<<*(*p1)(av,3)<<endl;cout<<p2(av,3)<<": "<<*p2(av,3)<<endl;
根据前面讲的,(*p1)(av,3)和p2(av,3)都调用指向的函数(这里为函数f1()和f2()),并将av和3作为参数。因此,显示的是这两个函数的返回值。返回值的类型为const double*(即double值的地址),因此在每条cout语句中,前半部分显示的是一个double值的地址;为了查看存储在这些地址处的实际值,需要将运算符*应用于这些地址,如表达式*(*p1)(av,3)和*p2(av,3)。
鉴于需要使用三个函数,如果有一个函数指针数组将很方便。这样,将可使用for循环通过指针一次调用每个函数。声明方法如下(包括初始化):
const double* (*pa[3])(const double *,int)={f1,f2,f3};
ps:因为运算符[]的优先级高于*,所以这里pa是一个包含三个指针的数组,其中每个指针都指向这样的函数,即将const double*和int作为参数,并返回一个const double *
这里不能用auto。自动类型推断只能用于单值初始化,而不能用于初始化列表。
//调用函数的两种写法const double * px=pa[0](av,3);const double * py=(*pa[1])(av,3);//获得指向的double值,可使用运算符*double x=*pa[0](av,3);double y=*(*pa[1])(av,3);
区分指向数组的指针和函数指针数组:
*pd[3]; //an array of 3 pointers(*pd)[3]; // a pointer to an array of 3 elements
这样就会使指针的使用显得非常恐怖,关于的指针的特性还有待进一步的了解。