C 學習筆記 (函式物件(仿函式))

2021-10-07 13:47:19 字數 2755 閱讀 7559

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

bool

lengthislessthanfive

(const string& str)

int res=

count_if

(vec.

begin()

, vec.

end(

), lengthislessthanfive)

;

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

bool

lenthislessthan

(const string& str,

int len)

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

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

1、函式的區域性變數;

區域性變數不能在函式呼叫中傳遞,而且caller無法訪問。

2、函式的引數;

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

3、全域性變數;

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

int maxlength;

bool

lengthislessthan

(const string& str)

int 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()運算子,舉個例子:

class

func};

func myfunc;

myfunc

("helloworld!");

>>

>helloworld!

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

class

void

operator()

(const string& str)

const

private

:const string ss;};

("is world");

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()函式?其實它呼叫了,建立了乙個臨時物件。你也可以自己加一些輸出語句看一看。

引用:

c 學習 函式物件(仿函式)

過載函式呼叫操作符 的類,其物件常稱為函式物件 function object 即它們是行為類似函式的物件,也叫仿函式 functor 其實就是過載 操作符,使得類物件可以像函式那樣呼叫。注 1 函式物件 仿函式 是乙個類,不是乙個函式 2 函式物件 仿函式 過載了 操作符使得它可以像函式一樣呼叫。...

C 函式物件 仿函式

概念 模仿函式的類,使用方式如同函式 本質 函式物件是乙個類,類中對小括號 進行了函式過載。仿函式主要用於stl中的演算法中,函式指標雖然也可以作為演算法的引數,但它不能滿足stl對抽象性的要求,也不能滿足軟體積木的要求 函式指標無法和stl其他元件搭配,產生更靈活變化。案例 如下 include ...

stl 仿函式 函式物件

定義 stl原始碼剖析 仿函式其實上就是乙個 行為類似函式 的物件。即主體是物件,只是使用起來像乙個函式。傳遞函式指標 templatebool compare to const t x,const t y templatevoid print compare t fun int main 傳遞的是...