思维导图
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;} }
#endif
using 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++ 函数指针使用总结。