函数对象(functor)简介

本文探讨了函数对象(伪函数)的概念及其相对于传统函数指针的优势,特别是在参数灵活性及面向对象封装方面。通过示例展示了如何使用模板实现函数对象,并讨论了其在临时对象传递中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数对象又叫伪函数.函数对象本来是一个类,但由于基本上没干啥事,就只封装一个函数在里面,并且被封装的函数还是通过重载运算符()来实现.

可能你很是纳闷,为啥搞个这东东出来啊?

其实是这样的,刚开始一些简单应用完全用个函数完全可以搞定,传个函数指针就行了.但这样不够灵活,可扩展性不好.于是干脆整个类出来得了.

 

函数指针的缺陷

还是举个例子来瞧瞧吧~

如果我们有个工厂要招人,然后要符合很多标准才行.本着分工合作的原则,那个判断符合条件的工作完全由另一个函数来完成.(当然这只是为了举例方便,有点牵强的)

假如函数IsOK(int userID)来判断符合条件不.

bool IsOK(int userID)

{

    //假如通过userID在数据库查找各种信息,然后判断

   int age = GetAge(userID);  //这个函数的实现就省略了,其他很多判断信息也不管了

   if( age > 18)

       return true;

    else

      return false;

}

void PrintAllLaborName(int userID, string name , bool (*pFun)(int))   //第二个参数是个函数指针

{

    if( pFun(userID) )  //符合条件则打印姓名

         cout<<name<<endl;

}

 

如果是简单的应用,就像上面一样在PrintAllLaborName中传个函数指针就行了,但啥时突然要变成需要其他一些条件,函数的参数要变.这样改起来就不太方便.

假如IsOK(int )要变成 IsOk(int , string) ,这样就得有两处要改了.一个是IsOK函数本身,另一个就是PrintAllLaborName的参数.

那我们知道面向对象类的好处就是封装,对外提供接口就行了.要改只改类里面的,接口不变.于是我们就想着把函数IsOK封装到一个类里面去.

 

函数对象

template<class T>

struct CheckCondition  //这就是一个函数对象,只要重载运算符()

{

   bool operator() (int userID , T otherInfo)  //假如有很多信息要传,到时定义一个类然后用T传过来就行的

   {

        // if( Check( userID , otherInfo) )  这里就不实现该功能了

            return true;

         //else

           //return false;

     }

}

 

template<class T>

void PrintAllLaborName(int userID, string name , T fun) //第二个参数是个函数对象

{

if( fun(userID, name ) //符合条件则打印姓名

cout<<name<<endl;

}

 

测试代码

PrintAllLaborName ( 123, "arwen" , CheckCondition<string>() );

 

函数对象传函数时的迷惑

看完例子你可能有两个疑问,

一个是重载运算符()的好处,

另一个是函数对象用起来有点怪怪的.都没有看到那个类在哪里实例化

 

重载()的好处是它的参数不受限制的,所以你可以模仿任意函数.而像其他运算符(一元运算符,二元运算符)只能有一个或两个参数.

 

函数对象的实例化:

首先是函数的形参是个类,然后里面调用,这好理解

template<class T>

void PrintAllLaborName(int userID, string name , T fun)

然后里面调用fun(userID, name )

 

但这里就不明白了

PrintAllLaborName ( 123, "arwen" , CheckCondition<string>() );

CheckCondition<string>()这个参数也太怪了吧.

如果是CheckCondition<string> checkCon;

然后PrintAllLaborName ( 123, "arwen" , checkCon);这样就非常好理解了.

实例化成一个对象,然后传过去就好了嘛.实际上这样是完全可以的,一点也没错.

 

不过大多数时候我们却没这样用,而是CheckCondition<string>()这样用,为啥? 因为这样有这么个好处.

我们知道CheckCondition<string> checkCon;这样实例化一个对象后,等你调用完了函数PrintAllLaborName该对象仍然没出作用域,没有被析构掉.

而CheckCondition<string>()就是调用构造函数,这样是传一个临时对象过去,一调用完函数就被析构(调用完立马被析构,这就是好处)

 

PrintAllLaborName ( 123, "arwen" , CheckCondition<string>() )这样传个参数过去,发生的动作是

void PrintAllLaborName(int userID, string name , T fun)

{

//下面两步操作是后台实现的

CheckCondition<string> tmp ;

fun = tmp;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值