C++中的函数指针

时间:2014.06.14

地点:基地

-------------------------------------------------------------------------------

一、函数指针简单介绍

  函数指针指向的是一个函数,而不是一个对象。但函数指针也和其它普通指针一样。指向特定的函数类型,函数的类型由返回类型和形參类型共同决定。与函数名无关,就像和变量名无关一样。

比方:

bool LengthCompare(const string&,const string& );
上面这个函数的类型即 bool (const string&,const string&),要想声明一个指向这样一个函数类型的指针能够这样:

bool (*pf)(const string&,const string&);  //函数指针未初始化
即用一个指针变量名加*替换掉函数名就可以。

这和声明普通指针和类型。声明普通指针时我们也是用一个指针变量名加*放在类型声明后。在这里,我们看到pf前面有*,说明pf是一个指针变量名,右側有形參列表。表pf指向的是一个函数,再看左側的返回类型,表明pf函数指针指向的函数返回一个布尔值。

这里声明一个函数指针时一定记得将 *pf括起来。否则比方这样:

bool* pf(const string&,const string&);
这将声明的是一个普通函数,它返回一个bool* 

-------------------------------------------------------------------------------

二、函数指针的使用

函数名就像数组名,当我们将函数名最为一个值使用时,该函数会自己主动转换成指针。可直接赋给函数指针

比方以下是等价的:

pf=LengthCompare;  //pf指针指向函数LengthCompare
pf=&LengthCompare;  //也是一样的,所以取址符在这里是可选的
同一时候,我们还能够使用指向函数的指针直接调用所指向的函数,无需解引用指针。当然解引用也没错。以下三种调用方式等价:

bool b1=pf("hello","world");
bool b2=(*pf)("hello","world");
bool b3=LngthCompare("hello","world");
总的一点说来:声明一个函数指针后,给该函数指针变量赋值也用相应类型函数的函数名或对函数名取址都可,调用时,直接用该函数指针变量或对该变量解引用也都可。

须要注意的是,函数指针不能发生不同类型之间的转换,但可赋值nullptr或者0,的整型常量表达式,表示该函数指针没有指向不论什么一个函数。

注意函数类型的匹配一定是函数返回值和形參类型和个数精确匹配。

说道精确匹配,这里是要求严格一致的精确匹配,当遇到函数重载时,函数指针仅仅能选用精确匹配的那个函数。比方:

void ff(int*);
void ff(unsigned int);
void (*pf1) (unsigned int)=ff/  //这里pf1指向ff(unsigned int)
-------------------------------------------------------------------------------

三、能作为函数參数的函数指针形參

  我们知道,数组是不能作为函数形參的,函数也一样,但函数的形參能够是一个指向某个函数的指针,就像函数的形參能够是指向某个数组的指针一样。也和数组一样,形參看起来是一个函数类型。但实际上会当成一个指向这样类型的函数指针。

比方:

//以下函数的声明中第三个參数就为函数类型,会自己主动转换为指向函数的指针
void Function(const string& s1,const& s2,bool pf(const string&,const string&));
//和上面等价。这里显示地将形參定义为了函数指针
void Function(const string& s1,const string& s2,bool (*pf)(const string &,const string&));
正如我们前面提及的,我们能够直接将函数作为实參使用,函数名就像数组名一样,当它传递给函数时会自己主动转换为一个指针,比方:

Function(s1,s2,LengthCompare);
在上面。我们看到Function的声明好长。看起来不爽,这是由于我们在说明一个函数类型时须要给出函数的返回值和函数的形參列表,而为了说明某种类型,我们在常规场合下可使用typedef来定义类型的别名,在这里相同适用。

首先我们可用typedef来定义自己的类型,比方:

typedef bool Func(const string&,const string&);  //这里的Func是一个函数类型
typedef bool(*FuncP)(const string&,const string&);  //这里的FuncP是一个指向函数的指针
啊。typedef的功劳使得这两句中的Func 和 FuncP是一个类型名。而不是简单的一个名,但同一时候,我们还有办法从变量名中推出类型,比方:

typedef decltype(LengthCompare) Func2; //定义了一个函数类型别名,它和LengthCompare函数的类型一样
typedef decltype(LengthCompare)* FuncP2; //使用decltype推导出LengthCompare函数的类型,然后加上个* 。于是说明FuncP2是一个指向这样的函数类型的指针类型
注意这里的decltype返回的是函数的类型,由于我们是推导LengthCompare,它不会将函数类型自己主动转换为函数指针类型。所以还要加上*才干得到指向这个函数类型的指针。如今我们的Function定义能够这样:

void Function(const string&,const string&,Func);//这里。Func表示的是函数类型,可编译器可自己主动将它转换为函数指针,注意仅仅有当Func是一个函数类型时可这样,简单的函数名不能够,所以,一定要记得typedef定义函数类型
void Function(const string&,const string&,FuncP2);//FuncP2在这里是一个显示的函数指针类型,也是要记得用typedef结合decltype导出一个函数指针的类型,由于形參是要给出一个类型的嘛?所以typedef在包括有函数指针的函数声明中骑到了简化作用
-------------------------------------------------------------------------------

四、返回指向函数的指针

  我们不仅能够使用函数指针,并且还能够返回函数指针。就像能够返回数组指针那样。先来讨论类型别名的还有一种写法:

using F=int(int*,int);  //这里F是函数类型。不是函数指针类型(啊。函数类型的说明仅仅要给出返回类型,參数列表就OK了)
using FP=int(*)(int*,int);//这里FP就是一个函数指针类型了
注:我们在声明一个函数时,无论是參数列表也好还是返回值也好。都相应着一种类型,若是函数指针參数或返回函数指针,那么它们也相应着要给出类型说明。但直接给出往往显得难看不美观,于是我们使用using或typedef定义类型别名。

如今我们知道,形如int(int*,int)是一种函数类型,而形如 int(*)(int*,int)是一种函数指针类型

我们的F是函数类型别名了,FP则是函数指针类型别名。和将函数名传递给函数不一样。函数返回一个函数指针时就不会将函数名转换为指针。必须显式地将返回类型指定为指针。比方:

FP f1(int);  //正确,FP是一个指向函数的指针类型,f1返回指向函数的指针
F f1(int);  //错误,F是函数类型,f1不能返回一个函数,就是不能返回一个数组一样
F* f1(int);//正确,显式地指定了返回类型是指向函数的指针
这样全然写也行:

int(*f1(int))(int*,int);
这个看起来比較纠结,从里往外看,f1有形參列表是一个函数,f1前有*,说明这个f1函数返回一个指针,再看,返回的指针类型本身也有形參列表。由于是一个指向函数的指针,再看这个函数指针的类型为 int(int* ,int)。更美观的我们是应该使用尾置返回类型的方式声明一个返回函数指针的函数:

auto f1(int)->int(*)(int*,int);

牢记。当decltypee作用于某个函数时,返回的是函数类型,而不是函数指针类型,一定要显式地加上*以表明所须要的返回指针或声明函数时的函数指针形參类型。

-------------------------------------------------------------------------------

五、练习题

  编写4个函数,它们都分别对两个int值进行加减乘除,将指向这四个函数的函数指针存放在vector中。调用vector中的每一个元素并输出结果:

#include<iostream>
#include<vector>
using namespace std;
int Func(int a, int b);
int Add(int a, int b)
{
	return a + b;
}
int Sub(int a, int b)
{
	return a - b;
}
int Multi(int a, int b)
{
	return a*b;
}
int Div(int a, int b)
{
	return a / b;
}
int main()
{
	using FuncType = decltype(Func);   
	vector<FuncType*> vec{ Add, Sub, Multi, Div };  //记得这里要加* 
	int a, b;
	cin >> a >> b;
	for (auto f : vec)
		cout << f(a, b) << endl;
}












posted on 2019-04-01 20:04  xfgnongmin  阅读(126)  评论(0编辑  收藏  举报

导航