zoukankan      html  css  js  c++  java
  • 局部类实现C++的闭包

    首先说明,虽然经常提到闭包,但我对闭包这个概念还真是不清晰,隐约感觉如果函数A中定义并返回了函数B,而函数B在函数A之外仍然可以正常运行并访问函数A中定义的变量,同时函数A中定义的变量不能被外部访问,就叫闭包——如果这个理解错了,那就当我啥也没说!

    看到有人写博说通过C++11的新特性std::bind来实现闭包,仔细想了一下,其实通过C++03的两个特性就可以实现的:一个是局部类,一个是静态局部变量。

    静态局部变量

    C++允许在函数内部定义静态的局部变量,这些变量不会在离开函数时被销毁,就像这样

    1. void func() { 
    2.     static int i = 0; 
    3.     cout << i++ << endl; 

    如果多次调用func,会发现输出到控制台的值一直在递增。

    局部类 

    想在函数里定义局部函数是不可能的,C++没这个语法。但是可以在函数里定义局部类,这个类只能在该函数里使用,很有意思的,就像这样

    1. void func() { 
    2.     class LocalClass { 
    3.     private: 
    4.         // 定义私有成员 
    5.     public: 
    6.         void run() { 
    7.             // ...... 
    8.         } 
    9.     } obj; 
    10.     obj.run(); 

    如果需要将局部类对象返回到外面,就需要定义一个接口,用于接收返回的对象并调用其中的方法;同时,在函数内需要使用new来生成对象并返回其指针,就像这样

    1. class ILocal { 
    2. public: 
    3.     virtual void run() = 0; 
    4. }; 
    5.  
    6. ILocal* func() { 
    7.     class LocalClass: public ILocal { 
    8.     public: 
    9.         virtual void run() { 
    10.             // ...... 
    11.         } 
    12.     }; 
    13.     return new LocalClass(); 

    基础知识具备了,下面来实现闭包,过程就不说了,看注释吧

    1. #include <iostream> 
    2. using namespace std; 
    3.  
    4. //////// 接口法实现 //////////////////////////////////////// 
    5. // 定义一个函数对象接口……就像C#的委托 
    6. class ITest { 
    7. public: 
    8.     // 定义这个运算符主要是为了像函数一样调用,就像这样:obj(); 
    9.     void operator() () { 
    10.         process(); 
    11.     } 
    12.  
    13. protected: 
    14.     // 接口函数 
    15.     virtual void process() = 0; 
    16. }; 
    17.  
    18. // 下面函数返回一个ITest对象指针 
    19. ITest* test() { 
    20.     // 函数内的静态变量,离开函数也不会销毁,而且可以 
    21.     static int count = 0; 
    22.  
    23.     // 定义一个局部类 
    24.     class Test: public ITest { 
    25.     public: 
    26.         // 实现ITest中定义的接口函数来实现操作 
    27.         virtual void process() { 
    28.             cout << "Count is " << count++ << endl; 
    29.         } 
    30.     }; 
    31.  
    32.     // 返回一个新的对象……这里必须得new,你懂的 
    33.     return new Test(); 
    34.  
    35. //////// 函数法实现 //////////////////////////////////////// 
    36. // 定义测试函数指针类型 
    37. typedef void (*Func)(const char*); 
    38.  
    39. // 下面函数返回一个闭包中的函数 
    40. Func testFunc() { 
    41.     // 静态局部变量初始化为100 
    42.     static int count = 100; 
    43.     // 静态局部常量 
    44.     static const char* const NAME = "James"; 
    45.  
    46.     // 不能直接定义函数,只好定义局部类的静态方法,并返回其指针 
    47.     class Test { 
    48.     public: 
    49.         // 这个定义说明可以传入参数,同理也可以有返回值 
    50.         static void process(const char* pName = NULL) { 
    51.             if (pName == NULL) { pName = NAME; } 
    52.             cout << pName << " Count is " << count-- << endl; 
    53.         } 
    54.     }; 
    55.     return Test::process; 
    56.  
    57. //////// 程序入口:主函数 ////////////////////////////////// 
    58. int main(int argc, char* argv[]) { 
    59.     ITest* pT = test(); 
    60.     Func pF = testFunc(); 
    61.  
    62.     // 多次调用得从函数里返回出来的函数和对象,观察结果 
    63.     for (int i = 0; i < 10; i++) { 
    64.         (*pT)(); 
    65.         pF((i % 2 == 0) ? NULL : "Fancy"); 
    66.     } 

    给个运行结果

    1. Count is 0 
    2. James Count is 100 
    3. Count is 1 
    4. Fancy Count is 99 
    5. Count is 2 
    6. James Count is 98 
    7. Count is 3 
    8. Fancy Count is 97 
    9. Count is 4 
    10. James Count is 96 
    11. Count is 5 
    12. Fancy Count is 95 
    13. Count is 6 
    14. James Count is 94 
    15. Count is 7 
    16. Fancy Count is 93 
    17. Count is 8 
    18. James Count is 92 
    19. Count is 9 
    20. Fancy Count is 91 

    C++是门非常灵活的语言,我们平时用到的相对于C++ Specification来说,仅仅是冰山一角。虽然因为工作关系我已经有四五年没用它了,但它依然是我最喜欢的语言之一。

  • 相关阅读:
    获取屏幕分辨率
    String-去除-指定-字符-操作
    Log4j配置详述
    Java-String-数据乱码
    javascript高级课程-3
    javascript高级课程-2
    javascript高级课程-1
    设计一个算法双链表删除重复
    设计一个算法将一个顺序表逆置
    w3c标准
  • 原文地址:https://www.cnblogs.com/xiangcunjiaoshi/p/12560247.html
Copyright © 2011-2022 走看看