函数指针
函数指针的类型由它的返回值和形参类型共同决定,与函数名无关:
//比较两个string对象的长度 bool lengthCompare(const string&, const string&);
函数的类型是 bool lengthCompare(const string&, const string&)。
要想声明一个可以指向该函数的指针,只需要用指针替换函数名即可:
//pf指向一个函数,该函数的参数是两个const string的引用,返回值是bool类型 bool (*pf)(const string&, const string&);//未初始化
pf 是一个指向函数的指针,其中该函数的参数是两个 const string 的引用,返回值是 bool 类型。
Note:pf 两端的括号必不可少。
不写括号 pf 是一个返回值为 bool 指针的函数:
//声明一个名为pf的函数,该函数返回值 bool* bool* pf(const string&, const string&);
使用函数指针
当把函数名作为一个值使用时,该函数自动转换地转换成指针,将 lengthCompare 的地址赋给 pf :
pf = lengthCompare;//pf指向名为lengthCompare的函数 pf = &lengthCompare;//等价的赋值语句:取地址符是可选的
直接使用指向函数的指针调用该函数,无须提前解引用的指针:
bool b1 = pf("hello", "goodbye");//调用lengthCompare函数 bool b2 = (*pf)("hello", "goodbye");//一个等价的调用 bool b3 = lengthCompare("hello", "goodbye");//另一个等价的调用
在指向不同函数类型的指针间不存在转换规则。
为函数指针赋一个 nullptr 或者值为0的整数常量表达式,表示该指针没有指向任何一个函数:
string::size_type sumLength(const string&, const string&); bool cstringCompare(const char*, const char*); pf = 0;//正确:pf不指向任何函数 pf = sumLength;//错误:返回类型不匹配 pf = cstringCompare;//错误:形参类型不匹配 pf = lengthCompare;//正确:函数和指针的类型精确匹配
重载函数的指针
使用重载函数时,上下文必须清晰地界定到底应该选用哪个函数。
void ff(int*); void ff(unsigned int); void (*pf1)(unsigned int) = ff;//pf1指向ff(unsigned int)
编译器通过指针类型决定选用哪个函数,指针类型必须与重载函数中的某一精确匹配:
void (*pf2)(int) = ff;//错误:没有任何一个ff与该形参列表匹配 double (*pf3)(int*) = ff;//错误:ff和pf3的返回类型不匹配
函数指针形参
形参可以是指向函数的指针,形参看起来是函数类型,实际上却是当成指针使用:
//第三个形参是函数类型,它会自动地转换成指向函数的指针 void useBigger(const string& s1, const string& s2, bool pf(const string&, const string&)); //等价声明:显式地将形参定义成指向函数的指针 void useBigger(const string& s1, const string& s2, bool (*pf)(const string&, const string&));
可以直接把函数作为实参使用,此时它会自动转换成指针:
//自动将函数 lengthCompare 转换成指向该函数的指针 useBigger(s1, s2, lengthCompare);
直接使用函数指针类型显得冗长而烦琐,类型别名和 decltype 能简化使用函数指针的代码:
//Func 和 Func2是函数类型 typedef bool Func(const string&, const string&); typedef decltype(lengthCompare) FuncP2;//等价的类型 //FuncP和FuncP2是指向函数的指针 typedef bool(*FuncP)(const string&, const string&); typedef decltype (lengthCompare)* FuncP2;//等价类型
Func 和 Func2 是函数类型,FuncP 和 FuncP2是指针类型。
decltype 返回函数类型,此时不会将函数类型自动转换成指针类型,只有在结果前面加上 * 才能得到指针。
重新声明 useBigger :
//useBigger 的等价声明,其中使用了类型别名 void useBigger(const string&, const string&, Func); void useBigger(const string&, const string&, FuncP2);
两个声明语句声明的是同一个函数,第一条语句编译器自动地将 Func 表示的函数类型转换成指针。
返回指向函数的指针
必须把返回类型写成指针形式,编译器不会自动地将函数返回类型当成对应的指针处理。
使用类型别名声明一个返回函数指针的函数:
using F=int(int*, int);//F是函数,不是指针 using PF=int(*)(int*, int);//PF是指针类型
使用类型别名将 F 定义成函数类型,将 PF 定义成指向函数类型的指针:
PF f1(int);//正确:PF是指向函数的指针,f1返回指向函数的指针 F f1(int);//错误:F是函数类型,f1不能返回一个函数 F *f1(int);//正确:显式地指向返回类型是指向函数的指针
也能用下面形式直接声明 f1 :
int (*f1(int))(int*, int);
由内向外顺序阅读:f1 有形参列表,所以 f1 是个函数。 f1 前面有 * ,所以 f1 返回一个指针。指针的类型本身也包含形参列表,因此指针指向函数,该函数的返回类型是 int 。
使用尾置返回类型的方式声明一个返回函数指针的函数:
auto f1(int) -> int (*)(int*, int);
将 auto 和 decltype 用于函数指针类型
明确知道返回的函数是哪一个,就能使用 decltype 简化书写函数指针返回类型的过程:
decltype (sumLength) *getFcn(const string &);

浙公网安备 33010602011771号