為什么我們需要使用仿函數(仿函數解決了什么痛點)?
成都創新互聯2013年至今,先為羅平等服務建站,羅平等地企業,進行企業商務咨詢服務。為羅平企業網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。仿函數的優點和作用?
文章目錄場景引入
計算a數組里面全部的和,放在x變量里面。
#include#include#include
using namespace std;
templateinline T accumulate(InputIterator first, InputIterator last, T init, T (*ptrA)(T, T)) {//函數指針
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;
}
#include#include#include
using namespace std;
templateinline T accumulate(InputIterator first, InputIterator last, T init, FunObject object) {//函數對象
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()); //仿函數作為函數的入參,只需要傳入類對象即可,這里傳入的是匿名對象
cout<< x<< endl;
return 0;
}
這樣就解決了效率和函數重載的問題了。
場景二#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<
bool IsGreaterThanThreshold(int num, int threshold) {return num>threshold ? true : false;
}
(1)閾值作為函數的局部變量。局部變量不能在函數調用中傳遞,故不可行;
bool IsGreaterThanThreshold(int num) {int threshold; // 這里的threhold 沒法獲得外部的傳參
return num>threshold ? true : false;
}
(2)全局變量。我們可以將閾值設置成一個全局變量。這種方法雖然可行,但不優雅,且容易引入 Bug,比如全局變量容易同名,造成命名空間污染
int threshold=10; // 定義全局變量
bool IsGreaterThanThreshold(int num) {
return num>threshold ? true : false;
}
(3)函數傳參。這種方法我們已經討論過了,多個參數不適用于已定義好的 RecallFunc() 函數。(除非你重寫函數指針)
假設你設計的傳參函數是這樣的:
bool IsGreaterThanThreshold(int num, int threshold) {
return num>threshold ? true : false;
}
在此基礎上,你必須重寫 RecallFunc() 函數 。
int RecallFunc(int *start, int *end, bool (*pf)(int,int),int threshold) {這里就需要引入新參數,來指threshold。同時需要重寫函數指針,以使其符合IsGreaterThanThreshold 。
int count=0;
for(int *i = start; i != end+1; i++) {count = pf(*i,threshold) ? count+1 : count;
}
return count;
}
這種方法擴展性較差,當函數參數有所變化,則無法兼容舊的代碼,具體在第一小節已經闡述。正如上面的例子,在我們寫代碼時有時會發現有些功能代碼,會不斷地被使用。為了復用這些代碼,實現為一個公共的函數是一個解決方法。不過函數用到的一些變量,可能是公共的全局變量。引入全局變量,容易出現同名沖突,不方便維護。
這時就可以使用仿函數了,寫一個簡單類,除了維護類的基本成員函數外,只需要重載 operator() 運算符 。這樣既可以免去對一些公共變量的維護,也可以使重復使用的代碼獨立出來,以便下次復用。而且相對于函數更優秀的性質,仿函數還可以進行依賴、組合與繼承等,這樣有利于資源的管理。如果再配合模板技術和 Policy 編程思想,則更加威力無窮,大家可以慢慢體會。Policy 表述了泛型函數和泛型類的一些可配置行為(通常都具有被經常使用的缺省值)。
STL 中也大量涉及到仿函數,有時仿函數的使用是為了函數擁有類的性質,以達到安全傳遞函數指針、依據函數生成對象、甚至是讓函數之間有繼承關系、對函數進行運算和操作的效果。比如 STL 中的容器 set 就使用了仿函數 less ,而 less 繼承的 binary_function,就可以看作是對于一類函數的總體聲明,這是函數做不到的。
#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));//仿函數作為函數的入參,只需要傳入類對象即可,這里傳入的是匿名對象
cout<< result<< endl;
}
仿函數(Functor)又稱為函數對象(Function Object)是一個能行使函數功能的類。
仿函數的語法幾乎和我們普通的函數調用一樣,不過作為仿函數的類,都必須重載 operator() 運算符。因為調用仿函數,實際上就是通過類對象調用重載后的 operator() 運算符。
我們先來看一個仿函數的例子。
直接調用仿函數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");// 隱式寫法
// myFunctor2.operator()("Hello"); //顯式寫法
編譯運行輸出:
Hello and world!
仿函數作為函數入參#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));//仿函數作為函數的入參,只需要傳入類對象即可,這里傳入的是匿名對象
cout<< result<< endl;
}
仿函數和STL通過仿函數建立與stl溝通的橋梁,只為算法服務,當我需要對算法提出一些要求的時候,例如排序默認為從小到大,但是我需要由大到小進行排序,就需要用一般函數的形式或仿函數的形式告訴算法,實現第二個版本的算法。
為什么要把加減,比大小等等功能定義成一個函數或仿函數,因為需要將這些信息傳入算法中。算法拿到這些東西之后才會做出相對應的改變。
STL內建的算術類仿函數,支持加法、減法、乘法、除法、模數(余數)、否定運算。
templateT plus????//加法仿函數
templateT minus????//減法仿函數
templateT multiplies?//乘法仿函數
templateT divides???//除法仿函數
templateT modulus???//取模仿函數
templateT negate????//取反仿函數
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
關系運算符STL支持6種關系運算,每一種都是二元運算
等于,不等于,大于,大于等于,小于,小于等于
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;}
};
邏輯運算符templatebool logical_and//邏輯與
templatebool logical_or //邏輯或
templatebool logical_not//邏輯非
仿函數和智能指針
仿函數自定義刪除器//用來釋放malloc出來的函數對象
templateclass FreeFunc{public:
void operator()(T* ptr)
{cout<< "free:"<< ptr<< endl;
free(ptr);
}
};
//用來釋放new[]出來的函數對象
templateclass DeleteArrayFunc {public:
void operator()(T* ptr)
{cout<< "delete[]"<< ptr<< endl;
delete[] ptr;
}
};
//用來釋放new 出來的函數對象
templateclass DeleteArrayFunc {public:
void operator()(T* ptr)
{cout<< "delete "<< ptr<< endl;
delete ptr;
}
};
//用來釋放文件描述符的函數對象
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); // 回調函數是可調用對象,可以是普通的函數名或者函數對象或者lambda表達式
DeleteArrayFuncObject2;
shared_ptr sp2(new int[4], Object2);
ClosefdFuncObject3;
shared_ptr sp3(fopen("myfile.txt","w"), Object3);
}
int main()
{test06();
return 0;
}
close fd0x7ff94b4bfa90
delete[]0x220c21d1ae0
free:0x220c21d1770
智能指針中的仿函數//智能指針的刪除器:
templatestruct default_delete{//......
//default deleter for unique_ptr,其中_Ptr是智能指針底層資源的指針
void operator()(_Ty *_Ptr) const _NOEXCEPT
{// delete a pointer
delete _Ptr;
//默認刪除器僅僅只做一件事,只調用delete進行資源的釋放
}
//......
};
改進,針對這種特殊的情況,添加自定義的一個刪除器保證資源釋放完全:
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來做刪除器
// 可用default_delete來做刪除器,default_.delete是標準庫里的模板類。
void fun4()
{cout<< "detail5:: func4()"<< endl;
shared_ptrpi5(new int[100](), std::default_delete());
}
改進,爭對這種特殊的情況,添加自定義的一個刪除器保證資源釋放完全:
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來做刪除器
// 可用default_delete來做刪除器,default_.delete是標準庫里的模板類。
void fun4()
{cout<< "detail5:: func4()"<< endl;
shared_ptrpi5(new int[100](), std::default_delete());
}
你是否還在尋找穩定的海外服務器提供商?創新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統配攻擊溯源,準確流量調度確保服務器高可用性,企業級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
新聞名稱:仿函數C++-創新互聯
標題網址:http://vcdvsql.cn/article24/cdiece.html
成都網站建設公司_創新互聯,為您提供定制網站、品牌網站制作、標簽優化、軟件開發、品牌網站設計、網站導航
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯