仿函數(shù)C++-創(chuàng)新互聯(lián)

仿函數(shù)

為什么我們需要使用仿函數(shù)(仿函數(shù)解決了什么痛點(diǎn))?

成都創(chuàng)新互聯(lián)2013年至今,先為羅平等服務(wù)建站,羅平等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為羅平企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

仿函數(shù)的優(yōu)點(diǎn)和作用?

文章目錄
  • 仿函數(shù)
    • 為什么需要仿函數(shù)
      • 場(chǎng)景一
      • 場(chǎng)景二
    • 仿函數(shù)是什么
      • 具體定義
      • 實(shí)例
          • 直接調(diào)用仿函數(shù)
          • 仿函數(shù)作為函數(shù)入?yún)?/li>
    • 仿函數(shù)和STL
        • 算術(shù)仿函數(shù)
        • 關(guān)系運(yùn)算符
        • 邏輯運(yùn)算符
    • 仿函數(shù)和智能指針
        • 仿函數(shù)自定義刪除器
        • 智能指針中的仿函數(shù)

為什么需要仿函數(shù) 場(chǎng)景一
  • 場(chǎng)景引入

  • 計(jì)算a數(shù)組里面全部的和,放在x變量里面。

#include#include#include

using namespace std;

templateinline T accumulate(InputIterator first, InputIterator last, T init, T (*ptrA)(T, T)) {//函數(shù)指針
    while (first != last) {init = (*ptrA)(init, *first);
        ++first;
    }

    return init;
}

int funcA(int x, int y)
{return x + y;
}

int main(void) 
{int a[5] = {2, 5, 7, 9, 11};

    random_shuffle(&a[0], &a[5]);
    int x = ::accumulate(&a[0], &a[5], 0, funcA);
    cout<< x<< endl;

    return 0;
}
  • 這里就是計(jì)算a數(shù)組里面全部的和,放在x變量里面。
  • ? 首先,這個(gè)函數(shù)的原型是T (*ptrA)(T x, T y);如果我想提升我處理數(shù)據(jù)的速度,讓時(shí)間少浪費(fèi)由于函數(shù)值傳遞引起的拷貝上,于是我需要這樣寫(xiě)函數(shù) T funcA(const int& x, const int& y)。這樣寫(xiě)的話,我們?cè)瓉?lái)的函數(shù)T (*ptrA)(T x, T y)就不能匹配這個(gè)函數(shù),于是我們就要重載函數(shù)。還有就是效率問(wèn)題,函數(shù)指針的調(diào)用,我們的電腦需要做很多工作,比如說(shuō)保存當(dāng)前的寄存器值,傳遞參數(shù),返回值,返回到函數(shù)調(diào)用地方繼續(xù)執(zhí)行等。
  • 幸運(yùn)的是,這一切問(wèn)題都可以通過(guò)仿函數(shù)來(lái)解決,如下:
#include#include#include

using namespace std;

templateinline T accumulate(InputIterator first, InputIterator last, T init, FunObject object) {//函數(shù)對(duì)象
    while (first != last) {init = object(init, *first);
        ++first;
    }

    return init;
}

template< typename T>class Test {public:
    T operator()(const T& x, const T& y) {return x + y;
    }
};

int main(void) 
{int a[5] = {2, 5, 7, 9, 11};

    random_shuffle(&a[0], &a[5]);
    int x = ::accumulate(&a[0], &a[5], 0, Test());  //仿函數(shù)作為函數(shù)的入?yún)?,只需要傳入?lèi)對(duì)象即可,這里傳入的是匿名對(duì)象
    cout<< x<< endl;

    return 0;
}

這樣就解決了效率和函數(shù)重載的問(wèn)題了。

場(chǎng)景二
  • 假設(shè)我們現(xiàn)在有一個(gè)數(shù)組,數(shù)組中存有任意數(shù)量的數(shù)字,我們希望能夠統(tǒng)計(jì)出這個(gè)數(shù)組中大于 10 的數(shù)字的數(shù)量,你的代碼很可能是這樣的:
#includeusing namespace std;
 
int RecallFunc(int *start, int *end, bool (*pf)(int)) {int count=0;
    for(int *i = start; i != end+1; i++) {count = pf(*i) ? count+1 : count;
    }
    return count;
}
 
bool IsGreaterThanTen(int num) {return num>10 ? true : false;
}
 
int main() {int a[5] = {10,100,11,5,19};
    int result = RecallFunc(a, a+4, IsGreaterThanTen);
    cout<
  • RecallFunc() 函數(shù)的第三個(gè)參數(shù)是一個(gè)函數(shù)指針,用于外部調(diào)用,而 IsGreaterThanTen() 函數(shù)通常也是外部已經(jīng)定義好的,它只接受一個(gè)參數(shù)的函數(shù)。如果此時(shí)希望將判定的閾值也作為一個(gè)變量傳入,變?yōu)槿缦潞瘮?shù):
bool IsGreaterThanThreshold(int num, int threshold) {return num>threshold ? true : false;
}
  • 雖然這個(gè)函數(shù)看起來(lái)比前面一個(gè)版本更具有一般性,但是它不能滿足已經(jīng)定義好的函數(shù)指針參數(shù)的要求,因?yàn)楹瘮?shù)指針參數(shù)的類(lèi)型是bool (*)(int),與函數(shù)bool IsGreaterThanThreshold(int num, int threshold)的類(lèi)型不相符。如果一定要完成這個(gè)任務(wù),按照以往的經(jīng)驗(yàn),我們可以考慮如下可能途徑:

(1)閾值作為函數(shù)的局部變量。局部變量不能在函數(shù)調(diào)用中傳遞,故不可行;

bool IsGreaterThanThreshold(int num) {int threshold; // 這里的threhold 沒(méi)法獲得外部的傳參
	return num>threshold ? true : false;
}

(2)全局變量。我們可以將閾值設(shè)置成一個(gè)全局變量。這種方法雖然可行,但不優(yōu)雅,且容易引入 Bug,比如全局變量容易同名,造成命名空間污染

int threshold=10; // 定義全局變量
bool IsGreaterThanThreshold(int num) {

	return num>threshold ? true : false;
}

(3)函數(shù)傳參。這種方法我們已經(jīng)討論過(guò)了,多個(gè)參數(shù)不適用于已定義好的 RecallFunc() 函數(shù)。(除非你重寫(xiě)函數(shù)指針)

假設(shè)你設(shè)計(jì)的傳參函數(shù)是這樣的:

bool IsGreaterThanThreshold(int num, int threshold) {
	return num>threshold ? true : false;
}

在此基礎(chǔ)上,你必須重寫(xiě) RecallFunc() 函數(shù) 。

int RecallFunc(int *start, int *end, bool (*pf)(int,int),int threshold) {這里就需要引入新參數(shù),來(lái)指threshold。同時(shí)需要重寫(xiě)函數(shù)指針,以使其符合IsGreaterThanThreshold 。
    int count=0;
    for(int *i = start; i != end+1; i++) {count = pf(*i,threshold) ? count+1 : count;
    }
    return count;
}
  1. 這種方法擴(kuò)展性較差,當(dāng)函數(shù)參數(shù)有所變化,則無(wú)法兼容舊的代碼,具體在第一小節(jié)已經(jīng)闡述。正如上面的例子,在我們寫(xiě)代碼時(shí)有時(shí)會(huì)發(fā)現(xiàn)有些功能代碼,會(huì)不斷地被使用。為了復(fù)用這些代碼,實(shí)現(xiàn)為一個(gè)公共的函數(shù)是一個(gè)解決方法。不過(guò)函數(shù)用到的一些變量,可能是公共的全局變量。引入全局變量,容易出現(xiàn)同名沖突,不方便維護(hù)。

  2. 這時(shí)就可以使用仿函數(shù)了,寫(xiě)一個(gè)簡(jiǎn)單類(lèi),除了維護(hù)類(lèi)的基本成員函數(shù)外,只需要重載 operator() 運(yùn)算符 。這樣既可以免去對(duì)一些公共變量的維護(hù),也可以使重復(fù)使用的代碼獨(dú)立出來(lái),以便下次復(fù)用。而且相對(duì)于函數(shù)更優(yōu)秀的性質(zhì),仿函數(shù)還可以進(jìn)行依賴(lài)、組合與繼承等,這樣有利于資源的管理。如果再配合模板技術(shù)和 Policy 編程思想,則更加威力無(wú)窮,大家可以慢慢體會(huì)。Policy 表述了泛型函數(shù)和泛型類(lèi)的一些可配置行為(通常都具有被經(jīng)常使用的缺省值)。

  3. STL 中也大量涉及到仿函數(shù),有時(shí)仿函數(shù)的使用是為了函數(shù)擁有類(lèi)的性質(zhì),以達(dá)到安全傳遞函數(shù)指針、依據(jù)函數(shù)生成對(duì)象、甚至是讓函數(shù)之間有繼承關(guān)系、對(duì)函數(shù)進(jìn)行運(yùn)算和操作的效果。比如 STL 中的容器 set 就使用了仿函數(shù) less ,而 less 繼承的 binary_function,就可以看作是對(duì)于一類(lèi)函數(shù)的總體聲明,這是函數(shù)做不到的。

  • 仿函數(shù)實(shí)現(xiàn)
#includeusing namespace std;
 
class IsGreaterThanThresholdFunctor {public:
	explicit IsGreaterThanThresholdFunctor(int t):threshold(t){}
	bool operator() (int num) const {return num >threshold ? true : false;
	}
private:
	const int threshold;
};
 
int RecallFunc(int *start, int *end, IsGreaterThanThresholdFunctor myFunctor) {int count = 0;
	for (int *i = start; i != end + 1; i++) {count = myFunctor(*i) ? count + 1 : count;
	}
	return count;
}
 
int main() {int a[5] = {10,100,11,5,19};
	int result = RecallFunc(a, a + 4, IsGreaterThanThresholdFunctor(10));//仿函數(shù)作為函數(shù)的入?yún)?,只需要傳入?lèi)對(duì)象即可,這里傳入的是匿名對(duì)象
	cout<< result<< endl;
}
  • 這個(gè)例子應(yīng)該可以讓您體會(huì)到仿函數(shù)的一些作用:它既能像普通函數(shù)一樣傳入給定數(shù)量的參數(shù),還能存儲(chǔ)或者處理更多我們需要的有用信息。于是仿函數(shù)提供了第四種解決方案:成員變量。成員函數(shù)可以很自然地訪問(wèn)成員變量,從而可以解決第一節(jié)“1.為什么要有仿函數(shù)”中提到的問(wèn)題:計(jì)算出數(shù)組中大于指定閾值的數(shù)字?jǐn)?shù)量。
仿函數(shù)是什么 具體定義
  • 仿函數(shù)(Functor)又稱(chēng)為函數(shù)對(duì)象(Function Object)是一個(gè)能行使函數(shù)功能的類(lèi)。

  • 仿函數(shù)的語(yǔ)法幾乎和我們普通的函數(shù)調(diào)用一樣,不過(guò)作為仿函數(shù)的類(lèi),都必須重載 operator() 運(yùn)算符。因?yàn)檎{(diào)用仿函數(shù),實(shí)際上就是通過(guò)類(lèi)對(duì)象調(diào)用重載后的 operator() 運(yùn)算符。

實(shí)例

我們先來(lái)看一個(gè)仿函數(shù)的例子。

直接調(diào)用仿函數(shù)
class StringAppend {public:
    explicit StringAppend(const string& str) : ss(str){}
    void operator() (const string& str) const { cout<< str<< ' '<< ss<< endl;
    }
private:
    const string ss;
};

int main() {StringAppend myFunctor2("and world!");
    myFunctor2("Hello");// 隱式寫(xiě)法
  //   myFunctor2.operator()("Hello"); //顯式寫(xiě)法
   

編譯運(yùn)行輸出:

Hello and world!

仿函數(shù)作為函數(shù)入?yún)?pre>#includeusing namespace std; class IsGreaterThanThresholdFunctor {public: explicit IsGreaterThanThresholdFunctor(int t):threshold(t){} bool operator() (int num) const {return num >threshold ? true : false; } private: const int threshold; }; int RecallFunc(int *start, int *end, IsGreaterThanThresholdFunctor myFunctor) {int count = 0; for (int *i = start; i != end + 1; i++) {count = myFunctor(*i) ? count + 1 : count; } return count; } int main() {int a[5] = {10,100,11,5,19}; int result = RecallFunc(a, a + 4, IsGreaterThanThresholdFunctor(10));//仿函數(shù)作為函數(shù)的入?yún)?,只需要傳入?lèi)對(duì)象即可,這里傳入的是匿名對(duì)象 cout<< result<< endl; }仿函數(shù)和STL
  • 通過(guò)仿函數(shù)建立與stl溝通的橋梁,只為算法服務(wù),當(dāng)我需要對(duì)算法提出一些要求的時(shí)候,例如排序默認(rèn)為從小到大,但是我需要由大到小進(jìn)行排序,就需要用一般函數(shù)的形式或仿函數(shù)的形式告訴算法,實(shí)現(xiàn)第二個(gè)版本的算法。

  • 為什么要把加減,比大小等等功能定義成一個(gè)函數(shù)或仿函數(shù),因?yàn)樾枰獙⑦@些信息傳入算法中。算法拿到這些東西之后才會(huì)做出相對(duì)應(yīng)的改變。

算術(shù)仿函數(shù)

STL內(nèi)建的算術(shù)類(lèi)仿函數(shù),支持加法、減法、乘法、除法、模數(shù)(余數(shù))、否定運(yùn)算。

templateT plus????//加法仿函數(shù)
templateT minus????//減法仿函數(shù)
templateT multiplies?//乘法仿函數(shù)
templateT divides???//除法仿函數(shù)
templateT modulus???//取模仿函數(shù)
templateT negate????//取反仿函數(shù)
    
    struct plus : public binary_function{T operator()(const T &x, const T &y) const return x y;
    };
    templatestruct minus : public binary_function{T operator()(const T &x, const T &y) const return x - y;
    };
    templatestruct multiplies : public binary_function{T operator()(const T &x, const T &y) const return x y;
    };
    templatestruct divides : public binary_function{T operator()(const T &x, const T &y) const return x y;
    };
    templatestruct modulus : public binary_function{T operator()(const T &x, const T &y) const return x $y;
    };
    templatestruct negate : public unary_function{T operator()(const T &x) const return -x;
    };
  • 例子
#include#includeusing namespace std;

void test1()
{negaten;
	cout<< n(50)<< endl;
}

void test2()
{plusp;
	cout<< p(10, 20)<< endl;
}

int main()
{test1();
	test2();
	std::cout<< "Hello World!\n";
}
// -50
// 30
關(guān)系運(yùn)算符

STL支持6種關(guān)系運(yùn)算,每一種都是二元運(yùn)算

等于,不等于,大于,大于等于,小于,小于等于
templatestruct equal_to:public binary_function{bool operator()(const T&x,const T& y)const {return x==y;};
}
templatestruct not_equal_to:public binary_function{bool operator()(const T& x,const T& y)const {return x!=y;}
};
templatestruct greater:public binary_function{bool operator()(const T&x ,const T7 y)const {return x>y;}
};
templatestruct less:public binary_function{bool operator()(const T&x ,const T7 y)const {return xstruct greater_equal:public binary_function{bool operator()(const T&x ,const T7 y)const {return x>=y;}
};
templatestruct less_equal:public binary_function{bool operator()(const T&x ,const T7 y)const {return x<=y;}
};
邏輯運(yùn)算符
templatebool logical_and//邏輯與
templatebool logical_or //邏輯或
templatebool logical_not//邏輯非
仿函數(shù)和智能指針 仿函數(shù)自定義刪除器
//用來(lái)釋放malloc出來(lái)的函數(shù)對(duì)象
templateclass FreeFunc{public:
	void operator()(T* ptr)
	{cout<< "free:"<< ptr<< endl;
		free(ptr);
	}
};

//用來(lái)釋放new[]出來(lái)的函數(shù)對(duì)象
templateclass DeleteArrayFunc {public:
	void operator()(T* ptr)
	{cout<< "delete[]"<< ptr<< endl;
		delete[] ptr;
	}
};
//用來(lái)釋放new 出來(lái)的函數(shù)對(duì)象
templateclass DeleteArrayFunc {public:
	void operator()(T* ptr)
	{cout<< "delete "<< ptr<< endl;
		delete ptr;
	}
};

//用來(lái)釋放文件描述符的函數(shù)對(duì)象
templateclass ClosefdFunc{public:
	void operator()(T* fd)
	{cout<< "close fd"<< fd<< endl;
		fclose(fd);
	}
};

void test06(){FreeFuncObject1;
	shared_ptr  sp1((int*)malloc(sizeof(int)*4), Object1);         // 回調(diào)函數(shù)是可調(diào)用對(duì)象,可以是普通的函數(shù)名或者函數(shù)對(duì)象或者lambda表達(dá)式

	DeleteArrayFuncObject2;
	shared_ptr  sp2(new int[4], Object2); 

	ClosefdFuncObject3;
	shared_ptr sp3(fopen("myfile.txt","w"), Object3);

}

	int main()
{test06();
    return 0;
}
  • 輸出結(jié)果:
close fd0x7ff94b4bfa90
delete[]0x220c21d1ae0 
free:0x220c21d1770  
智能指針中的仿函數(shù)
//智能指針的刪除器:
templatestruct default_delete{//......
	
//default deleter for unique_ptr,其中_Ptr是智能指針底層資源的指針
void operator()(_Ty *_Ptr) const _NOEXCEPT
	{// delete a pointer
		delete _Ptr; 
		//默認(rèn)刪除器僅僅只做一件事,只調(diào)用delete進(jìn)行資源的釋放
	}
	
//......
};

改進(jìn),針對(duì)這種特殊的情況,添加自定義的一個(gè)刪除器保證資源釋放完全:

templateclass Deleter{public:
	void operator()(Ty *ptr)const{cout<<"Call a custom method !!!!! "<std::unique_ptr>ptr(new int[100]);//delete []ptr
	return 0;
}

或者使用 default_delete來(lái)做刪除器

// 可用default_delete來(lái)做刪除器,default_.delete是標(biāo)準(zhǔn)庫(kù)里的模板類(lèi)。
    void fun4()
    {cout<< "detail5:: func4()"<< endl;
        shared_ptrpi5(new int[100](), std::default_delete());
    }

改進(jìn),爭(zhēng)對(duì)這種特殊的情況,添加自定義的一個(gè)刪除器保證資源釋放完全:

templateclass Deleter{public:
	void operator()(Ty *ptr)const{cout<<"Call a custom method !!!!! "<std::unique_ptr>ptr(new int[100]);//delete []ptr
	return 0;
}

或者使用 default_delete來(lái)做刪除器

// 可用default_delete來(lái)做刪除器,default_.delete是標(biāo)準(zhǔn)庫(kù)里的模板類(lèi)。
    void fun4()
    {cout<< "detail5:: func4()"<< endl;
        shared_ptrpi5(new int[100](), std::default_delete());
    }

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

新聞名稱(chēng):仿函數(shù)C++-創(chuàng)新互聯(lián)
標(biāo)題網(wǎng)址:http://muchs.cn/article24/cdiece.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、品牌網(wǎng)站制作、標(biāo)簽優(yōu)化、軟件開(kāi)發(fā)、品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)