c 中仿函式的理解

2021-08-17 15:45:47 字數 3279 閱讀 1254

2023年11月11日 17:47:25

1341人閱讀收藏 

舉報c++基礎(7)

先考慮乙個簡單的例子:假設有乙個vector,你的任務是統計長度小於5的string的個數,如果使用count_if函式的話,你的**可能長成這樣:

1

bool lengthislessthanfive(const string& str)

4int res=count_if(vec.begin(), vec.end(), lengthislessthanfive);

其中count_if函式的第三個引數是乙個函式指標,返回乙個bool型別的值。一般的,如果需要將特定的閾值長度也傳入的話,我們可能將函式寫成這樣:

1

bool lenthislessthan(const

string& str, int

len)

這個函式看起來比前面乙個版本更具有一般性,但是他不能滿足count_if函式的引數要求:count_if要求的是unary function(僅帶有乙個引數)作為它的最後乙個引數。所以問題來了,怎麼樣找到以上兩個函式的乙個折中的解決方案呢?

這個問題其實可以歸結於乙個data flow的問題,要設計這樣乙個函式,使其能夠access這個特定的length值,回顧我們已有的知識,有2種解決方案可以考慮:

1、函式的引數;

這種方法我們已經討論過了,多個引數不適用於count_if函式。

2、全域性變數;

我們可以將長度閾值設定成乙個全域性變數,**可能像這樣:

1

int maxlength;

2bool lengthislessthan(const string& str)

5int res=count_if(vec.begiin(), vec.end(), lengthislessthan);

這段**看似很不錯,實則不符合規範,剛重要的是,它不優雅。原因有以下幾點要考慮:

1、容易出錯;

為什麼這麼說呢,我們必須先初始化maxlength的值,才能繼續接下來的工作,如果我們忘了,則可能無法得到正確答案。此外,變數maxlength和函式lengthislessthan之間是沒有必然聯絡的,編譯器無法確定在呼叫該函式前是否將變數初始化,給碼農平添負擔。

2、沒有可擴充套件性;

如果我們每遇到乙個類似的問題就新建乙個全域性變數,尤其是多人合作寫**時,很容易引起命名空間汙染(namespace polution)的問題;當範圍域內有多個變數時,我們用到的可能不是我們想要的那個。

3、全域性變數的問題;

每當新建乙個全域性變數,即使是為了coding的便利,我們也要知道我們應該盡可能的少使用全域性變數,因為它的cost很高;而且可能暗示你這裡有一些待解決的優化方案。

說了這麼多,還是要回到我們原始的那個問題,有什麼解決方案呢?答案當然就是這篇blog的正題部分:仿函式。

我們的初衷是想設計乙個unary function,使其能做binary function的工作,這看起來並不容易,但是仿函式能解決這個問題。

先來看仿函式的通俗定義:仿函式(functor)又稱為函式物件(function object)是乙個能行使函式功能的類。仿函式的語法幾乎和我們普通的函式呼叫一樣,不過作為仿函式的類,都必須過載operator()運算子,舉個例子:

1

class func

6 };

1 func myfunc;

2 myfunc("helloworld!");

>>>helloworld!

仿函式其實是上述解決方案中的第四種方案:成員變數。成員函式可以很自然的訪問成員變數:

2public:

3 explicit

string& str) : ss(str){} 45

void

operator() (const

string& str) const 89

private:

10 const

string ss;

11 };

1214 myfunc("hello");

>>>hellois world

我相信這個例子能讓你體會到一點點仿函式的作用了;它既能想普通函式一樣傳入給定數量的引數,還能儲存或者處理更多我們需要的有用資訊。

讓我們回到count_if的問題中去,是不是覺得問題變得豁然開朗了?

1 class shorterthan 

4bool

operator() (const

string& str) const

7private:

8 const

int length;

9 };

1 count_if(myvector.begin(), myvector.end(), shorterthan(length));//直接呼叫即可
這裡需要注意的是,不要糾結於語法問題:shorterthan(length)似乎並沒有呼叫operator()函式?其實它呼叫了,建立了乙個臨時物件。你也可以自己加一些輸出語句看一看。

這篇博文就先記到這裡了,仿函式也在stl中大量涉及到,不徹底弄懂仿函式的問題看到stl原始碼就會一頭包。後續可能再分享一些關於functor的資料和個人學習心得。

**原因:這個用例對仿函式的用處解釋的比較清楚,其實相比用函式指標去處理,仿函式多了很多的靈活性,而且stl中也預先實現了一些仿函式,需要包頭檔案#include

**********=2017.9.18補充**********=== 

在c++11裡面可以通過lambda表示式解決上述問題:

#include 

#include

#include

#include

using

namespace

std;

int main()

; int x = 5;

int k=std::count_if(c.begin(), c.end(), [x](int n));

cout

<< k << endl;

return

0;}

比仿函式方便多了:)

在C 中對仿函式的理解

先考慮乙個簡單的例子 假設有乙個vector,你的任務是統計長度小於5的string的個數,如果使用count if函式的話,你的 可能長成這樣 bool lengthislessthanfive const string str int res count if vec.begin vec.end...

仿函式 C 中仿函式的應用

仿函式 c 中仿函式的應用 在使用仿函式的時候,主要用到以下兩種 一種是以基類std unary function派生出來的派生類 另一種是以基類std binary function派生出來的派生類。而這兩種有什麼區別呢?它們之間的區別只是第一種接收的引數個數為乙個,而第二種接收的引數的個數為兩個...

理解仿函式

1 考慮下面的需求,vector中放置person,person有age和name欄位。在vector中查詢第乙個person c,這個很簡單,方法如下 vector iterator iter find personvector.begin personvector.end c 注意 find演算...