一、仿函数
Functor/Function Object翻译过来就是仿函数,它是通过重载()运算符模拟函数行为的类。也就是说,它不是函数(所以仿函数翻译的很贴切)。因为它重载了()运算符,因此可以像调用函数一样对它进行调用。STL中大量运用了Function Object,也提供了很多预先定义的Function Object。还是从vector遍历举例:
1 | class PrintInt |
仿函数的优点:
1.仿函数是对象,可以拥有成员函数和成员变量,即仿函数拥有状态(states)
2.每个仿函数都有自己的类型
3.仿函数通常比一般函数快(很多信息编译期确定)
二、闭包
闭包(Closure)可以被理解为一个附带数据的操作,WikiPedia 对闭包的定义是 *”In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions.”*,其中有两层含义:
- 词法作用域(lexically scoped)的名字绑定(name binding):在词法作用域(C++ 的词法作用域是静态绑定的,包括块、函数、类、命名空间、全局作用域等)中,变量名与其词法上下文的标识符相关联,而独立于运行时的调用栈;
- 函数被当作头等公民(first-class citizen):在运行时可以构造一个函数对象并将其作为参数传递给其他函数;
显然 C++ 98 并不符合这两点定义,因此 C++ 98 中并没有严格意义上的闭包,但我们可以用仿函数(Functor)来模拟闭包的行为;仿函数即一个重载了小括号操作符的类,这个类拥有与函数相近的行为方式,它拥有自己的私有成员变量,例如:
1 | class Adder |
相比之下 golang 中真正的闭包显得简洁很多:
1 | unc adder() func(int) int { |
三、匿名函数
C++ 11 标准中正式引入了匿名函数,也叫做 lambda 表达式(Lambda Expression);匿名函数是一种没有被绑定标识符的函数,可以用于很方便地定义一个临时的函数对象,或作为一个函数对象传递给更上层的函数(例如 std::for_each
),其在 C++ 11 的语法上表现得非常轻量级,不需要像普通的具名函数一样单独在头文件中作出声明,且符合闭包的定义。
1. 闭包和匿名函数的关系
- 匿名函数和闭包的关系就如同类和类对象的关系,匿名函数和类的定义都只存在于源码(代码段)中,而闭包和类对象则是在运行时占用内存空间的实体;
- 对匿名函数的定义会生成一个独一无二的类,并在运行时生成其类对象;
- 可以知道实际上匿名函数也是用仿函数实现的,它实际上是 C++ 11 加入的语法糖,不过其语法特性是符合闭包定义的。