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;
}

C++中的函数指针

时间: 2024-10-11 00:40:50

C++中的函数指针的相关文章

C++中传送函数指针

函数指针是一种非常好的类型.因此,可以编写一个函数,它的一个参数是函数指针.然后,在(外部)函数使用其函数指针参数时,就间接地调用在调用函数时对应参数指向的函数. 由于指针在不同的情况下可以指向不同的函数,因此允许调用程序确定要从外部函数中调用哪个函数. 在用函数指针类型的参数调用函数时,参数可以只包含函数地址的相应类型的指针.还可以把函数名作为参数,显示传送函数.作为参数传送给另一个函数的函数有时称为回调函数. 示例: #include <iostream> using std::cout;

C++中使用函数指针 【瓦特芯笔记】

     在C++类中使用函数指针. 类型定义:      typedef 返回类型(类名::*新类型)(参数表) //类定义 class CA { public: char lcFun(int a) { return; } };      CA ca;      typedef char (CA::*PTRFUN)(int);      PTRFUN pFun;     void main()     {        pFun = CA::lcFun;        ca.(*pFun)(2

1、C语言中的函数指针

一 通常的函数调用 1 void MyFun(int x); //此处的申明也可写成:void MyFun( int ); 2 3 int main(int argc, char* argv[]) 4 { 5 MyFun(10); //这里是调用MyFun(10);函数 6 7 return 0; 8 } 9 10 void MyFun(int x) //这里定义一个MyFun函数 11 { 12 printf("%d\n",x); 13 } 这个MyFun函数是一个无返回值的函数,它

QT中使用函数指针

想仿命令行,所以定义了一个类,让一个String 对应一个 function,将两者输入list容器. 类中定义了 QString commandStr; void (MainWindow::*commandFun)(void);一个QString ,一个指向MainWindow类成员函数的指针.但是没想到在类中使用函数指针这么复杂. 一般情况,我们使用函数指针声明和引用都很简单明了.但是在类中就不一样了.最后的成功的形式如下: class command_type { public: comm

结构体中定义函数指针

转自:http://blog.csdn.net/unix21/article/details/9293877 结构体指针变量的定义,定义结构体变量的一般形式如下: 形式1:先定义结构体类型,再定义变量 struct结构体标识符 { 成员变量列表;… }; struct 结构体标识符 *指针变量名; 变量初始化一:struct结构体标识符 变量名={初始化值1,初始化值2,…, 初始化值n }; 形式2:在定义类型的同时定义变量 struct结构体标识符 { 成员变量列表;… } *指针变量名;

C语言结构体中的函数指针

这篇文章简单的叙述一下函数指针在结构体中的应用,为后面的一系列文章打下基础 本文地址:http://www.cnblogs.com/archimedes/p/function-pointer-in-c-struct.html,转载请注明源地址. 引言 指针是C语言的重要组成部分, 于是深入理解指针并且高效地使用指针可以使程序员写出更加老练的程序.我们要记住指针是一个指向内存地址的变量.指针可以引用如int.char……常见的数据类型,例如: int * intptr; // 声明一个指向整型值的

Delphi中的函数指针判断是否为空

delphi函数指针 只有@@p才代表了函数指针本身的地址   assigned(p) 判断是否为空 或者用 @p=nil 来判断函数指针是不是为空 Delphi中的函数指针实际上就是指针,只是在使用的时候有些不同 函数指针要先定义一个函数类型,比如 type TTestProc = procedure of object; 这是一个最简单的函数类型,没有参数,也没有返回值,并且要求是类的成员函数 类的成员函数其实就代表了调用的时候参数的不同,因为类的成员函数隐含着一个对象参数,而不是显式写明,

为什么 C++ 中成员函数指针是 16 字节?

当我们讨论指针时,通常假设它是一种可以用 void * 指针来表示的东西,在 x86_64 平台下是 8 个字节大小.例如,下面是来自 维基百科中关于 x86_64 的文章 的摘录: Pushes and pops on the stack are always in 8-byte strides, and pointers are 8 bytes wide. 从 CPU 的角度来看,指针无非就是内存的地址,所有的内存地址在 x86_64 平台下都是由 64 位来表示,所以假设它是 8 个字节是

C 中typedef 函数指针的使用

类型定义的语法可以归结为一句话:只要在变量定义前面加上typedef,就成了类型定义.这儿的原本应该是变量的东西,就成为了类型. int integer;     //整型变量int *pointer;   //整型指针变量int array [5]; //整型数组变量int *p_array [5]; //整型指针的数组的变量int (*array_pointer) [5];//整型数组的指针的变量int function (int param);//函数定义,也可将函数名看作函数的变量int