万字长文系统梳理一下C++函数指针 您所在的位置:网站首页 本位币是什么 万字长文系统梳理一下C++函数指针

万字长文系统梳理一下C++函数指针

#万字长文系统梳理一下C++函数指针| 来源: 网络整理| 查看: 265

本篇的内容相对比较简单 主要从语法的层面讲解函数指针的使用以及应用场景。都是些面向入门者的基础,大佬轻喷。首先:什么是函数指针。

这个问题老生常谈了,不用理解的多么复杂,它其实就是一个特殊的指针,它用于指向函数被加载到的内存首地址,可用于实现函数调用。

听上有点像函数名,函数名也是记录了函数在内存中的首地址,加()就可以调用。

不错,不过函数指针和函数名还是有点区别的,他们虽然都指向了函数在内存的入口地址,但函数指针本身是个指针变量,对他做&取地址的话会拿到这个变量本身的地址去。

而对函数名做&取址,得到的还是函数的入口地址。如果是类成员函数指针,差别更加明显。

关于函数名和函数指针的差异,找到一篇帖子介绍的比较深入,如果看完这篇文章你还没晕的话,可以回过头来去看看这位大佬的讲解https://www.cnblogs.com/hellscream-yi/p/7943848.html函数指针有啥用?

和通过函数名调用一样,函数指针给我们提供了另一种调用函数的可能

而他又具备变量的特性,可以作为参数传递,可以函数返回

因此在一些直接通过函数名无法调用的场景下,函数指针就有了用武之地。

我们接下来还是先说说函数指针怎么写,完后再提供一些具体应用场景来说明它有什么用。

函数指针的写法

大多数初学者包括我在内,潜意识里对于函数指针都有点抵触,能不用的时候都尽量不用。

因为我们印象里见过的函数指针很可能是这样的:

double * (*p1)(const double * , int m); int (*funcArry[10])(int, int); typedef char * (MyObject::*FUNC_PTR )(const chat * str); void * (* ( * fp1)(int))[10]; #define double (*(*(*fp3)())[10])(); int (*(*fp4())[10])();

甚至还有:

int *(*(*fp)(int(*)(int, int), int(*)(int)))(int, int, int(*)(int, double * (p1)(const double * , int m)));

好在一般这种反人类的写法,只会经常出现在大学的期末试卷里,生产实践中谁也不会把函数写成这个鬼样子。

不过这也奠定了我们内心深处对于函数指针深深的抵触和恐惧。

普通函数指针

言归正传,我们来说说函数指针的语法该怎么理解。

声明

函数指针就是一种特殊的指针。

如果你要声明一个变量:

int a ;

而一个指针呢:

int *a;

那一个函数指针,就是在一个变量指针的写法基础上加一个括号,告诉他这是一个指向函数的指针就可以:

int (*a)();

这样,a就是一个函数指针了。

这个括号(*a)一定要加,否则就成了int *a();编译器会认为这是一个 返回int *的函数a;

这时候呢,int (*a)();就声明了一个函数指针变量a,它可以指向一个返回int,参数列表为空的函数。

前面的int,就是这个函数指针的返回值,a是变量名,最后一个()是参数列表。

赋值

直接将一个已经定义的函数名,赋值给函数指针就可以:a = function;

当然,直接把声明定义和初始化写在一起也可以,只是平常不多见这么写:int (*a)() = function;

和上面先声明再赋值是等价的。

调用

函数指针的变量,可以当做函数名一样被调用,所以直接:a();就相当于调用了函数。

注意这是声明的一个函数指针的变量,和函数的声明有所区别。

因此你不能像定义一个函数一样定义一个函数指针,你只能声明出这个指针,然后给他赋值一个函数签名匹配的已经定义好的函数名:

int function() // 正确的函数声明 { return 0; } int (*a)() // 错误:这是一个变量,不能当函数一样定义 { return 0; } //你只能这样: int (*a)(); //声明一个函数指针变量a, int main() { a = function; //给函数指针赋值。 a(); //通过函数指针调用 // 也可以直接把声明和赋值写在一起:这就像是 int i;和int * p = i;的区别 int (*b)() = function; b(); return 0; } 稍微复杂一些的函数指针

给函数指针赋值的时候,对应的函数签名(返回值和参数列表)必须是和他的相匹配的。

如果对应的函数原型比较复杂,相对应的函数指针的写法也会复杂一些。

这里循序渐进地举几个相对复杂一些的例子:

// 最简单的函数及其对应的函数指针: void f(); void (*f_ptr)(); // 复杂点的,带返回值和参数列表,但都是基本类型 int f(double b, int i); int (*f_ptr)(double b, int i); // 返回值和参数带上指针,再加上几个const混淆一下 const double * f(const double * b2, int m); const double * (*f_ptr)(const double * b2, int m); // 再复杂一点点,参数里加个函数指针 也不是很复杂,基本只要把函数名换成(*函数名) 就可以了 int f(int (*fp)(),int a ); int (*f_ptr)(int (*fp)(),int a ); // 稍微再复杂一点点,返回值是一个函数指针:(光是普通函数返回函数指针,语法就有点费劲。我们一步一步来:) //// 首先搞一个返回void的普通函数: void f(); //// 假设返回一个函数指针,这个函数指针返回值和参数都为空。我们用一个函数指针替换掉返回值void就可以了 //// 感觉应该写成这样:void (*fp)() f(); //// 但是这个样子显然过不了编译的,得要变一下: void (* f())(); //这就是一个参数为空,返回函数指针的函数。 void (*(*f_ptr)())(); //把f替换成(*f_ptr),这就成了返回函数指针的函数指针。 // 其实写成上面这个样子,大多数人已经懵逼了。 // 再往复杂的搞,真就彻底花了,比如返回值和参数里整上函数指针数组,函数指针参数里套函数指针,返回的函数指针返回值是个函数指针等等 // 这种的我们就不研究了。一方面项目中这么写会挨骂,另一方面太复杂的我也不会。

从一开始的void f();,到最后成了这个void (*(*f_ptr)())();鬼样子

说真的最后这种写法我是正向推导过来的,如果是你维护别人的代码,上来看到一个这void (*(*f_ptr)())();,恐怕得先骂一会儿娘才能正式开始工作

然而这却只是返回函数指针的函数指针的最简单的写法,参数全为空,返回全为void,也不涉及指针数组,还完全没有进行太多反人类的语法变种。

好在,我们还是有办法给他整的简化一点的

把函数指针弄成一个自定义类型

我们把关注点聚焦到上面最后一个函数指针上,定义一个返回值是函数指针的函数,完整的声明加调用应该是这样的:

#include using namespace std; void aaa() { cout


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有