📌 参考C++ primer 6.7
A function pointer is just that—a pointer that denotes a function rather than an object.
- a function pointer points to a particular type.
- A function’s type is determined by its return type and the types of its parameters. The function’s name is not part of its type. 函数的类型,由返回值类型和参数类型决定,名称不起作用,这也是函数重载能成功的原因。
声明和初始化
// 函数指针的声明, pf as a pointer to function bool(const string &, const string &)
// (*pf)是整体,bool(const string &, const string &)是整体
bool (*pf)(const string &, const string &);
// 函数的声明, 该函数的类型为bool(const string &, const string &)
bool lengthCompare(const string &, const string &);
函数指针的声明特别容易与返回指针类型的函数的声明混淆,如下:
// 不是函数指针的声明,而是一个返回指向bool类型指针的函数
// pf(const string &, const string &) as a pointer to bool
// pf(const string &, const string &) 是整体
bool *pf(const string &, const string &);
所以,不要忘记那对括号。
当使用函数名称作为一个value,其自动转化为一个pointer。
// 两种初始化方式等价,&是可选的。
pf = lengthCompare;
pf = &lengthCompare;
// 可以使用空指针初始化,意味着该函数指针未指向任何函数
pf = 0;
pf = nullptr;
// 函数指针声明的类型,必须与用于初始化的函数类型相同
int sumLength(const string &, const string &);
bool cstringCompare(const char *, const char *);
pf = sumLength; // error, 返回值类型不匹配
pf = cstringCompare; // error, 参数类型不匹配
函数指针的使用
基本使用
我们可以使用指向一个函数的指针,调用这个函数。
bool b1 = lengthCompare("hello", "world");
bool b1 = pf("hello", "world");
bool b1 = (*pf)("hello", "world");
// 三种方式等价,*也是可选的
当调用重载函数时,compiler会根据函数指针中声明的类型,选择对应的重载函数之一进行调用,不要忘记,函数的类型由返回值类型和参数类型决定。
函数指针作为参数
函数中也不能定义函数类型(function type
)作为参数,而是需要使用pointer to function
, 和数组的方式有点像。
在函数中如果要传递函数类型的参数,使用如下方式:
// 两者的声明等价,
// 一个隐式转为pointer to function
void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));
// 一个显式定义为pointer to function
void useBigger(const string &s1, const string &s2, bool (*pf)(const string &, const string &));
// 使用如下
userBigger(s1, s2, lengthCompare);
其中,当传递的参数为function type时,编译器会自动将其转为pointer to function. 这两种类型的区别,可以通过一个小例子查看:
bool lengthCompare(const string &, const string &);
int main(int argc, char const *argv[])
{
bool (*pf)(const string &, const string &);
pf = lengthCompare;
cout << typeid(pf).name() << endl;
using F = bool(const string &, const string &);
F f;
cout << typeid(f).name() << endl;
return 0;
}
bool lengthCompare(const string &s1, const string &s2){
return true;
}
// 输出:
// PF: pointer to function
// PFbRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEES7_E
// F: function
// FbRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEES7_E
之前提过,C++中的类型过于复杂会导致问题,这里函数指针就遇到了这个问题,因此可以使用类型别名进行替代。在这里需要注意function type
和pointer to function
两种类型的区别。
// Func and Func2 have function type
typedef bool Func(const string&, const string&);
typedef decltype(lengthCompare) Func2; // equivalent type
// FuncP and FuncP2 have pointer to function type
typedef bool( *FuncP)(const string&, const string&);
typedef decltype(lengthCompare) *FuncP2; // equivalent type
- Func和Func2均为function type;
- FuncP和FuncP2均为pointer to function type;
当作为函数的参数传递时,这两种方式均可以:
// 两者声明等价
// 编译器自动将function type转为pointer to function
void useBigger(const string&, const string&, Func);
// 直接传递pointer to type
void useBigger(const string&, const string&, FuncP2);
函数指针作为返回值
- 函数指针还可以作为返回值,但是仍然不能返回函数类型,而是需要使用pointer to function.
- 编译器不会自动将函数类型转为指针类型,需要显式给出;注意,这一点与将函数类型作为参数传递不同(那里会自动转为指针类型)。
// F是function type
using F = int(int*, int);
// PF是pointer type
using PF = int(*)(int*, int);
// ok, return pointer to function
PF f1(int);
// error, return function type
F f1(int);
// ok, return pointer to function
F *f1(int)
// 可以使用auto + trailing return 简写
auto f1(int) -> int ( * )(int * , int);
推导函数指针类型
这里的pointer to function 和 function type各种写法混在一起,非常容易出错,无法理解。因此,可以使用decltype
等来推导,如下:
string::size_type sumLength(const string&, const string&);
string::size_type largerLength(const string&, const string&);
decltype(sumLength) *getFcn(const string &);
这里需要注意的是:当对函数使用decltype时,返回的是function type
,不是 pointer to function
, 因此在getFcn
前的*
千万不能忘记。