函数指针
函数指针指向的是函数并不是对象。和其他指针一样,函数指针指向
某种特定类型,函数的类型由它的
返回类型和
形参类型共同决定,与
函数名无关。
声明指向函数的指针的语法形式:用指针替代函数名
1
2
3
4
5
6
7
8
9
10
11 1//比较两个string对象的长度
2bool lengthCompare(const string &,const string &);
3
4//pf就是指向函数的指针,该函数的形参为const string的引用,返回值为bool类型
5bool (*pf) (const string &,const string &);
6//pf前面有个*,表示为指针;右侧是形参列表,则表示pf指向的是函数;再观察左侧,函数返回类型是bool值
7
8//*p两端的括号不能省略
9bool *pf(const string &,const string &);
10//声明名为pf的函数,函数返回类型为bool*
11
1、使用函数指针:
把函数名当一个值使用时,该函数自动转换为指针
1
2
3
4 1//pf为指针,函数名当值使用,函数自动转换为地址,取地址符可要可不要
2pf=lengthCompare; //pf指向lengthCompare函数
3pf=&lengthCompare; //与上式等价,取地址符可要可不要
4
可以直接使用指向该函数的指针,无须提前解引用指针
1
2
3
4 1bool b1=pf("hello","goodbye"); //调用lengthCompare函数
2bool b2=(*pf)("hello","goodbye"); //等价调用
3bool b3=lengthCompare("hello","goodbye");//等价调用
4
可以为函数指针赋予nullptr,表示该指针没有指向任何一个函数。
2、重载函数的指针:
使用重载函数的指针,形参列表和函数返回类型都必须要与重载函数中的某一个
精准匹配。
1
2
3
4
5
6
7 1void ff(int *);
2void ff(unsigned int);
3
4void (*pf1)ff(unsigned int);//pf1指向ff(unsigned int)
5void (*pf2)ff(int)=ff; //错误:没有任何一个ff与pf2的形参列表匹配
6double (*pf3)ff(int *)==ff; //错误:ff和pf3的返回类型不同
7
3、函数指针形参:
和数组类似,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。这时的形参看起来是函数类型,实际上是被当指针使用
1
2
3
4
5
6
7
8
9 1//第三个形形参看起来是函数类型,但是它会自动转换为指向函数的指针
2void useBigger(const string &s1,const string &s2,bool pf(const string &,const string &));
3
4//等价的声明:显式地将形参定义为指向函数的指针
5void useBigger(const string &s1,const string &s2,bool (*pf)(const string &,const string &));
6
7//把函数作为实参使用,它也会转换为指针
8useBigger(s1,s2,lengthCompare);
9
使用类型别名和decltype简化函数指针的代码:
1
2
3
4
5 1//Func函数类型的别名
2typedef bool Func(const string &,const string &);
3//FuncP函数指针类型的别名
4typedef book (*FuncP)(const string &,const string &);
5
decltype得到的是
函数类型,只有在前面
加上*才能得到指针。
1
2
3
4 1//Func自动地转换为函数指针
2void useBigger(const string &,const string &,Func);
3void useBigger(const string &,const string &,FuncP);
4
编译器自动地
将Func表示的函数类型转换为指针。
4、返回指向函数的指针:
使用类型别名可以定义函数类型,也可以定义指向函数类型的指针。
1
2
3
4
5
6
7
8
9
10
11
12 1using F=int(int*,int);//F是函数类型,不是指针
2using PF=int(*)(int*,int);;//PF是函数指针类型
3
4PF f1(int);//正确:PF是指向函数的指针,f1返回的是函数的指针
5F f1(int);//错误:F是函数类型,f1不能返回函数类型
6F *f1(int);//正确:显式地将返回类型转换为函数的指针
7
8int (*f1(int))(int*,int);//f1有形参列表,所以f1是个函数;f1前面有*,所以f1返回的是一个指针;指针的类型本身也包含形参列表,因此指针指向函数,该函数的返回类型为int
9
10//尾置返回类型
11auto f1(int)->int(*)(int*,int);
12
使用auto和decltype用于函数指针类型:
decltype得到的类型,需要加上*得到函数指针,auto直接得到函数指针。
几个简单的demo:
练习 6.54:
int func(int,int);
vector<decltype(func)*> vF;
练习 6.55:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 1#include<iostream>
2#include<vector>
3using namespace std;
4
5int func1(int a, int b) //加法
6{
7 return a + b;
8}
9int func2(int a, int b) //减法
10{
11 return a - b;
12}
13int func3(int a, int b) //乘法
14{
15 return a * b;
16}
17int func4(int a, int b) //除法
18{
19 if (b != 0)
20 return a / b;
21 else
22 {
23 cout << "除数不能为0!" << endl;
24 return 0;
25 }
26}
27
28int main(void)
29{
30 system("color 50");
31 //函数名当值使用时自动转换为指针,即int(*)(int,int);decltype得到的类型为int()(int,int),加上*变成函数指针了
32 decltype(func1)* p1 = func1, * p2 = func2, * p3 = func3, * p4 = func4;
33 //vector装的是类型为int (*)(int,int)的函数指针
34 vector<decltype(func1)*> vF = { p1,p2,p3,p4 };
35 system("pause");
36}
37
练习 6.56:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 1#include<iostream>
2#include<vector>
3using namespace std;
4
5int func1(int a, int b) //加法
6{
7 return a + b;
8}
9int func2(int a, int b) //减法
10{
11 return a - b;
12}
13int func3(int a, int b) //乘法
14{
15 return a * b;
16}
17int func4(int a, int b) //除法
18{
19 if (b != 0)
20 return a / b;
21 else
22 {
23 cout << "除数不能为0!" << endl;
24 return 0;
25 }
26}
27//第三个形参为函数指针
28void Compute(int a, int b, int(*p)(int, int))
29{
30 //使用函数指针无须解引用,直接调用即可
31 cout << p(a, b) << endl;
32}
33int main(void)
34{
35 system("color 50");
36 int i = 5, j = 10;
37 //函数名当值用自动转换为指针,函数指针指向的类型为int(int,int)
38 decltype(func1)* p1 = func1, * p2 = func2, * p3 = func3, * p4 = func4;
39 //vector装的是类型为int (*)(int,int)的函数指针
40 vector<decltype(func1)*> vF = { p1,p2,p3,p4 };
41 for (auto it : vF)
42 {
43 Compute(i, j, it);
44 }
45 system("pause");
46}
47