函数指针

函数指针的类型由它的返回值和形参类型共同决定,与函数名无关:

//比较两个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 &);
posted @ 2019-07-25 09:53  CodeWithMe  阅读(212)  评论(0)    收藏  举报