bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

仿函數C++-創新互聯

仿函數

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

成都創新互聯2013年至今,先為羅平等服務建站,羅平等地企業,進行企業商務咨詢服務。為羅平企業網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。

仿函數的優點和作用?

文章目錄
  • 仿函數
    • 為什么需要仿函數
      • 場景一
      • 場景二
    • 仿函數是什么
      • 具體定義
      • 實例
          • 直接調用仿函數
          • 仿函數作為函數入參
    • 仿函數和STL
        • 算術仿函數
        • 關系運算符
        • 邏輯運算符
    • 仿函數和智能指針
        • 仿函數自定義刪除器
        • 智能指針中的仿函數

為什么需要仿函數 場景一
  • 場景引入

  • 計算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;
}
  • 這里就是計算a數組里面全部的和,放在x變量里面。
  • ? 首先,這個函數的原型是T (*ptrA)(T x, T y);如果我想提升我處理數據的速度,讓時間少浪費由于函數值傳遞引起的拷貝上,于是我需要這樣寫函數 T funcA(const int& x, const int& y)。這樣寫的話,我們原來的函數T (*ptrA)(T x, T y)就不能匹配這個函數,于是我們就要重載函數。還有就是效率問題,函數指針的調用,我們的電腦需要做很多工作,比如說保存當前的寄存器值,傳遞參數,返回值,返回到函數調用地方繼續執行等。
  • 幸運的是,這一切問題都可以通過仿函數來解決,如下:
#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;
}

這樣就解決了效率和函數重載的問題了。

場景二
  • 假設我們現在有一個數組,數組中存有任意數量的數字,我們希望能夠統計出這個數組中大于 10 的數字的數量,你的代碼很可能是這樣的:
#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() 函數的第三個參數是一個函數指針,用于外部調用,而 IsGreaterThanTen() 函數通常也是外部已經定義好的,它只接受一個參數的函數。如果此時希望將判定的閾值也作為一個變量傳入,變為如下函數:
bool IsGreaterThanThreshold(int num, int threshold) {return num>threshold ? true : false;
}
  • 雖然這個函數看起來比前面一個版本更具有一般性,但是它不能滿足已經定義好的函數指針參數的要求,因為函數指針參數的類型是bool (*)(int),與函數bool IsGreaterThanThreshold(int num, int threshold)的類型不相符。如果一定要完成這個任務,按照以往的經驗,我們可以考慮如下可能途徑:

(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;
}
  1. 這種方法擴展性較差,當函數參數有所變化,則無法兼容舊的代碼,具體在第一小節已經闡述。正如上面的例子,在我們寫代碼時有時會發現有些功能代碼,會不斷地被使用。為了復用這些代碼,實現為一個公共的函數是一個解決方法。不過函數用到的一些變量,可能是公共的全局變量。引入全局變量,容易出現同名沖突,不方便維護。

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

  3. 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;
}
  • 這個例子應該可以讓您體會到仿函數的一些作用:它既能像普通函數一樣傳入給定數量的參數,還能存儲或者處理更多我們需要的有用信息。于是仿函數提供了第四種解決方案:成員變量。成員函數可以很自然地訪問成員變量,從而可以解決第一節“1.為什么要有仿函數”中提到的問題:計算出數組中大于指定閾值的數字數量。
仿函數是什么 具體定義
  • 仿函數(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。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯