关于c++STL中,使用mem_fun的问题

关于c++STL中,使用mem_fun的问题,第1张

一个类重载了(),它事实上就是一个仿函数(functor)了。这其实是一个C++语法上的trick,因为C++的泛型是基于代码层面的,所以虽然调用函数和调用一个类的operator ()在本质上是不同的,但是在语法上的写法是一致的,因此就可以破例调用。

STL的标准算法是不支持传入一个“成员函数指针”的(因为当没有实例化的对象的时候,成员函数根本不知道this是谁),但是支持“普通函数指针”或“仿函数”,而mem_fun、mem_fun_ref的作用就是将一个"成员函数指针"包装成一个仿函数。

你说for_each的问题,关键是,它传入的是一个对象,而不是一个函数指针。for_each是允许一个对象作为仿函数被传入的(只要它重载了operator() ),但是for_each不允许你传入一个成员函数指针。你如果把一个类的成员函数作为参数,当然会出现问题。

operator()和普通的成员函数并没有什么本质的不同,其实如果你显式的把一个仿函数的operator()传入for_each,也会报错的。但关键是人家传入的不是一个operator(),而是整个对象。

这块涉及到的泛型编程知识,深究起来会有点深(特别是mem_fun的实现,非常tricky),想看的话建议去翻翻《C++标准程序库》和《STL源码剖析》

中断服务函数ISR不被任何函数调用,ISR和main可以看作是并行发生的。

函数式编程:

  函数式编程是种编程典范,它将电脑运算视为函数的计算。函数编程语言最重要的基础是 λ 演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。和过程化编程相比,函数式编程里,函数的计算可随时调用。

  在经常被引用的论文 “Why Functional Programming Matters”(请参阅 参考资料) 中,作者 John Hughes 说明了模块化是成功编程的关键,而函数编程可以极大地改进模块化。在函数编程中,编程人员有一个天然框架用来开发更小的、更简单的和更一般化的模块, 然后将它们组合在一起。函数编程的一些基本特点包括:

  支持闭包和高阶函数,支持惰性计算(lazy evaluation)。使用递归作为控制流程的机制。加强了引用透明性。没有副作用。我将重点放在在 Java 语言中使用闭包和高阶函数上,但是首先对上面列出的所有特点做一个概述。

闭包和高阶函数:

  函数编程支持函数作为第一类对象,有时称为 闭包或者 仿函数(functor)对象。实质上,闭包是起函数的作用并可以像对象一样 *** 作的对象。与此类似,FP 语言支持 高阶函数。高阶函数可以用另一个函数(间接地,用一个表达式) 作为其输入参数,在某些情况下,它甚至返回一个函数作为其输出参数。这两种结构结合在一起使得可以用优雅的方式进行模块化编程,这是使用 FP 的最大好处。

惰性计算:

  除了高阶函数和仿函数(或闭包)的概念,FP 还引入了惰性计算的概念。在惰性计算中,表达式不是在绑定到变量时立即计算,而是在求值程序需要产生表达式的值时进行计算。延迟的计算使您可以编写可能潜在地生成无穷输出的函数。因为不会计算多于程序的其余部分所需要的值,所以不需要担心由无穷计算所导致的 out-of-memory 错误。一个惰性计算的例子是生成无穷 Fibonacci 列表的函数,但是对 第 n 个Fibonacci 数的计算相当于只是从可能的无穷列表中提取一项。

递归:

  FP 还有一个特点是用递归做为控制流程的机制。例如,Lisp 处理的列表定义为在头元素后面有子列表,这种表示法使得它自己自然地对更小的子列表不断递归。

引用透明性:

  函数程序通常还加强引用透明性,即如果提供同样的输入,那么函数总是返回同样的结果。就是说,表达式的值不依赖于可以改变值的全局状态。这使您可以从形式上推断程序行为,因为表达式的意义只取决于其子表达式而不是计算顺序或者其他表达式的副作用。这有助于验证正确性、简化算法,甚至有助于找出优化它的方法。

副作用:

  副作用是修改系统状态的语言结构。因为 FP 语言不包含任何赋值语句,变量值一旦被指派就永远不会改变。而且,调用函数只会计算出结果 ── 不会出现其他效果。因此,FP 语言没有副作用

callback函数定义回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

在计算机程序设计中,回调函数,或简称回调(Callback),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序:

例如:defmy_callback(input):print"functionmy_callbackwascalledwith%sinput"%(input,)defcaller(input,func):func(input)foriinrange(5):caller(i,my_callback)执行结果是:functionmy_callbackwascalledwith0inputfunctionmy_callbackwascalledwith1inputfunctionmy_callbackwascalledwith2inputfunctionmy_callbackwascalledwith3inputfunctionmy_callbackwascalledwith4input

回调函数,或简称回调(Callback 即call then back 被主函数调用运算后会返回主函数),是指通过参数将函数传递到其它代码的,某一块可执行代码的引用。

这一设计允许了底层代码调用在高层定义的子程序。

回调的用途十分广泛。例如,假设有一个函数,其功能为读取配置文件并由文件内容设置对应的选项。

若这些选项由散列值所标记,则让这个函数接受一个回调会使得程序设计更加灵活:函数的调用者可以使用所希望的散列算法,该算法由一个将选项名转变为散列值的回调函数实现;因此,回调允许函数调用者在运行时调整原始函数的行为。

回调的另一种用途在于处理信号或者类似物。例如一个POSIX程序可能在收到SIGTERM信号时不愿立即终止;为了保证一切运行良好,该程序可以将清理函数注册为SIGTERM信号对应的回调。

回调亦可以用于控制一个函数是否作为:Xlib允许自定义的谓词用于决定程序是否希望处理特定的事件。

有两种类型的回调,它们在运行时控制数据流的方式不同:阻塞回调(也称为同步回调或仅回调)和延迟回调(也称为异步回调)。

在函数返回之前调用阻塞回调(在下面的 C 示例中,它说明了阻塞回调,它是函数main),则可以在函数返回后调用延迟回调。延迟回调通常用于 I/O *** 作或事件处理的上下文中,并且在多个线程的情况下由中断或不同的线程调用。

由于其性质,阻塞回调可以在没有中断或多线程的情况下工作,这意味着阻塞回调通常不用于同步或将工作委托给另一个线程。

回调用于在窗口系统中对应用程序进行编程。在这种情况下,应用程序提供(引用)一个特定的自定义回调函数供 *** 作系统调用,然后 *** 作系统调用此特定于应用程序的函数以响应鼠标单击或按键等事件。

这里的一个主要问题是权限和安全性的管理:虽然该函数是从 *** 作系统调用的,但它不应以与系统相同的权限运行。这个问题的解决方案是使用保护环。

回调函数在实际中有许多作用。

假设有这样一种情况:我们要编写一个库,它提供了某些排序算法的实现(如冒泡排序、快速排序、shell排序、shake排序等等),为了能让库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑。

回调可用于通知机制。例如,有时要在A程序中设置一个计时器,每到一定时间,A程序会得到相应的通知,但通知机制的实现者对A程序一无所知。

那么,就需一个具有特定原型的函数指针进行回调,通知A程序事件已经发生。实际上,API使用一个回调函数SetTimer来通知A程序。如果没有提供回调函数,它还会把一个消息发往程序的消息队列。

另一个使用回调机制的API函数是EnumWindow,它枚举屏幕上所有的顶层窗口,每个窗口都可以通过它调用另一个程序提供的函数,并传递窗口的处理程序。例如:如果被调用者返回一个值,就继续进行迭代;否则,退出。

EnumWindow并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。

C语言的回调函数只能通过函数指针实现,在C++中则可以使用匿名函数(lambda)或仿函数(functor)作为回调函数。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/13492106.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2025-09-01
下一篇2025-09-01

发表评论

登录后才能评论

评论列表(0条)

    保存