<STL源碼剖析>閱讀筆記之 仿函數(shù)和適配器仿函數(shù)(函數(shù)對象)和適配器可以說是STL中默默無聞的貢獻(xiàn)者,,它們沒有容器、算法和迭代器那么有名 但是其貢獻(xiàn)卻很大,。這里總結(jié)的主要是書中第7,、8章的內(nèi)容,。 一 仿函數(shù) 仿函數(shù)又稱函數(shù)對象,,從名字上可以得出,它本質(zhì)上是 一種具有函數(shù)特質(zhì)的對象,, 也即可以像使用函 數(shù)一樣使用該對象,。怎么樣做?重載operator()運(yùn)算符即可,,有了這個(gè)運(yùn)算符,,我們就可以在仿函數(shù)對象后 面加上一對小括號,以此調(diào)用仿函數(shù)所定義的operator(),。STL仿函數(shù)可以分為一元和二元,,或者算術(shù)運(yùn) 算、關(guān)系運(yùn)算和邏輯運(yùn)算,。 為什么要有仿函數(shù),?在算法的設(shè)計(jì)過程中,我們會(huì)發(fā)現(xiàn)其本質(zhì)往往是不變的(例如排序算法的思想),,變 化的除了數(shù)據(jù)之外還有操作(例如排序中不一定是比較大小,,也可以是兩兩之間滿足某種關(guān)系),,仿函數(shù)就 是為了這種情況產(chǎn)生的,它替代原來需要函數(shù)指針的地方,,把這種操作或者策略傳給算法,,使得算法抽象性 更高,也就更通用,。 為什么不用函數(shù)指針,?很簡單的解釋是抽象性不夠,更進(jìn)一步說是它無法配接,,也就是可以將操作配接在 一起變換為更復(fù)雜的操作(例如compose和bind1st等等方法),,仿函數(shù)則可以輕松實(shí)現(xiàn)這些配接,使得其功 能異常強(qiáng)大,。 仿函數(shù)在實(shí)現(xiàn)上是一個(gè)結(jié)構(gòu)體,,并且如上所述重載了operator()運(yùn)算符,所有的仿函數(shù)如果是一元的都繼 承自unary_function,,二元?jiǎng)t繼承自binary_function,因?yàn)槔^承自這兩個(gè)函數(shù)的仿函數(shù)均定義了相應(yīng)型別供 配接時(shí)使用,,也就具有了配接能力。 template <class Arg, class Result> 從以上代碼可以看到,,這兩個(gè)類僅僅只是定義了相應(yīng)型別,,至于STL內(nèi)置的仿函數(shù)則僅僅是重載了()運(yùn) 算,很簡單:
二 適配器 適配器也是一種常用的設(shè)計(jì)模式: 將一個(gè)class的接口轉(zhuǎn)換為另一個(gè)class的接口,,使得原本因接口不兼容 而不能合作的classes可以一起運(yùn)作。一個(gè)通俗的例子是我們筆記本的電源,,一般都會(huì)有一個(gè)適配器把220v 的電壓降到適合筆記本工作的電壓范圍,,這樣筆記本就可以工作在我們常用的電壓環(huán)境了,這就擴(kuò)大了筆記 本的使用場景,,在軟件開發(fā)過程中也是一樣的道理,。 STL提供三種適配器:改變?nèi)萜鹘涌诘娜萜鬟m配器、改變迭代器接口的迭代器適配器以及改變仿函數(shù)接口 的仿函數(shù)適配器,。前兩者都較為簡單,,而最后一種則是靈活性最大的,有了它我們可以構(gòu)造非常復(fù)雜的表達(dá) 式策略,。 容器適配器常見的是stack和queue,,他們的底層存儲(chǔ)都是用deque完成的,再在deque上封裝一層接口以 滿足stack和queue的要求,。 迭代器適配器大致有三種對應(yīng)不同的迭代器行為,,它們以某容器為參數(shù),直接對容器的迭代器進(jìn)行封 裝,,主要有back_insert_iterator,、front_insert_iterator,、insert_iterator以及reverse_iterator。 從上面兩個(gè)適配器看,,其原理都是在其內(nèi)部有一個(gè)原來要適配的成員變量,,通過改變接口來實(shí)現(xiàn),那么仿 函數(shù)的適配器也不例外,。常用的是bind1st,bind2nd,not1,compose1,compose2等等,,這些適配器都是仿函數(shù) 同時(shí)以要適配的仿函數(shù)作為member object。 仿函數(shù)適配器的實(shí)現(xiàn)主要包括兩塊,,自身的類以及方便使用的函數(shù),,以bind1st為例,它的作用是綁定二 元仿函數(shù)的第一個(gè)參數(shù)為某指定值,。首先是其定義:
仿函數(shù)適配器第二個(gè)部分是方便使用的函數(shù),以讓我們可以像普通函數(shù)一樣使用適配器,,并通過函數(shù)模板 的參數(shù)推導(dǎo)功能來創(chuàng)建適配器對象,。 template <class Operation, class T>inline binder1st<Operation> bind1st(const Operation& op, const T& x) {typedef typename Operation::first_argument_type arg1_type;return binder1st<Operation>(op, arg1_type(x));//返回對象} 適配器很巧妙的構(gòu)造了這樣一種對象嵌套對象的結(jié)構(gòu)來使得我們可以構(gòu)造很復(fù)雜的語義,這也是函數(shù)指針 所不具備的,,當(dāng)然對于函數(shù)指針STL也提供了ptr_fun來將其變?yōu)楹瘮?shù)對象以獲得適配功能,,成員函數(shù)得使用 mem_fun,mem_fun_ref。
總的來說,,通過對適配器和仿函數(shù)的學(xué)習(xí)我們看到了STL里面精妙的封裝,,以及對高度抽象的追求,也正 是這些高度抽象使得它更加通用性,。有了這些知識,,我們可以利用系統(tǒng)的迭代器構(gòu)造自己的迭代器,來擴(kuò)展 STL的功能,。 |
|