思维导图
1. 声明函数指针
函数指针指向的是函数而非对象。和其他指针一样,函数指针指向某种特定类型。函数的类型有它的返回类型和形参类型共同决定,与函数名无关。bool (*pf)(const string &, int); // 未初始化pf前面有个*,因此pf是指针;右侧是形参列表(此处有两个形参,一个是const string &型,另一个是int型),表示pf指向的是函数;左侧为返回类型(此处为bool型)。
注意:*pf两端的括号必不可少。如果不写这对括号,则pf是一个返回值为bool指针的函数。
2. 使用函数指针
当我们把函数名作为一个值使用时,该函数自动地转化为指针。
pf = checkLenth; // pf指向名为checkLenth的函数pf = &checkLenth; // 等价的赋值语句:取地址符是可选的
可以直接使用指向函数的指针调用该函数,无须提前解引用指针。
bool b1 = pf(str, lenth); // 调用checkLenth函数bool b2 = (*pf)(str, lenth); // 等价的调用bool b3 = checkLenth(str, lenth); // 等价的调用
在指向不同函数类型的指针间不存在转化规则。通常可以为函数指针赋一个nullptr或者值为0的整型常量表达式,表示该指针没有指向任何一个函数。
/************************main.cpp************************/#include <iostream>#include <string>using std::string;bool checkLenth(const string &str, int lenth){if (str.length() != lenth){return false;}return true;}bool checkStr(const string &str1, const string &str2){if (str1.length() != str2.length()){return false;}return true;}int main(int argc, char *argv[]){bool(*pf1) (const string &, int); // 声明一个函数指针,未初始化bool(*pf2) (const string &, int) = nullptr; // 声明一个函数指针,并初始化,表示未指向任何一个函数string str = "hello world!";int lenth = 12;pf1 = checkLenth;// pf1 = &checkLenth; // 等价的赋值语句:取地址符是可选的// pf2 = checkStr; // 错误,形参类型不匹配,不同函数类型的指针间不存在转换规则bool b1 = pf1(str, lenth); // 调用checkLenth函数bool b2 = (*pf1)(str, lenth); // 等价的调用bool b3 = checkLenth(str, lenth); // 等价的调用system("pause");}
3. 重载函数的指针
当使用重载函数时,上下文必须清晰地界定到底应该选用那个函数。
/************************main.cpp************************/#include <iostream>#include <string>using std::string;bool checkStr(const string &str1, const string &str2){if (str1.length() != str2.length()){return false;}return true;}// 重载函数bool checkStr(const string &str1, const string &str2, int lenth){if (str1.length() != lenth|| str2.length() != lenth){return false;}return true;}int main(int argc, char *argv[]){using std::cout;using std::endl;bool(*pf1) (const string &, int) = nullptr; // 声明一个函数指针void(*pf2) (const string &, const string &) = nullptr; // 声明一个函数指针bool(*pf3) (const string &, const string &, int) = nullptr; // 声明一个函数指针string str1 = "hello world!";string str2 = "hell0 c++pri";int lenth = 11;// pf1 = checkStr; // 错误,没有任何一个checkStr与该形参列表匹配// pf2 = checkStr; // 错误,checkStr与pf2的返回类型不匹配pf3 = checkStr; // 正确bool b3 = pf3(str1, str2, lenth);system("pause");}
4. 函数指针形参
和数组类似,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。
使用typedef和decltype可以简化使用函数指针。
//#include "mainwindow.h"//#include <QtWidgets/QApplication>#include <iostream>#include <string>#ifndef SAFE_DELETE#define SAFE_DELETE(p) { if(p != nullptr){delete(p); (p) = nullptr;} }#endifusing std::string;bool checkStr(const string &str1, const string &str2){if (str1 > str2){return true;}return false;}// Func和Func2是函数类型typedef bool Func(const string &, const string &);typedef decltype(checkStr) Func2;// FuncP和FuncP2是函数类型typedef bool (*FuncP)(const string &, const string &);typedef decltype(checkStr) *FuncP2;// 第三个形参是函数类型,它会自动地转换成指向函数的指针string useBigger(const string &str1, const string &str2, bool pf(const string &, const string &)){if (pf(str1, str2)){return str1;}else{return str2;}}// 等价的声明,采用类型别名(typedef)和decltype简化函数类型// string useBigger(const string &str1, const string &str2, Func pf);// string useBigger(const string &str1, const string &str2, Func2 pf);// 等价的声明:显示地将形参定义成指向函数的指针// string useBigger(const string &str1, const string &str2, bool (*pf)(const string &, const string &));// 等价的声明,采用类型别名(typedef)和decltype简化函数指针类型// string useBigger(const string &str1, const string &str2, FuncP pf);// string useBigger(const string &str1, const string &str2, FuncP2 pf);int main(int argc, char *argv[]){bool(*pf) (const string &, const string &) = checkStr; // 声明一个函数指针string str1 = "ac";string str2 = "ab";string retStr = useBigger(str1, str2, checkStr); // 自动将checkStr转换成指向该函数的指针// string retStr = useBigger(str1, str2, &checkStr); // 等价的调用,显示的调用函数指针// string retStr = useBigger(str1, str2, pf); // 等价的调用// string retStr = useBigger(str1, str2, *pf); // 等价的调用system("pause");}
注意:decltype返回函数类型,此时不会将函数类型自动转换成指针类型,所以在typedef decltype(checkStr) *FuncP2中在FuncP2前加了一个*,表示checkStr函数的指针。
5. 返回指向函数的指针
和数组类似,虽然不能返回一个函数,但是能返回指向函数类型的指针。
我们必须把返回类型写成指针形式,编译器不会自动地将函数返回类型当成对应的指针类型处理。
// 直接声明
int (*f1(int))(int *, int);
// 使用别名
using F = int(int*, int); // F是函数类型,不是指针
using PF = int(*)(int *, int); // PF是指针类型
// 尾置返回类型方式
auto f1(int)->int(*)(int *, int);
对于直接声明,按照由内向外的顺序阅读这条语句,f1有形参列表(此处为int),所以f1是个函数;f1前面有*,所以f1返回一个指针;指针类型本身也包含形参列表(此处为int*和int),因此指针指向函数,该函数返回类型是int。
和函数类型的形参不一样,返回类型不会自动地转换成指针,必须显示地将返回类型指定为指针。
PF f1(int); // 正确:PF是指向函数的指针,f1返回指向函数的指针
F f1(int); // 错误:F是函数类型,f1不能返回一个函数
F *f1(int); // 正确:显示地指定返回类型是指向函数的指针
将decltype用于函数指针类型
// 申明两个函数
string::size_type sumLenth(const string &, const string &);
string::size_type largeLenth(const string &, const string &);
// 根据其形参的取值,getFcn函数返回指向sumLenth或者largeLenth的指针
decltype (sumLenth) *getFcn(const string &);
注意:decltype作用于某个函数时,它返回函数类型,而非指针类型。
#include <iostream>
#include <string>
using std::string;
string::size_type sumLenth(const string &str1, const string &str2)
{
return str1.length() + str2.length();
}
string::size_type largeLenth(const string &str1, const string &str2)
{
string::size_type len1 = str1.length();
string::size_type len2 = str2.length();
if (len1 > len2)
{
return len1;
}
else
{
return len2;
}
}
// 采用别名方式
using F = string::size_type(const string &, const string &); // F是函数类型,不是指针
using PF = string::size_type(*)(const string &, const string &); // PF是指针类型
F *getFcn(const string &type) // 显式地指定返回类型是真相函数的指针
// PF getFcn(const string &type) // 等价的写法
{
if (type == "1")
{
return sumLenth;
}
else
{
return &largeLenth;
}
}
// 直接申明方式,此处直接定义
string::size_type(*f1(const string &type))(const string &, const string &)
{
if (type == "1")
{
return sumLenth;
}
else
{
return &largeLenth;
}
}
// 尾置返回类型声明f2,此处直接定义
auto f2(const string & type)->string::size_type(*)(const string &, const string &)
{
if (type == "1")
{
return sumLenth;
}
else
{
return &largeLenth;
}
}
int main(int argc, char *argv[])
{
string str1 = "hello";
string str2 = "world!";
F *pf1 = getFcn("1"); // 显式地指定指针类型
// PF pf1 = getFcn("1"); // 等价的调用
// PF pf1 = f1("1"); // 等价的调用,采用别名方式
string::size_type size1 = pf1(str1, str2); // 此处size1 = 11
string::size_type size1_1 = f1("1")(str1, str2); // 直接调用方式,此处size1_1 = 11
F *pf2 = getFcn("2"); // 显式地指定指针类型
//PF pf2 = getFcn("2"); // 等价的调用
string::size_type size2 = pf2(str1, str2); // 此处size1 = 6
string::size_type size2_1 = f2("2")(str1, str2); // 直接调用方式,此处size1_1 = 6
system("pause");
}
6. 成员函数指针
详见类成员指针章节的成员函数指针。
参考:
1)《C++ Primer 中文版(第5版)》;
2)C/C++ 函数指针使用总结。

