两方面用途:
- 函数调用
- 作为函数参数进行传递
1 | const double * (*pf[3])(const double *, int) = {f1, f2, f3} |
函数指针
函数指针:指向函数地址的指针变量。 在C++编译时,每一个函数都有一个入口地址,该地址是存储函数机器语言代码的内存的开始地址。函数指针主要有两方面的用途:调用函数和用作函数参数。函数指针的声明方法如下所示:
1 | double pam(int); |
从上面的语句可以看出,C++同时允许使用带星号和不带星号的函数指针,最神奇的是效果居然是等价的(对于给函数指针赋值时,函数名带取址符和不带取址符的效果也是等价的!)!
导致以上“神奇事情”发生的原因是,在C++指定函数指针标准时,出现了两种不同的声音:一种学派认为,由于pf
是函数指针,而*pf
是函数,因此应将(*pf)()
用作函数调用。另一种学派认为,由于函数名是指向该函数的指针,指向函数的指针的行为应该与函数名相似,因此应将pf()
用作函数调用使用。C++进行了折衷——这两种方式都是正确的,虽然看上去它们在逻辑上是相冲突的。
返回指向函数的指针1
2int (* func(int))(double, double);
// func 具有形参表, 因此它本身是一个参数为 (int) 的函数, 而该函数的返回值则是一个指向 int(double, double) 的函数指针.
下面的声明语句指出了一个函数指针数组,其中每个指针都指向这样的函数:将const double*
和int
作为参数,返回一个const double *
1
const double* (* pa[3]) (const double * , int ) = {f1,f2,f3};
这里不能使用auto
,因为auto
只能用于单值初始化,而不能用于初始化列表,但声明数组pa
后,可以使用auto
:1
auto pb = pa; //
pa和pb都是指向函数指针的指针(数组首地址),使用时可以用下标法,也可以当做指针使用:1
2
3
4
5
6const double *px = pa[0](av,3);
const double *py = (* pa[0])(av,3); //如果带星号,则不能少括号
//要获得值,可使用运算符
double x = *pa[0](av,3); //少了括号以后,会取得返回值地址指向的值
double y = *(* pb[1])(av,3);
如果继续声明了指向函数指针整个数组的指针,则使用方法又有些不同,见下面:1
2
3
4
5
auto pc = &pa; //pc指向pa的地址
*pd[3]; // 相当于 pa[3],代表一个包含三个指针的指针数组
(* pd)[3]; // 代表pc是一个函数指针,指向含3个元素的指针数组
函数对象
函数对象的实质是对运算符()
的重载, 函数对象也叫做仿函数。
1 | class A{ |
函数对象与函数指针的比较
函数对象的优势在于,可以把附加对象保存在函数对象中,也可以存储一些其他的额外信息,甚至可以用来封装类成员函数指针。
但是,函数对象本身并不是指针,因此在使用函数指针的场合中,往往无能为力。例如,不能将对象传给qsort
函数!因为它只接受函数指针。