函数对象的概念
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。
注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
函数对象基本概念
函数对象也可以有参数和返回值
函数对象超出函数概念,可以保存函数调用状态
函数对象做参数和返回值
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
using namespace std;
class FuncObject01{
public:
void operator()(){
cout << "hello world" << endl;
}
};
void FuncObject02(){
cout << "hello world" << endl;
}
//函数对象概念
void test01(){
FuncObject01 fobj;
fobj();
FuncObject02();
}
class FuncObject03{
public:
int operator()(int a, int b){
return a + b;
}
};
int FuncObject04(int a,int b){
return a + b;
}
//函数对象也可以像普通函数一样 具有返回值和参数
void test02(){
FuncObject03 fobj;
int ret = fobj(10,20);
cout << "ret :" << ret << endl;
ret = FuncObject04(10,20);
cout << "ret :" << ret << endl;
}
//函数对象超出了普通函数的功能,可以具有保存函数调用状态
//例如 我们要统计函数调用次数
class FuncObject05{
public:
FuncObject05() :count(0){}
void operator()(){
cout << "hello world" << endl;
count++;
}
int count;
};
//普通函数要统计调用次数 需要一个全局变量
int g_count = 0;
void FuncObject06(){
cout << "hello world" << endl;
g_count++;
}
void test03(){
FuncObject06();
FuncObject06();
cout << "函数调用次数:" << g_count << endl;
//使用函数对象 不需要使用全局变量
FuncObject05 fobj;
fobj();
fobj();
fobj();
cout << "函数调用次数:" << fobj.count << endl;
}
//函数对象做参数和返回值
class print{
public:
print() :count(0){}
void operator()(const int& val){
cout << val << " ";
count++;
}
int count;
};
void test04(){
vector v;
v.push_back(1);
v.push_back(3);
v.push_back(5);
v.push_back(2);
//通过for_each算法 遍历容器元素
print myprint;
//函数对象做返回值和参数
myprint = for_each(v.begin(), v.end(), myprint);
cout << endl;
cout << "函数对象调用次数:" << myprint.count << endl;
}
int main(){
test01();
test02();
test03();
test04();
system("pause");
return EXIT_SUCCESS;
}
谓词概念
谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式。
struct myfuncobj01{
bool operator()(int v)const{} //接受一个参数,并且返回值为Bool 即一元谓词
}
bool compare01(int v); //同样是叫做一元谓词
struct myfuncobj02{
bool operator()(int v1,int v2)const{} //接受两个参数,返回值为Bool 即二元谓词
}
bool compare02(int v1,int v2); //同样是叫做二元谓词
上面想将struct改为class也行,不过要在重载函数前加public,因为class内默认是private
内建函数对象
STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。
使用内建函数对象,需要引入头文件 #include
6个算数类函数对象,除了negate是一元运算,其他都是二元运算。
template T plus//加法仿函数
template T minute//减法仿函数
template T multiplies//乘法仿函数
template T divides//除法仿函数
template T modulus//取模仿函数
template T negate//取反仿函数
6个关系运算类函数对象,每一种都是二元运算。
template bool equal_to//等于
template bool not_equal_to//不等于
template bool greater//大于
template bool greater_equal//大于等于
template bool less//小于
template bool less_equal//小于等于
逻辑运算类运算函数,not为一元运算,其余为二元运算。
template bool logical_and//逻辑与
template bool logical_or//逻辑或
template bool logical_not//逻辑非
使用例子:
//使用内建函数对象声明一个对象
plus myPlus;
cout << myPlus(5, 3) << endl;
//使用匿名临时对象
cout << plus()(5, 6) << endl;
sort排序使用预定义函数对象进行排序。
count_if equal_to 参数绑定
函数对象适配器
函数对象适配器是完成一些配接工作,这些配接包括绑定(bind),否(negate),以及对一般函数或成员函数的修饰,使其成为函数对象,重点掌握函数对象适配器(红色字体):
bind1st :将参数绑定为函数对象的第一个参数
bind2nd : 将参数绑定为函数对象的第二个参数
not1 : 对一元函数对象取反
not2 : 对二元函数对象取反
ptr_fun : 将普通函数修饰成函数对象
mem_fun : 将成员函数修饰成函数对象,当容器内是对象指针时用这个,这是与mem_fun_ref的区别
mem_fun_ref : 将成员函数修饰成函数对象
预定义函数对象
仿函数适配器bind1st bind2nd
仿函数适配器not1 not2
仿函数适配器 ptr_fun
成员函数适配器 mem_fun mem_fun_ref
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
using namespace std;
/*
template T plus//加法仿函数
template T minute//减法仿函数
template T multiplies//乘法仿函数
template T divides//除法仿函数
template T modulus//取模仿函数
template T negate//取反仿函数
*/
//预定义函数对象
class print{
public:
void operator()(int v){
cout << v << " ";
}
};
void test01(){
plus myplus; //实例化一个对象
int ret = myplus(10, 20);
cout << "ret : " << ret << endl;
cout << plus()(30, 40) << endl;
vector v1, v2, v3;
for (int i = 0; i < 10;i++){
v1.push_back(i);
v2.push_back(i + 1);
}
v3.resize(v1.size());
transform(v1.begin(),v1.end(),v2.begin(),v3.begin(),plus());
for_each(v1.begin(), v1.end(), print());
cout << endl;
for_each(v2.begin(), v2.end(), print());
cout << endl;
for_each(v3.begin(), v3.end(), print());
cout << endl;
}
//函数适配器bind1st bind2nd
//现在我有这个需求 在遍历容器的时候,我希望将容器中的值全部加上100之后显示出来,怎么做哇?
struct myprint : public binary_function{ //二元函数对象 所以需要继承 binary_fucntion<参数类型,参数类型,返回值类型>
void operator()(int v1 ,int v2) const{
cout << v1 + v2 << " ";
}
};
void test02(){
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//我们直接给函数对象绑定参数 编译阶段就会报错
//for_each(v.begin(), v.end(), bind2nd(myprint(),100));
//如果我们想使用绑定适配器,需要我们自己的函数对象继承binary_function 或者 unary_function
//根据我们函数对象是一元函数对象 还是二元函数对象
for_each(v.begin(), v.end(), bind2nd(myprint(), 100));
cout << endl;
//总结: bind1st和bind2nd区别?
//bind1st : 将参数绑定为函数对象的第一个参数
//bind2nd : 将参数绑定为函数对象的第二个参数
//bind1st bind2nd将二元函数对象转为一元函数对象
}
//函数对象适配器 not1 not2
struct myprint02 {
void operator()(int v1) const{
cout << v1 << " ";
}
};
void test03(){
vector v;
v.push_back(2);
v.push_back(1);
v.push_back(5);
v.push_back(4);
vector::iterator it = find_if(v.begin(), v.end(), not1(bind2nd(less_equal(), 2)));
cout << "it:" << *it << endl;
sort(v.begin(),v.end(),not2(greater()));
for_each(v.begin(), v.end(), myprint02());
cout << endl;
//not1 对一元函数对象取反
//not2 对二元函数对象取反
}
//如何给一个普通函数使用绑定适配器(bind1st bind2nd)绑定一个参数?(拓展)
//ptr_fun
void myprint04(int v1,int v2){
cout << v1 + v2 << " ";
}
void test04(){
vector v;
v.push_back(2);
v.push_back(1);
v.push_back(5);
v.push_back(4);
//1 将普通函数适配成函数对象
//2 然后通过绑定器绑定参数
for_each(v.begin(), v.end(), bind2nd(ptr_fun(myprint04),100));
cout << endl;
//总结: ptr_fun 将普通函数转变为函数对象
}
//mem_fun mem_fun_ref
//如果我们容器中存储的是对象或者对象指针,如果能指定某个成员函数处理成员数据。
class student{
public:
student(string name, int age) :name(name), age(age){}
void print(){
cout << "name:" << name << " age:" << age << endl;;
}
void print2(int a){
cout << "name:" << name << " age:" << age << " a:" << a << endl;
}
int age;
string name;
};
void test05(){
//mem_fun : 如果存储的是对象指针,需要使用mem_fun
vector v;
student* s1 = new student("zhaosi",10);
student* s2 = new student("liuneng", 20);
student* s3 = new student("shenyang", 30);
student* s4 = new student("xiaobao", 40);
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
v.push_back(s4);
for_each(v.begin(), v.end(), mem_fun(&student::print));
cout << "-----------------------------" << endl;
//mem_fun_ref : 如果存储的是对象,需要使用mem_fun_ref
vector v2;
v2.push_back(student("zhaosi",50));
v2.push_back(student("liuneng", 60));
v2.push_back(student("shenyang", 70));
v2.push_back(student("xiaobao", 80));
for_each(v2.begin(), v2.end(), mem_fun_ref(&student::print));
}
int main(){
//test01();
//test02();
//test03();
//test04();
test05();
system("pause");
return EXIT_SUCCESS;
}
如果希望函数对象适配器能对我们自己编写的函数对象有效,我们需要根据我们的函数对象类型继承STL的父类对象。
如果你本身是二元函数对象 需要继承
二元函数继承:public binary_function<参数类型,参数类型,返回类型>
一元函数继承:public unary_function<参数类型,返回类型>
如果是普通函数、成员函数转化成的函数对象就不需要继承