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演算...