STL不但使我們能夠更輕松、更快捷地編寫復(fù)雜的代碼,而且使編寫的代碼既標(biāo)準(zhǔn)又高度優(yōu)化。
std::vector<std::string> names;
// ...
std::sort(names.begin(), names.end());
STL另一個優(yōu)雅之處在于高度可配置。在以上的代碼中,使用string的小于(<)操作符對vector中的string元素進行排序,但在其它場合,未必總有一個小于操作符可供使用,而且有時并不希望以升序方式進行排序。
class State
{
public:
// ...
int population() const;
float aveTempF() const;
// ...
};
State類用于表示聯(lián)邦的一個州,它沒有小于操作符,而且也不打算為它實現(xiàn)一個,因為“一個州小于另一個州”說不清是什么意思。幸運的是,對于這樣的情形來說,STL一般允許我們指定一個替代的類似小于操作符(less-than-like)的操作。這樣的操作被稱為“比較器”,因為它用于比較兩個值:
inline bool popLess(const State& a, const State& b)
{
return a.population() < b.population();
}
擁有針對State的比較器之后,就可以用它進行排序了:
State aUnion[50];
// ...
std::sort(aUnion, aUnion + 50, popLess); // 按人口數(shù)進行排序
這里我們傳遞一個指向popLess函數(shù)的指針作為比較器(函數(shù)名字會退化成一個指針)。因為popLess作為函數(shù)指針進行傳遞,所以它在sort內(nèi)無法被內(nèi)聯(lián)。如果希望得到快速的排序操作,這種做法只能讓人感到遺憾了。
如果使用函數(shù)對象作為比較器,情況就會好很多:
struct PopLess : public std::binary_function<State, State, bool>
{
bool operator () (const State& a, const State& b) const
{
return a.population() < b.population();
}
};
PopLess類型是一個典型的、有著正確構(gòu)造的STL函數(shù)對象的例子。
首先,它是一個函數(shù)對象。它重載了函數(shù)調(diào)用操作符,因此可以以普通函數(shù)調(diào)用的語法調(diào)用。這一點很重要,因為諸如sort這樣的STL泛型算法是以這種方式編寫的:函數(shù)指針和函數(shù)對象都可以用來實例化它們,只要此二者可以采用典型的函數(shù)調(diào)用語法進行調(diào)用即可。一個具有重載的operator()的函數(shù)對象完全可以滿足這個語法要求。
其次,它派生于標(biāo)準(zhǔn)的binary_function基類。此項機制允許其它部分的STL實現(xiàn)詢問函數(shù)對象編譯器問題。在這個例子中,從binary_function派生下來的PopLess類型允許我們找出函數(shù)對象的參數(shù)和返回值類型。不過在這里我們并沒有利用這種能力,但是可以打賭肯定有人需要這樣的能力,而且希望我們的PopLess類型可以為其他人所用。
第三,這個函數(shù)對象沒有數(shù)據(jù)成員、沒有虛函數(shù)、沒有顯示聲明的構(gòu)造函數(shù)和析構(gòu)函數(shù),且對operator()的實現(xiàn)是內(nèi)聯(lián)的。用作STL比較器的函數(shù)對象一般都很小巧。簡單且快速。當(dāng)然可以設(shè)計一個具有重型實現(xiàn)的STL函數(shù)對象,但這種做法通常不是明智之舉。當(dāng)與STL協(xié)同使用時,在函數(shù)對象中避免(或盡量少)使用數(shù)據(jù)成員的另一個原因在于,STL實現(xiàn)可能為會一個函數(shù)對象產(chǎn)生若干份復(fù)制,而且假定所有這些復(fù)制都是一致的。為了確保一個對象的所有復(fù)制一致,最簡單的方式就是不要讓對象帶有任何數(shù)據(jù)成員。
現(xiàn)在我們就可以使用該函數(shù)對象對這個aUnion進行排序:
std::sort(aUnion, aUnion + 50, PopLess()); // 按人口數(shù)進行排序
請注意在這個sort調(diào)用中跟在PopLess后面的圓括號。PopLess是一個類型,但是我們必須傳入一個該類型的對象作為函數(shù)的參數(shù)。通過在PopLess類型名字后面附加一對圓括號,就創(chuàng)建了一個沒名字的臨時PopLess對象,此對象僅存活于函數(shù)調(diào)用期間(這個沒名字的對象即總所周知的“匿名臨時對象”)。也可以聲明并傳入一個具名對象:
PopLess comp;
std::sort(aUnion, aUnion + 50, comp); // 按人口數(shù)進行排序
然而,傳入一個匿名臨時對象更簡單、更符合習(xí)慣,而且擊鍵次數(shù)更少。
使用函數(shù)對象作為比較器還有一個額外的好處,就是比較操作將被內(nèi)聯(lián)處理,而使用函數(shù)指針則不允許內(nèi)聯(lián)。原因在于,當(dāng)一個sort函數(shù)模板實例化時,編譯器知道比較器的類型是PopLess,從而使它知道PopLess:operator()將被調(diào)用,接著使它可以內(nèi)聯(lián)該函數(shù)。
在STL中,函數(shù)對象另一個常見的用途是用作判斷式。判斷式是一個詢問關(guān)于單個對象的真/假問題的操作(可以將比較器視作一種二元判斷式)。
struct IsWarm : public std::unary_function<State, bool>
{
bool operator () (const State& a) const
{
return a.aveTempF() > 60;
}
};
STL判斷式的設(shè)計知道方針與STL比較器的一致,唯一的例外在于,前者是一元函數(shù),而非二元函數(shù)。從我們前面排過序的State結(jié)果開始,采用一個適當(dāng)?shù)呐袛嗍剑梢宰屛覀兒苋菀拙湍苷业揭粋€氣候溫暖且人數(shù)較少的州:
State* warmandsparse = find_if(aUnion, aUnion + 50, IsWarm());
posted on 2011-06-29 08:46
水 閱讀(2894)
評論(1) 編輯 收藏 引用 所屬分類:
c/c++基礎(chǔ)知識