前提:
????????本博客對比?函數指針實現回調 和??仿函數 ,突出仿函數的優勢。
目的:
????????一個類要能夠靈活的調用兩個函數,essfc
?和?greaterfc
,分別用于比較兩個整數的大小:
①:lessfc
:判斷?x
?是否小于?y
,如果是則返回?true
,否則返回?false
。
②:greaterfc
:判斷?x
?是否大于?y
,如果是則返回?true
,否則返回?false
一:函數指針實現回調
①:普通代碼:
//lessfc函數 x<y?
bool lessfc(int x, int y)
{return x < y;
}//greaterfc函數 x>y?
bool greaterfc(int x, int y)
{return x > y;
}// A這個類體現了--->函數指針實現回調
class A
{
public:A(bool(*pf)(int, int))//構造函數接收一個函數指針 并賦值給成員變量:_pf(pf){}void func(int xx, int yy)//func函數接收兩個參數{cout << "void func(int xx, int yy)" << _pf(xx, yy) << endl;;} //用接收到的函數指針結合兩個int參數調用該函數 bool(*_pf)(int, int);//成員變量也是一個函數指針類型
};int main()
{A aa1(lessfc);//創建一個對象aa1.func(1, 2);//調用對象的func函數 且傳兩個intA aa2(greaterfc);//創建一個對象aa2.func(1, 2);//調用對象的func函數 且傳兩個int
}
運行結果:
解釋:
類?A
?的行為可以通過傳入不同的函數指針來動態改變:
????????傳入?lessfc
?時,func
?方法會執行小于比較。
????????傳入?greaterfc
?時,func
?方法會執行大于比較。
②:加上模版的代碼:
//lessfc函數 x<y?
template<class T>
bool lessfc(T x, T y)
{return x < y;
}//greaterfc函數 x>y?
template<class T>
bool greaterfc(T x, T y)
{return x > y;
}// A這個類體現了--->函數指針實現回調
template<class T>
class A
{
public:A(bool(*pf)(T, T))//構造函數接收一個函數指針 并賦值給成員變量:_pf(pf){}void func(T xx, T yy)//func函數接收兩個參數{cout << "void func(T xx, T yy)" << _pf(xx, yy) << endl;;} //用接收到的函數指針結合兩個int參數調用該函數 bool(*_pf)(T, T);//成員變量也是一個函數指針類型
};int main()
{A<int> aa1(lessfc);//因為有模版,所以顯式傳模版的類型去創建一個對象aa1.func(1, 2);//調用對象的func函數 且傳兩個int 與創建時T的類型吻合A<double>aa2(greaterfc);//因為有模版,所以顯式傳模版的類型創建一個對象aa2.func(1.1, 1.0);//調用對象的func函數 且傳兩個double 與創建時T的類型吻合
}
解釋:加上模版之后,范圍更廣了
二:仿函數
定義:一個對象能像函數一樣用,實際上調用的是我們重載的?operator()
①:普通代碼:
//定義仿函數
class lessfc //將之前的lessfc函數封裝成一個類
{
public://類中僅需對()這個操作符進行重載bool operator()(const int& x, const int& y){return x < y;}
};//定義仿函數
class greaterfc //將greaterfc函數封裝成一個類
{
public://類中僅需對()這個操作符進行重載bool operator()(const int& x, const int& y){return x > y;}
};template<class Comapre>
class A//A這個類要使用仿函數
{
public:void func(int xx, int yy){Comapre com;//創建一個 Comapre 類型的對象 com。cout << "void func(int xx, int yy)" << com(xx, yy) << endl;;//調用 com(xx, yy),即調用仿函數的 operator(),比較 xx 和 yy。}
};int main()
{A<less<int>> aa1;aa1.func(1, 2); // 輸出 1 < 2 的結果(true)A<greater<int>> aa2;aa2.func(1, 2); // 輸出 1 > 2 的結果(false)
}
運行結果:
①:不再像函數指針那樣,赤裸裸的寫兩個函數,而是在兩個類中對()運算符進行重載,重載的定義在寫函數的功能
②:需要用仿函數的類的模版參數,就是那兩個仿函數的類名,在類中進行仿函數類的對象的創建,再結合類中函數(如func)的參數,最后結合()進行函數的調用,仿函數對象看見()就會實現重載后的功能
③:main函數中的less<int>,就是對仿函數進行顯式的調用,此時的模版不再是簡單的類型,而是一個類
②:加上模版的代碼:
//定義仿函數
template<class T>
class lessfc //將之前的lessfc函數封裝成一個類
{
public://類中僅需對()這個操作符進行重載bool operator()(const T& x, const T& y){return x < y;}
};//定義仿函數
template<class T>
class greaterfc //將greaterfc函數封裝成一個類
{
public://類中僅需對()這個操作符進行重載bool operator()(const T& x, const T& y){return x > y;}
};template<class Comapre, class T>
class A//A這個類要使用仿函數
{
public:void func(T xx, T yy){Comapre com;//創建一個 Comapre 類型的對象 com。cout << "void func(T xx, T yy)" << com(xx, yy) << endl;;//調用 com(xx, yy),即調用仿函數的 operator(),比較 xx 和 yy。}
};int main()
{A<less<int>, int> aa1;aa1.func(1, 2); // 輸出 1 < 2 的結果(true)A<greater<double>, double> aa2;aa2.func(1.1, 1.0); // 輸出 1.1 >1.0 的結果(ture)
}
運算結果:
解釋:對三個類都加上模版之后,范圍更廣了
三:仿函數更優的點
1. 更靈活的功能擴展
仿函數:仿函數是一個類對象,可以包含成員變量和成員函數,因此可以在調用時保存狀態(例如計數器、配置參數等)。
函數指針:函數指針只能指向一個靜態函數,無法保存狀態,功能擴展性較差。
2. 更高的性能
仿函數:仿函數通常是內聯的(inline),編譯器可以優化其調用,減少函數調用的開銷。
函數指針:函數指針的調用需要通過指針間接調用,無法內聯,性能稍差。
3. 更強的類型安全
仿函數:仿函數是類對象,類型信息在編譯時確定,類型安全性更高。
函數指針:函數指針的類型信息較弱,容易出錯(例如指向錯誤類型的函數)。
4. 更好的通用性
仿函數:仿函數可以與模板結合,實現高度通用的代碼。例如,STL 中的排序算法 std::sort 可以通過傳入不同的仿函數實現升序或降序排序。
函數指針:函數指針的通用性較差,難以與模板結合。
5. 支持運算符重載
仿函數:仿函數可以重載 operator(),使得對象可以像函數一樣被調用,語法更直觀。
函數指針:函數指針的調用語法較為繁瑣。
6. 更易于組合和擴展
仿函數:仿函數可以通過繼承、組合等方式擴展功能。
函數指針:函數指針的功能擴展性較差,難以實現復雜的邏輯組合。
?