引言
函数指针指向的是函数而不是对象。函数指针指向某种特定类型,就像我们可以定义指向int变量的指针,指向char变量的指针以及指向string变量的指针,函数指针指向的这种特定类型由函数的返回类型和形参类型共同决定,而与函数名无关。
例如有一个函数
compare
声明如下:
bool compare(const string &, const string &);
若要定义指向该函数的指针,那么应该像这样:
bool (*pf)(const string &,const string &);
依然遵循由内而外的原则阅读声明:
- 首先
(*pf)
表明变量
pf
是指针类型;
- 而后面的
(const string &,const string &)
是形参列表,表明指针
pf
指向一个函数,该函数的形参列表如上;
- 最后,最左边的
bool
表明这个函数的返回类型是
bool
。
Note:
bool *pf(const string &,const string &);
对比上面的这个声明和上上个声明,差别在
(*pf)
和
*pf
上。
(*pf)
指明
pf
是指针类型,而
*pf
对应的那条声明指明
pf
是个函数,函数的返回类型是
bool *
。因此,声明指向函数的指针时,
(*pf)
两端的括号必不可少,至于差别大家也看到了。
使用函数指针
当我们把函数名作为一个值使用时,该函数自动转换成指针。例如对上面的
compare
函数和函数指针
pf
,若要使
pf
指向
compare
函数,我们有:
pf = compare; //函数名自动转换为指针pf = &compare; //等价的赋值,&可选。pf = 0; //表明pf不指向任何函数pf = nullptr; //与上句等价
并且,我们能够直接使用指向函数的指针调用该函数,不一定非要解引用指针。例如:
bool b1 = pf("你好", "Fuck!"); //直接使用指向函数的指针调用函数bool b2 = (*pf)("你好", "Fuck!"); //等价的调用。先解引用指针,再调用函数。bool b2 = *pf("你好", "Fuck!"); //错误的调用。函数调用运算符()的优先级高于解引用运算符*的优先级。/*bool b2 = *pf("你好", "Fuck!");//等价于以下两条语句:bool tmp = pf("你好", "Fuck!"); //即调用pf指向的函数。bool b2 = *tmp; //对tmp解引用。显然错误,因为不能对bool类型解引用//如果compare函数返回char *类型,则语句bool b2 = *pf("你好", "Fuck!");反而正确*/bool b3 = compare("你好", "Fuck!"); ////等价的调用。直接使用函数。
我们再来加深下对函数指针指向的类型的理解:假设有三个函数声明如下:
bool compare1(const string &, const string &);bool compare2(const string &, const string &);bool compare3(const int &, const int &);
函数指针
pf
如下:
bool (*pf) (const string &, const string &);pf = compare1; //正确pf = compare2; //正确pf = compare3; //错误,形参不匹配
(重载函数)的指针
考虑重载的函数:
void f(int *);void f(int);void (*pf) (int) = f; //pf指向void f(int);
编译器通过指针类型决定指向哪个重载函数,指针类型必须与重载函数中的某一个精确匹配(返回类型和形参列表精确匹配)。
将函数指针作为形参
就如我们不能定义数组类型的形参一样,我们不能定义函数类型的形参,但是形参可以是指向函数的指针。形参看起来是函数类型,实际上当成指针使用。例如:
//第三个形参是函数类型,但会自动转换为指向函数的指针。即,pf是指向函数的指针。void f(const string &s1, const string &s2, bool pf(const string &, const string &));//等价的声明,显式地将形参定义为指向函数的指针。void f(const string &s1, const string &s2, bool (*pf)(const string &, const string &));
直接把函数作为实参时,会自动转换为指针。
//自动将函数compare转换为指向该函数的指针。f("你好", "Fuck", compare);
将指向函数的指针作为返回类型
就如我们不能在函数中返回数组类型一样,我们不能直接返回函数类型,但可以返回指向函数的指针。以下声明一个返回函数指针的函数:
int (*f(int)) (int *, int);
从内而外阅读声明,首先
*f(int)
表明
f
是函数,参数是
int
,返回指针类型。
(int *, int)
表明指针指向函数一个,且参数列表为
(int *, int)
,最左边的int表明指向的该函数返回
int
。
亦可以使用尾置返回类型的方式:
auto f(int) -> int (*) (int*, int);
该声明与上一条声明等价。
将decltype用于函数指针类型
如果我们明确知道返回的函数是哪一个,就能使用
decltype
简化书写函数指针。
decltype(compare) *p; //p是一个指向compare函数对应类型(只是返回类型和形参,函数名不属于类型的一部分)的指针类型decltype(compare) * f(); //函数声明,f是一个函数,没有形参,返回类型为指向compare函数对应类型(只是返回类型和形参,函数名不属于类型的一部分)的函数指针类型
Note:
将
decltype
作用于某个函数时,返回函数类型而不是指针类型,需要显式加上
*
表明我们需要指针类型。
声明:c++ Basic是对《C++ Primer 第五版》的个人总结与疑难解释,主要用于个人日后复习。如果想要深入了解更多,请支持正版。