1. 函数对象
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。
注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
分类:假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
函数对象的作用主要是什么?
STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。
class myprint
{
public:
myprint()
{
count = 0;
}
//对象超出普通函数概念,内存可以保存状态
void operator()(int num)
{
cout<<"num "<<num<<endl;
count++;
}
int count;
};
void test()
{
myprint p;
p(100);
cout<<"函数调用 的次数"<<p.count<<endl;
}
函数对象做函数参数
class myprint
{
public:
myprint()
{
count = 0;
}
void operator()(int num)
{
cout<<"num "<<num<<endl;
count++;
}
int count;
};
void test()
{
myprint p;
p(100);
cout<<"函数调用 的次数"<<p.count<<endl;
}
//函数对象做参数
void test1(myprint p,int num)
{
p(num);
}
void main()
{
//test();
myprint p;
test1(p,100);
//匿名对象做参数
test1(myprint(),30);
}
函数对象(仿函数)的优势
- 函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题。
- 函数对象超出普通函数的概念,函数对象可以有自己的状态
- 函数对象可内联编译,性能好。用函数指针几乎不可能
- 模版函数对象使函数对象具有通用性,这也是它的优势之一
谓词
谓词是指普通函数或重载的operator() 返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式。
一元谓词
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class GreaterThenFive
{
public:
bool operator()(int num)
{
return num > 5;
}
};
//一元谓词
void test01()
{
vector<int> v;
for (int i = 0; i < 10;i ++)
{
v.push_back(i);
}
//查找符合要求的第一个元素并返回迭代器
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterThenFive());
if (it == v.end())
{
cout << "没有找到" << endl;
}
else
{
cout << "找到了: " << *it << endl;
}
}
二元谓词
//二元谓词
class MyCompare
{
public:
bool operator()(int num1, int num2)
{
return num1 > num2;
}
};
void test02()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(20);
v.push_back(90);
v.push_back(60);
//默认从小到大
sort(v.begin(), v.end());
for_each(v.begin(),v.end(),[](int val){cout<<val<<" ";});
cout << endl;
cout << "----------------------------" << endl;
//使用函数对象改变算法策略,排序从大到小
sort(v.begin(), v.end(),MyCompare());
//for_each 遍历算法
for_each(v.begin(),v.end(), [](int val){cout<<val<<" ";});
cout << endl;
}
内建函数对象
STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件 functional 。
- 6个算数类函数对象,除了negate是一元运算,其他都是二元运算。
template<class T> T plus<T>//加法仿函数
template<class T> T minus<T>//减法仿函数
template<class T> T multiplies<T>//乘法仿函数
template<class T> T divides<T>//除法仿函数
template<class T> T modulus<T>//取模仿函数
template<class T> T negate<T>//取反仿函数
void test()
{
//negate 取反
negate<int> n;
cout<<n(10)<<endl;
plus<int>p;
cout<<p(10,20)<<endl;
}
- 6个关系运算类函数对象,每一种都是二元运算。
template<class T> bool equal_to<T>//等于
template<class T> bool not_equal_to<T>//不等于
template<class T> bool greater<T>//大于
template<class T> bool greater_equal<T>//大于等于
template<class T> bool less<T>//小于
template<class T> bool less_equal<T>//小于等于
void test01()
{
vector<int>p;
p.push_back(10);
p.push_back(30);
p.push_back(40);
p.push_back(20);
sort(p.begin(),p.end());
for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
cout<<endl;
sort(p.begin(),p.end(),greater<int>());
for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
cout<<endl;
}
- 逻辑运算类运算函数,not为一元运算,其余为二元运算。
template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
void test02()
{
vector<int>p;
p.push_back(true);
p.push_back(false);
p.push_back(true);
p.push_back(false);
p.push_back(true);
for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});//10101
cout<<endl;
vector<int>p2;
p2.resize(p.size());
transform(p.begin(),p.end(),p2.begin(),logical_not<bool>());
for_each(p2.begin(),p2.end(),[](int val){cout<<val<<" ";});//01010
cout<<endl;
}
函数对象适配器
函数适配器 bind2nd() 绑定
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<string>
using namespace std;
class myprint:public binary_function<int,int,void>
{
public:
void operator()(int val,int num) const
{
cout<<"val = "<<val<<" "<<"num = "<<num<<" "<<val+num<<" "<<endl;
}
};
//函数适配器
void test01()
{
vector<int> p;
for(int i = 0;i<10;i++)
{
p.push_back(i);
}
for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
cout<<endl;
//函数适配器bind1st bind2nd
//现在我有这个需求 在遍历容器的时候,我希望将容器中的值全部加上100之后显示出来,怎么做?
//我们直接给函数对象绑定参数 编译阶段就会报错
//for_each(v.begin(), v.end(), bind2nd(myprint(),100));
//如果我们想使用绑定适配器,需要我们自己的函数对象继承binary_function 或者 unary_function
//根据我们函数对象是一元函数对象 还是二元函数对象
//bindlst bind2nd
//1.绑定数据 bind2nd
//2.继承类 binary_function<参数1类型,参数2类型,返回值类型>
//3.在函数后边加const
//4.bind2nd(类,num)
cout<<"bind2nd:"<<endl;
for_each(p.begin(),p.end(),bind2nd(myprint(),100));
cout<<"---------------------"<<endl;
//总结: bind1st和bind2nd区别?
//bind1st : 将参数绑定为函数对象的第一个参数
//bind2nd : 将参数绑定为函数对象的第二个参数
//bind1st bind2nd将二元函数对象转为一元函数对象
cout<<"bind1st:"<<endl;
for_each(p.begin(),p.end(),bind1st(myprint(),100));
}
取反适配器 not
公有继承 :unary_function
lass greaterfive:public unary_function<int,bool>
{
public:
bool operator()(int val) const
{
return val >5;
}
};
//取反适配器
void test02()
{
vector<int>p;
for(int i=0 ;i<10;i++)
{
p.push_back(i);
}
//查找大于5的数
vector<int>::iterator pos = find_if(p.begin(),p.end(),greaterfive());
cout<<"大于5的数"<<*pos<<endl;
//查找小于5的数 not1 一元 找出小于5
//vector<int>::iterator pos1 = find_if(p.begin(),p.end(),not1(greaterfive()));
//方式二
vector<int>::iterator pos1 = find_if(p.begin(),p.end(),not1(bind2nd(greater<int>(),5)));
cout<<"小于5的数"<<*pos1<<endl;
//not2 二元 排序 not2( less<int>() ) 从大到小 相当于 greater<int>()
sort(p.begin(),p.end(),not2(less<int>()));
for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
cout<<endl;
}
函数指针适配器 ptr_fun
void myprint1(int val1,int val2)
{
cout<<val1+val2<<endl;
}
//函数指针适配器 ptr_fun
void test03()
{
vector<int> p;
for(int i = 0;i<10;i++)
p.push_back(i);
// ptr_fun( )把一个普通的函数指针适配成函数对象
for_each(p.begin(),p.end(),bind2nd(ptr_fun(myprint1),100));
}
成员函数适配器
//成员函数适配器
class person
{
public:
person(string name,int age)
{
this->name = name;
this->age = age;
}
void myperson()
{
cout<<name<<" "<<age<<endl;
}
string name;
int age;
};
void test04()
{
vector<person> v;
person p1("aa",10);
person p2("bb",11);
person p3("cc",12);
person p4("dd",13);
person p5("ff",14);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
//利用 mem_fun_ref 将Person内部成员函数适配
for_each(v.begin(),v.end(),mem_fun_ref(&person::myperson));
cout<<"---------------------"<<endl;
vector<person*> v1;
v1.push_back(&p1);
v1.push_back(&p2);
v1.push_back(&p3);
v1.push_back(&p4);
v1.push_back(&p5);
//如果容器存放的是对象指针, 那么用mem_fun
//如果容器中存放的是对象实体,那么用mem_fun_ref
for_each(v1.begin(),v1.end(),mem_fun(&person::myperson));
}