博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++中的函数指针的一些总结
阅读量:2440 次
发布时间:2019-05-10

本文共 2934 字,大约阅读时间需要 9 分钟。

1、函数指针的引出

      假设我们需要写个函数

sort( start, end, compare );
对start 和end 之间的数组元素进行排序compare 定义了比较数组中两个字符串的比较操作。如果我们需要比较的数组是string类型,那么排序方式,也许是按照字典序列,也许是串长度,也许是出现频率,那么怎么方便的进行比较呢?

        众所周知,C语言的一大精髓就是指针,那么对此,我们同样可以引入指针来解决。这里的解决方案就是函数指针:讲第三个参数compare 设为函数指针并由它指定要使用的比较函数。从而方便的进行各种比较。

2、函数指针的使用

1)声明

     怎么声明一个函数指针呢?

int (*pf)( const string &, const string & ); // ok: 正确
       如上,声明了一个函数指针,注意的是,解引用操作符* 应与返回类型关联所以在这种情况下是与类型名int 关联而不是pf 要想让解引用操作符与pf 关联,所以括号是必需的,而不能声明为:
int *pf( const string &, const string & );

2)初始化、赋值和调用

      a. 函数指针可以用0 来初始化或赋值以表示该指针不指向任何函数。

      b.直接去想要调用的函数名,如add,注意,这里没有括号。为什么呢?我们知道不带下标操作符的数组名会被解释成指向首元素的指针当一个函数名没有被调用操作符修饰时会被解释成指向该类型函数的指针,例如表达式    

lexicoCompare;
被解释成类型
int (*)( const string &, const string & );
的指针,这里,lexicoCompare定义如下:

#include 
int lexicoCompare( const string &s1, const string &s2 ) {return s1.compare(s2);}
     c.将取地址操作符作用在函数名上也能产生指向该函数类型的指针因此lexicoCompare和&lexioCompare 类型相同
     对于初始化和赋值的示例如下:

int (*pfi)( const string &, const string & ) = lexicoCompare;//初始化pfi = lexicoCompare;//赋值
      看到这个赋值,楼主想到2个地方,一个是在严蔚敏版数据结构的源代码中,BFS和DFS中的visit函数,都是定义为的函数指针,当时的定义为:

void(*VisitFunc)(char* v); /* 函数变量(全局量) */
      传参时如本例提出,将参数作为函数指针传入

void DFSTraverse(ALGraph G,void(*Visit)(char*))
      另外一个,是在flex的ActionScrip中的addEnentListen(),如

addEventListener(Event.CLOSE, closeHandler);
        closeHandler则是作为函数指针传入,虽然在as入门书上讲是引用,不过引用,不就是弱化版指针呢么?(其实对于引用,C++Primer有一句简要的概括:
引用是没有指针语法的指针。比如调用时指针用->,引用用点操作符)。
3、问题的解决

       下面用函数指针解决开始提出的sort问题,funcP.h代码如下:

#include 
#include
using namespace std;typedef int ( *PFI2S )( const string &, const string & );int lexicoCompare( const string &s1, const string &s2 ){ return s1.compare(s2);}void sort( string *s1, string *s2,PFI2S compare = lexicoCompare ){ // 递归的停止条件 if ( s1 < s2 ) { string elem = *s1; string *low = s1; string *high = s2 + 1; for (;;) { while ( compare( *++low, elem ) < 0 && low < s2) ; while ( compare( elem, *--high ) < 0 && high > s1) ; if ( low < high ) low->swap(*high); else break; } // end, for(;;) s1->swap(*high); sort( s1, high - 1, compare ); sort( high + 1, s2, compare ); } // end, if ( s1 < s2 )}
main.cpp如下:

#include "funcP.h"string as[10] = { "a", "light", "drizzle", "was", "falling",                   "when", "they", "left", "the", "museum" };int main() {	// 调用 sort(), 使用缺省实参作比较操作	sort( as, as + sizeof(as)/sizeof(as[0]) - 1 );	// 显示排序之后的数组的结果	for ( int i = 0; i < sizeof(as)/sizeof(as[0]); ++i )		cout << as[ i ].c_str() << endl;	return 0;}
     程序使用了typedef使程序可读性更强,并提供了默认参数(关于默认参数这种偷懒的东东,理解为初始化对话框内容这样,以后可改,只是提供初值。只是这样的初始化,很符合常规思维,理念上更可取)
4、一些注意的问题

      在指向函数类型的指针之间不存在隐式类型转。也就是,只有当赋值操作符左边指针的参数表和返回类型与右边函数或指针的参数表和返回类型完全匹配时初始化和赋值才是正确的如果不匹配则将产生编译错误消息。在灵活性上,更注重了安全性,高级货啊!

      

         关于函数指针,还可以参考这个简单明了,很清晰易懂。

就比较教科书化了。另外有很好的一个总结,,像这个2楼提到,linux下的一个system table的调用,其实也是函数指针。当时做linux内核实验的时候发现系统调用,其实也是以函数指针的形式传递,怎么讲呢,这样的传递,重要的是一种思想,而不是语言的实现,或者实现的名字。提到这个,又扯一下,看《疯狂的程序员》发现里面一个很有道理的一句,汇编里什么寻址方式,C语言里讲什么,语言应该是相通的,不过貌似中文版的那些什么作者们或者译者们是互不往来似的(当然,像侯捷这样的大师除外)

       就是这样了,菜鸟goes on~~

转载地址:http://wlcqb.baihongyu.com/

你可能感兴趣的文章
react 实现滚动加载_如何在React中实现平滑滚动
查看>>
报纸打字项目_如何使用打字稿设置节点项目
查看>>
如何在Debian 10上安装Docker Compose
查看>>
prisma orm_Prisma中的身份验证-第2部分:JSON Web令牌和登录
查看>>
centos cron_如何在CentOS 8上使用Cron自动化任务
查看>>
V8的V8:JavaScript中的可选链接和无效合并
查看>>
如何在JavaScript中使用map(),filter()和reduce()
查看>>
react hooks使用_使用Hooks动态加载React组件
查看>>
bat命令行遍历文件_命令行基础知识:如何遍历目录中的文件
查看>>
了解编程中的操作顺序
查看>>
react中创建一个组件_如何在React中创建社交关注组件
查看>>
DigitalOcean的技术写作指南
查看>>
配置管理规范 配置管理计划_配置管理简介
查看>>
如何在Ubuntu 18.04上添加和删除用户
查看>>
angular4前后端分离_如何在Angular 4+中使用Apollo客户端GraphQL
查看>>
如何在Ubuntu 18.04上安装Apache Kafka
查看>>
如何在Ubuntu 20.04上安装R [快速入门]
查看>>
debian tomcat_如何在Debian 10上安装Apache Tomcat 9
查看>>
如何使用MongoDB和Docker设置Flask
查看>>
如何为Python 3设置Jupyter Notebook
查看>>