原本說好要聊一聊命名空間的,由於最近在看C++lambda表達式的內容,因此借這個機會咱們來好好聊一聊C++的閉包。python
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)
打印結果爲:app
10 //funcA的閉包變量 abc //funcB的閉包變量
由上述兩個函數咱們看到變量做爲一種狀態嵌入到函數由getFun返回的函數之中。不一樣的語言實現閉包的方式不一樣。Python以函數對象爲基礎,爲閉包是經過函數對象的屬性來保存閉包的變量。(這裏在Python之中是一個tuple,從這裏也能夠看出,所謂的閉包本質上就是類屬性的一個語法糖。)函數式編程
這裏閉包解決了編程工做之中的兩個痛點:函數
- (1)突破了函數訪問變量的做用域。
- (2)能夠動態添加函數屬性,真是經過這種動態特性,可讓咱們實現某些編程任務的時候變得很簡潔。
- (3)函數可定製化更佳,提升了函數的可移植性。
閉包的做用有不少,能夠在python上實現動態代理,如裝飾器等.......這裏就不展開聊閉包的使用,接下來咱們要來重點看看在C++之中是如何實現閉包的。工具
2.C++之中的閉包
C++相對於C的優越點就在於C++可以支持面向對象的特性,C語言之中在語法層面是不能支持閉包的。咱們來看看C++之中有幾種方式來支持閉包特性:spa
- 重載類的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搖身一變成爲了一個函數,能夠直接被調用。同時它也包含了對象成員,經過對象成員保存下來了函數的運行狀態。.net
- 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之中能夠用好它........
本文同步分享在 博客「HappenLee」(CNBlog)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。