• C++雾中风景7:闭包


    本来说好要聊一聊命名空间的,因为最近在看C++lambda表达式的内容,所以借这个机会我们来好好聊一聊C++的闭包。

    1.什么是闭包?

    闭包(closure)是函数式编程的重要的语法结构。
    闭包的概念其实很简单,一言以蔽之:闭包是带有上下文的函数。说白了,就是有状态的函数。也就是说一个局部变量n,在被函数对象给“封闭”在函数里,从而能把值保存了下来,让函数能够保存状态。(其实本质上就是一个类,用纯粹面向对象的方式理解,函数也是一个对象

    扯概念很烦,我们直接上代码来看一看。这里我们用Python的代码来解释一下闭包。(后续我们再来详细聊聊C++之中是怎么样实现闭包的):

    def getFun(n):
         return lambda:n + n
    
    funA = getFun(10)
    funB = getFun("abc")
    
    print(funA.func_closure[0].cell_contents)
    print(funB.func_closure[0].cell_contents)
    

    打印结果为:

    10      //funcA的闭包变量
    abc     //funcB的闭包变量
    

    由上述两个函数我们看到变量作为一种状态嵌入到函数由getFun返回的函数之中。不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包是通过函数对象的属性来保存闭包的变量。(这里在Python之中是一个tuple,从这里也可以看出,所谓的闭包本质上就是类属性的一个语法糖。

    这里闭包解决了编程工作之中的两个痛点:

    • (1)突破了函数访问变量的作用域。
    • (2)可以动态添加函数属性,真是通过这种动态特性,可以让我们实现某些编程任务的时候变得很简洁。
    • (3)函数可定制化更佳,提高了函数的可移植性。

    闭包的作用有很多,可以在python上实现动态代理,如装饰器等.......这里就不展开聊闭包的使用,接下来我们要来重点看看在C++之中是如何实现闭包的。

    2.C++之中的闭包

    C++相对于C的优越点就在于C++能够支持面向对象的特性,C语言之中在语法层面是不能支持闭包的。我们来看看C++之中有几种方式来支持闭包特性:

    • 重载类的operator() 操作符
      第一次看到用法的时候有点震惊,没想到重载()括号操作符之后可以将普通的类转变为Callable对象,当时觉得很Tricky。这种用法其实本质上是其他语法糖的基础,我们来看一看代码:
    class Closure {
    public:
        Closure(int n):num(n){};
        int operator()(int add) {
            return num + add;
        }
    private:
        int num;
    };
    
    
    int main() {
        Closure clu(20);
        cout << clu(50) << endl;
    }
    

    可以看到,重载了()操作符的类Closure摇身一变成为了一个函数,可以直接被调用。同时它也包含了对象成员,通过对象成员保存下来了函数的运行状态

    • lambda表达式
      喜欢函数式编程的同学最喜欢使用的工具了(C++11对于C++来说是一个很重要的版本),lambda表达式可以很方便的让我们定义一个匿名函数,我们来看看怎么用lambda表达式来实现闭包:
    int main() {
        int num = 20;
        function<int(int)> clu = [num](int add) {return num + add;};
        cout << clu(50) << endl;
    }
    

    使用lambda表达式实现同样的功能,代码就简洁明了许多。这里的clu是通过一个匿名类来实现的,所以每个lambda表达式都是独一无二的,我们只能使用function或auto来捕获它。这里lambda表达式通过[]操作符捕获外部变量,并且和函数绑定在了一起。

    • 参数绑定
      bind函数在C++11之中也被加入了标准库,我们来看看通过参数绑定是如何实现闭包的:
    int addNum(int num,int add) {
        return add + num;
    }
    
    int main() {
        auto clu = bind(addNum,placeholders::_1,20);
        cout << clu(50) << endl;
    }
    

    通过bind函数,将20绑定到对应的参数add之上,而每次调用clu函数之时,参数会对应到_1的位置,也就是函数addNum的第一个参数num。通过bind的函数,我们可以将外部变量与和原函数绑定在了一起,并且生成了一个新的函数对象。

    好的,关于C++之中的闭包就和大家聊到这里,希望大家在实际Coding之中可以用好它........

  • 相关阅读:
    PAT Advanced 1073 Scientific Notation (20 分)
    PAT Advanced 1071 Speech Patterns (25 分)
    C++ 正则查找
    PAT Advanced 1022 Digital Library (30 分)
    Linux文件系统及常用命令
    Elasticsearch常用查询
    Sublime Text3 快捷键
    Lua函数
    线程池
    Jdk8新特性之Base64
  • 原文地址:https://www.cnblogs.com/happenlee/p/8427254.html
Copyright © 2020-2023  润新知