C++:函数指针


📌 参考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 typepointer 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前的*千万不能忘记。


文章作者: alex Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 alex Li !
  目录