1. 程式人生 > >C++中仿函式/函式物件,函式指標的用法

C++中仿函式/函式物件,函式指標的用法

研究這個起因是這樣的,就是今天在用priority_queue的時候,需要自定義比較函式,但是此時又不能修改需要比較的類的內容(即不能用過載<的方法),所以只能寫在外面,但是發現這樣並不能編譯通過。報的錯叫cmp(我寫的那個比較函式)不是型別名。後來查了下資料發現,這個需要用比較類去完成,比較類需要過載()方法,所以這個事情就非常引起我的好奇,想要知道一下,為什麼sort這樣的函式就可以直接用函式名,而priority_queue就不行呢

基本概念

首先先要了解幾個概念:函式物件/仿函式,函式指標,Lambda表示式

函式物件/仿函式

函式物件(function object)又叫仿函式(functor),就是過載了呼叫運算子

()的類,所生成的物件,就叫做函式物件/仿函式。因為過載了()之後,我們就能像函式一樣去使用這個類,同時類裡面又可以儲存一些資訊,所以要比普通的函式更加靈活。
就像,下面的就是一個比較類:

class comp_class {
public:
    bool operator()(const B& a,const B& b) {
        return a.a < b.a;
    }
};

函式指標

首先,函式指標也是一個函式物件,因為指標在C++中都是物件。

lambda表示式

lambda表示式的用法,我單獨放偏部落格來講吧,這個坑先留著。這裡就記住lambda也是一個函式物件

就行了。

STL函式和STL容器

開頭說到的sort就是STL函式(STL function),而priority_queue就是STL容器(STL containers)。
跟priority_queue類似的帶著比較函式的容器還有set和map。記住STL容器中<>裡面傳入的一定是型別名稱,不能是具體的例項。

程式例子

回到我們最開始的問題上,以set和sort為例

class B {
public:
    int a;
    int b;
    B(int _a,int _b):a(_a), b(_b) {};
};
class comp_class
{
public: bool operator()(const B& a,const B& b) { return a.a < b.a; } }; const bool comp_function(const B& a,const B &b) { return a.a < b.a; }

然後以下是正確用法的有
對於set類

//傳入比較類的
set<B, comp_class> A_set;
set<B, comp_class> A_set(comp_class ());
//傳入函式指標的
set<B, const bool(*)(const B& a, const B &b)> A_set(comp_function);//記住引數一定要嚴格匹配,包括const
//還可以這麼寫,簡化宣告,
set<B, decltype(comp_function)*> A_set(comp_function);

注意此時一定要寫*,因為用decltype來獲得一個函式指標型別時,其只返回函式型別,而非指標型別,所以這個地方要顯示的加上 * 表明這裡是函式指標.

對於sort函式的傳入

//傳入比較類的
sort(A_vector.begin(), A_vector.end()comp_class());    //注意後面的括號一定不能省略
//傳入函式指標的
sort(A_vector.begin(), A_vector.end(),comp_function);

結論

所以開頭中提到的問題,這裡其實就已經非常明白了,我在查資料的時候,一直就坑在了這個地方,後來恍然大悟.
其實對於sort和set需要傳進去的東西都是一致的.
只不過set中間需要定義的是類別模板而不是具體的比較函式,
所以其實set裡面傳入函式也是可以的,只不過在<>中需要寫的不是具體函式名,而是這個函式指標的型別,然後用那個具體的函式來初始化set.就像我上面寫的那樣.
而對於sort來說,因為其本身就是一個函數了,所以傳進去具體的比較函式例項就可以.
同理,如果再sort中傳入的是型別也是不可以的,所以需要傳入一個具體的例項,就像上面的那個sort必須要加()來給它例項化