局部类实现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 charconst 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来说,仅仅是冰山一角。虽然因为工作关系我已经有四五年没用它了,但它依然是我最喜欢的语言之一。



本文转自边城__ 51CTO博客,原文链接:http://blog.51cto.com/jamesfancy/1166900,如需转载请自行联系原作者

相关文章
|
7天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
21 2
|
13天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
40 5
|
19天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
49 4
|
20天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
46 4
|
2月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
28 4
|
2月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
25 4
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
22 1
|
2月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
2月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
17 0
|
2月前
|
存储 编译器 C语言
深入计算机语言之C++:类与对象(上)
深入计算机语言之C++:类与对象(上)