十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
为什么我们需要使用仿函数(仿函数解决了什么痛点)?
成都创新互联2013年至今,先为罗平等服务建站,罗平等地企业,进行企业商务咨询服务。为罗平企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。仿函数的优点和作用?
文章目录场景引入
计算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;
}
#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;
}
这样就解决了效率和函数重载的问题了。
场景二#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<
bool IsGreaterThanThreshold(int num, int threshold) {return num>threshold ? true : false;
}
(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;
}
这种方法扩展性较差,当函数参数有所变化,则无法兼容旧的代码,具体在第一小节已经阐述。正如上面的例子,在我们写代码时有时会发现有些功能代码,会不断地被使用。为了复用这些代码,实现为一个公共的函数是一个解决方法。不过函数用到的一些变量,可能是公共的全局变量。引入全局变量,容易出现同名冲突,不方便维护。
这时就可以使用仿函数了,写一个简单类,除了维护类的基本成员函数外,只需要重载 operator() 运算符 。这样既可以免去对一些公共变量的维护,也可以使重复使用的代码独立出来,以便下次复用。而且相对于函数更优秀的性质,仿函数还可以进行依赖、组合与继承等,这样有利于资源的管理。如果再配合模板技术和 Policy 编程思想,则更加威力无穷,大家可以慢慢体会。Policy 表述了泛型函数和泛型类的一些可配置行为(通常都具有被经常使用的缺省值)。
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;
}
仿函数(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元起,快前往官网查看详情吧