首先說明,雖然經常提到閉包,但我對閉包這個概念還真是不清晰,隱約感覺如果函數A中定義並返回了函數B,而函數B在函數A之外仍然可以正常運行並訪問函數A中定義的變量,同時函數A中定義的變量不能被外部訪問,就叫閉包——如果這個理解錯了,那就當我啥也沒說!
看到有人寫博說通過C++11的新特性std::bind來實現閉包,仔細想了一下,其實通過C++03的兩個特性就可以實現的:一個是局部類,一個是靜態局部變量。
靜態局部變量
C++允許在函數內部定義靜態的局部變量,這些變量不會在離開函數時被銷毀,就像這樣
- void func() {
- static int i = 0;
- cout << i++ << endl;
- }
如果多次調用func,會發現輸出到控制台的值一直在遞增。
局部類
想在函數裡定義局部函數是不可能的,C++沒這個語法。但是可以在函數裡定義局部類,這個類只能在該函數裡使用,很有意思的,就像這樣
- void func() {
- class LocalClass {
- private:
- // 定義私有成員
- public:
- void run() {
- // ......
- }
- } obj;
- obj.run();
- }
如果需要將局部類對象返回到外面,就需要定義一個接口,用於接收返回的對象並調用其中的方法;同時,在函數內需要使用new來生成對象並返回其指針,就像這樣
- class ILocal {
- public:
- virtual void run() = 0;
- };
- ILocal* func() {
- class LocalClass: public ILocal {
- public:
- virtual void run() {
- // ......
- }
- };
- return new LocalClass();
- }
基礎知識具備了,下面來實現閉包,過程就不說了,看注釋吧
- #include <iostream>
- using namespace std;
- //////// 接口法實現 ////////////////////////////////////////
- // 定義一個函數對象接口……就像C#的委托
- class ITest {
- public:
- // 定義這個運算符主要是為了像函數一樣調用,就像這樣:obj();
- void operator() () {
- process();
- }
- protected:
- // 接口函數
- virtual void process() = 0;
- };
- // 下面函數返回一個ITest對象指針
- ITest* test() {
- // 函數內的靜態變量,離開函數也不會銷毀,而且可以
- static int count = 0;
- // 定義一個局部類
- class Test: public ITest {
- public:
- // 實現ITest中定義的接口函數來實現操作
- virtual void process() {
- cout << "Count is " << count++ << endl;
- }
- };
- // 返回一個新的對象……這裡必須得new,你懂的
- return new Test();
- }
- //////// 函數法實現 ////////////////////////////////////////
- // 定義測試函數指針類型
- typedef void (*Func)(const char*);
- // 下面函數返回一個閉包中的函數
- Func testFunc() {
- // 靜態局部變量初始化為100
- static int count = 100;
- // 靜態局部常量
- static const char* const NAME = "James";
- // 不能直接定義函數,只好定義局部類的靜態方法,並返回其指針
- class Test {
- public:
- // 這個定義說明可以傳入參數,同理也可以有返回值
- static void process(const char* pName = NULL) {
- if (pName == NULL) { pName = NAME; }
- cout << pName << " Count is " << count-- << endl;
- }
- };
- return Test::process;
- }
- //////// 程序入口:主函數 //////////////////////////////////
- int main(int argc, char* argv[]) {
- ITest* pT = test();
- Func pF = testFunc();
- // 多次調用得從函數裡返回出來的函數和對象,觀察結果
- for (int i = 0; i < 10; i++) {
- (*pT)();
- pF((i % 2 == 0) ? NULL : "Fancy");
- }
- }
給個運行結果
- Count is 0
- James Count is 100
- Count is 1
- Fancy Count is 99
- Count is 2
- James Count is 98
- Count is 3
- Fancy Count is 97
- Count is 4
- James Count is 96
- Count is 5
- Fancy Count is 95
- Count is 6
- James Count is 94
- Count is 7
- Fancy Count is 93
- Count is 8
- James Count is 92
- Count is 9
- Fancy Count is 91
C++是門非常靈活的語言,我們平時用到的相對於C++ Specification來說,僅僅是冰山一角。雖然因為工作關系我已經有四五年沒用它了,但它依然是我最喜歡的語言之一。
本文出自 “邊城客棧 學海無涯” 博客,請務必保留此出處http://jamesfancy.blog.51cto.com/2516291/1166900