细致的讲,如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
eg:
int (*p)(int,int);
这个语句就定义了一个指向函数的指针变量 p。首先它是一个指针变量,所以要有一个“”,即(p);其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。p 的类型为 int(*)(int,int)。
那么这个函数指针的类型是什么?
把变量名去掉,就可以得到函数指针的类型:
int (*)(int,int);
赋值:
int func1(int a,int b){return a>b?a:b;} p=func1; p=(&func1);//取址符号是可选的
在普通的指针变量赋值时,如上面所示,需要加取地址符号,而这里却是可选的?这是由于要同时考虑到两个因素(1)避免二义性(2)形式一致性。在普通指针赋值,需要加取地址符号是为了区别于将地址还是将内容赋给指针。而在函数赋值时没有这种考虑,因为这里的语义是清晰的,加上&符号是为了和普通指针变量一致---“因为一致的时候就不容易出错”。
使用:
p(0,20); (*p)(0,20);
上面这两种使用函数指针调用函数的方式都是可以的,原因和上面一样。
格式如下:
typedef char (*pt)(int);
这里是把定义了一个别名叫(*p)(int)吗,显然不对,其含义是:
要定义的类型是void (*)(int),即参数一个int,什么也不返回的函数指针,定义的别名是p
使用:
pt p; p=max; p(a);
#include<iostream> using namespace std; typedef int (*pf)(int,int); //此种方式最容易理解,定义了一个函数指针类型;函数名就是指针。 int f(pf p,int a,int b) { return p(a,b); } int add(int a,int b) { return a+b; } int main(){ cout<<f(add,1,2)<<endl;//3 }
for_each用的就是这种方法
template<typename _InputIterator, typename _Function> _Function for_each(_InputIterator __first, _InputIterator __last, _Function __f) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) __glibcxx_requires_valid_range(__first, __last); for (; __first != __last; ++__first) __f(*__first); return __f; // N.B. [alg.foreach] says std::move(f) but it's redundant. }
上面的_f既可以传入函数,也可以传入仿函数_