1.函數對象
重載函數調用操作符的類,其對象常稱為函數對象(function object),即它們是行為類似函數的對象。一個類對象,表現出一個函數的特征,就是通過“對象名+(參數列表)”的方式使用一個類對象,如果沒有上下文,完全可以把它看作一個函數對待。
這是通過重載類的operator()來實現的。
“在標準庫中,函數對象被廣泛地使用以獲得彈性”,標準庫中的很多算法都可以使用函數對象或者函數來作為自定的回調行為;
一元函數對象:函數參數1個;
二元函數對象:函數參數2個;
2.謂詞
一元謂詞: 函數參數1個,函數返回值是bool類型,可以作為一個判斷式
二元謂詞: 函數參數2個,函數返回值是bool類型
謂詞可以使一個仿函數,也可以是一個回調函數。
一元謂詞舉例如下:
1.判斷給出的string對象的長度是否小于6
bool GT6(const string &s)
{
return s.size() >= 6;
}
2.判斷給出的int是否在3到8之間
bool Compare( int i )
{
return ( i >= 3 && i <= 8 );
}
二元謂詞舉例如下:
1.比較兩個string對象,返回一個bool值,指出第一個string是否比第二個短
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
3.一元函數對象案例
//1普通類 重載 函數調用操作符
template <typename T>
void FuncShowElemt(T &t) //普通函數 不能像 仿函數那樣記錄狀態
{cout << t << " ";
};void showChar(char &t)
{cout << t << " ";
}//函數模板 重載 函數調用操作符
template <typename T>
class ShowElemt
{
public:ShowElemt(){n = 0;}void operator()(T &t){n++;cout << t << " ";}void printCount(){cout << n << endl;}
public:int n;
};//1 函數對象 基本使用
void main11()
{int a = 100;FuncShowElemt<int>(a); //普通的函數調用ShowElemt<int> showElemt; //函數對象 showElemt(a); //函數對象調用
}
4.一元謂詞案例
//1元謂詞 例子
template <typename T>
class Isdiv
{
public:Isdiv(const T &divisor) //{this->divisor = divisor;}bool operator()(T &t){return (t%divisor == 0);}
protected:
private:T divisor;
};void main13()
{vector<int> v2;for (int i=10; i<33; i++){v2.push_back(i);}vector<int>::iterator it;int a = 4;Isdiv<int> mydiv(a);// _InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred) //返回的是迭代器it = find_if(v2.begin(), v2.end(), Isdiv<int>(4));if (it != v2.end()){cout << "第一個被4整除的數是:" << *it << endl;}
}
5.二元函數對象案例
template <typename T>
struct SumAdd
{T operator()(T &t1, T &t2){return t1 + t2;}
};template <typename T>
void printE(T &t)
{for (vector<int>::iterator it = t.begin(); it!=t.end(); it++ ){cout << *it << " ";}
}void printVector(vector<int> &v)
{for (vector<int>::iterator it = v.begin(); it!=v.end(); it++ ){cout << *it << " ";}
}void main14()
{vector<int> v1, v2 ;vector<int> v3;v1.push_back(1);v1.push_back(2);v1.push_back(3);v2.push_back(4);v2.push_back(5);v2.push_back(6);v3.resize(10);//transform(v1.begin(), v1.end(), v2.begin(),v3.begin(), SumAdd<int>());/*template<class _InIt1,class _InIt2,class _OutIt,class _Fn2> inline_OutIt transform(_InIt1 _First1, _InIt1 _Last1,_InIt2 _First2, _OutIt _Dest, _Fn2 _Func)*/vector<int>::iterator it = transform(v1.begin(), v1.end(), v2.begin(),v3.begin(), SumAdd<int>());cout << *it << endl;printE(v3);
}
6.二元謂詞案例
void current(int &v)
{cout << v << " ";
}bool MyCompare(const int &a, const int &b)
{return a < b;
}
void main15()
{vector<int> v(10);for (int i=0; i<10; i++){v[i] = rand() % 100;}for_each(v.begin(), v.end(), current);printf("\n");sort(v.begin(), v.end(), MyCompare );printf("\n");for (int i=0; i<10; i++){printf("%d ", v[i]);}printf("\n");
}
7.綜合示例代碼
#include <iostream>
using namespace std;#include "string"
#include <vector>
#include <list>
#include "set"
#include <algorithm>
#include "functional"//函數對象 類重載了()
template <typename T>
class ShowElemt
{
public:ShowElemt(){n = 0;}void operator()(T &t){n ++;//printN();cout << t << " ";}void printN(){cout << "n:" << n << endl;}
protected:
private:int n;
};//函數模板 ==函數
template <typename T>
void FuncShowElemt(T &t)
{cout << t << endl;
}//普通函數
void FuncShowElemt2(int &t)
{cout << t << " ";
}//函數對象 定義 ; 函數對象和普通函數的異同
//
void main01()
{int a = 10;ShowElemt<int> showElemt;showElemt(a); //函數對象的()的執行 很像一個函數 //仿函數FuncShowElemt<int>(a);FuncShowElemt2(a);
}//函數對象是屬于類對象,能突破函數的概念,能保持調用狀態信息
//函數對象的好處
// for_each算法中, 函數對象做函數參數
// for_each算法中, 函數對象當返回值
void main02()
{vector<int> v1;v1.push_back(1);v1.push_back(3);v1.push_back(5);for_each(v1.begin(), v1.end(), ShowElemt<int>()); //匿名函數對象 匿名仿函數cout << endl;for_each(v1.begin(), v1.end(), FuncShowElemt2); //通過回調函數 誰使用for_each 誰去填寫回調函數的入口地址ShowElemt<int> show1;//函數對象 做函數參數 /*template<class _InIt,class _Fn1> inline_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func){ // perform function for each element_DEBUG_RANGE(_First, _Last);_DEBUG_POINTER(_Func);return (_For_each(_Unchecked(_First), _Unchecked(_Last), _Func));}*///1 for_each算法的 函數對象的傳遞 是元素值傳遞 ,不是引用傳遞for_each(v1.begin(), v1.end(), show1);show1.printN();cout << "通過for_each算法的返回值看調用的次數" << endl;show1 = for_each(v1.begin(), v1.end(), show1);show1.printN();//結論 要點: 分清楚 stl算法返回的值是迭代器 還是 謂詞(函數對象) 是stl算法入門的重要點
}template<typename T>
class IsDiv
{
public:IsDiv(const T &divisor){this->divisor = divisor;}bool operator()(T &t){return (t%divisor == 0);}protected:
private:T divisor;
};void main03()
{vector<int> v2;for (int i=10; i<33; i++){v2.push_back(i);}int a = 4;IsDiv<int> myDiv(a);//find_if(v2.begin(), v2.end(), myDiv );/*template<class _InIt,class _Pr> inline_InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred){ // find first satisfying _Pred_DEBUG_RANGE(_First, _Last);_DEBUG_POINTER(_Pred);return (_Rechecked(_First,_Find_if(_Unchecked(_First), _Unchecked(_Last), _Pred)));}//find_if返回值是一個迭代器 //要點: 分清楚 stl算法返回的值是迭代器 還是 謂詞(函數對象) 是stl算法入門的重要點*/vector<int>::iterator it;it = find_if(v2.begin(), v2.end(), IsDiv<int>(a) );if (it == v2.end()){cout << "容器中沒有被4整除的元素" << endl;}else{cout <<"第一個是被4整除的元素是:" << *it << endl;}}//二元函數對象
template <typename T>
class SumAdd
{
public:T operator()(T t1, T t2){return t1 + t2;}
};void main04()
{//v1 v2 ==> v3vector<int> v1, v2;vector<int> v3;v1.push_back(1);v1.push_back(3);v1.push_back(5);v2.push_back(2);v2.push_back(4);v2.push_back(6);v3.resize(10);/*template<class _InIt1,class _InIt2,class _OutIt,class _Fn2> inline_OutIt transform(_InIt1 _First1, _InIt1 _Last1,_InIt2 _First2, _OutIt _Dest, _Fn2 _Func){ // transform [_First1, _Last1) and [_First2, ...) with _Func_DEBUG_RANGE(_First1, _Last1);_DEBUG_POINTER(_Dest);_DEBUG_POINTER(_Func);if (_First1 != _Last1)return (_Transform2(_Unchecked(_First1), _Unchecked(_Last1),_First2, _Dest, _Func,_Is_checked(_Dest)));return (_Dest);}//transform 把運算結果的 迭代器的開始位置 返回出來 */transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), SumAdd<int>() );for (vector<int>::iterator it=v3.begin(); it!=v3.end(); it++ ){cout << *it << " ";}cout << endl;
}bool MyCompare(const int &a, const int &b)
{return a < b; //從小到大
}void main05()
{vector<int> v1(10);for (int i=0; i<10; i++){int tmp = rand() %100;v1[i] = tmp;}for (vector<int>::iterator it=v1.begin(); it!=v1.end(); it++ ){cout << *it <<" ";}cout << endl;for_each(v1.begin(), v1.end(), FuncShowElemt2);cout << endl;sort(v1.begin(), v1.end(), MyCompare);for_each(v1.begin(), v1.end(), FuncShowElemt2);cout << endl;
}struct CompareNoCase
{bool operator()(const string &str1, const string &str2){string str1_ ;str1_.resize(str1.size() );transform(str1.begin(), str1.end(), str1_.begin(), tolower ); //預定義函數對象 string str2_ ;str2_.resize(str2.size() );transform(str2.begin(), str2.end(), str2_.begin(), tolower ); //預定義函數對象 return (str1_ < str2_); // 從小到大進行排序}
};
void main06()
{set<string> set1;set1.insert("bbb");set1.insert("aaa");set1.insert("ccc");set<string>::iterator it = set1.find("aAa"); //find函數 默認 區分大小寫if (it == set1.end()){cout << " 沒有 查找到 aaa " << endl;}else{cout << " 查找到 aaa " << endl;}set<string, CompareNoCase> set2;set2.insert("bbb");set2.insert("aaa");set2.insert("ccc");set<string, CompareNoCase>::iterator it2 = set2.find("aAa");if (it2 == set2.end()){cout << " 沒有 查找到 aaa " << endl;}else{cout << " 不區分大小的的查找 查找到 aaa " << endl;}}void main1111()
{//main01(); //函數對象基本概念//main02(); //函數對象的好處 函數對象做函數參數 函數對象做返回值//main03(); //一元謂詞//main04(); //二元函數對象 和二元謂詞//main05(); //二元函數對象 和二元謂詞main06(); //二元謂詞在set集合中的應用cout<<"hello..."<<endl;system("pause");return ;
}
8.預定義函數對象
標準模板庫STL提前定義了很多預定義函數對象,#include <functional>
必須包含。
//1使用預定義函數對象:
//類模板plus<> 實現了: 不同類型的數據進行加法運算
void main41()
{plus<int> intAdd;int x = 10;int y = 20;int z = intAdd(x, y); //等價于 x + y cout << z << endl;plus<string> stringAdd;string myc = stringAdd("aaa", "bbb");cout << myc << endl;vector<string> v1;v1.push_back("bbb");v1.push_back("aaa");v1.push_back("ccc");v1.push_back("zzzz");//缺省情況下,sort()用底層元素類型的小于操作符以升序排列容器的元素。//為了降序,可以傳遞預定義的類模板greater,它調用底層元素類型的大于操作符:cout << "sort()函數排序" << endl;;sort(v1.begin(), v1.end(), greater<string>() ); //從大到小for (vector<string>::iterator it=v1.begin(); it!=v1.end(); it++ ){cout << *it << endl;}
}
8.1算術函數對象
預定義的函數對象支持加、減、乘、除、求余和取反。調用的操作符是與type相關聯的實例
//加法:plus<Types>
plus<string> stringAdd;
sres = stringAdd(sva1,sva2);減法:minus<Types>
乘法:multiplies<Types>
除法divides<Tpye>
求余:modulus<Tpye>
取反:negate<Type>
negate<int> intNegate;
ires = intNegate(ires);
Ires= UnaryFunc(negate<int>(),Ival1);
8.2關系函數對象
等于equal_to<Tpye>
equal_to<string> stringEqual;
sres = stringEqual(sval1,sval2);
不等于not_equal_to<Type>
大于 greater<Type>
大于等于greater_equal<Type>
小于 less<Type>
小于等于less_equal<Type>
void main42()
{vector<string> v1;v1.push_back("bbb");v1.push_back("aaa");v1.push_back("ccc");v1.push_back("zzzz");v1.push_back("ccc");string s1 = "ccc";//int num = count_if(v1.begin(),v1.end(), equal_to<string>(),s1);int num = count_if(v1.begin(),v1.end(),bind2nd(equal_to<string>(), s1));cout << num << endl;
}
8.3邏輯函數對象
邏輯與 logical_and<Type>
logical_and<int> indAnd;
ires = intAnd(ival1,ival2);
dres=BinaryFunc( logical_and<double>(),dval1,dval2);
邏輯或logical_or<Type>
邏輯非logical_not<Type>
logical_not<int> IntNot;
Ires = IntNot(ival1);
Dres=UnaryFunc( logical_not<double>,dval1);