理解STL中的函数子,函数子类,和其用法

 

本文最初发表于SpriteLW的博客http://blog.csdn.net/SpriteLW,欢迎转载,但请务必保留原文完整,并保留本声明。 

首先要知道什么是函数子,什么是函数子类,与其和函数的区别。简单地说,函数子是一个对象,而函数子类是该对象的类,并且该类要实现operator();函数是在类之外的函数,例如:

struct  MaxWeight: public  binary_function < Widget,Widget, bool >
{
    
bool   operator ()( const  Widget &  lhs, const  Widget  & rhs)
    {
        
return  lhs.m_weigth  >  rhs.m_weigth ;
    }
};
int  Print( const  Widget  & w)
{
    printf(
" %d  " ,w.m_weigth);
    
return   0 ;
}
       类MaxWeight为函数子类,Print为函数。用class或struct因个人风格而定。
 
       设类Widget有属性weight,现要对它进行显示。有以下几种方法
#include  < vector >
#include 
< iostream >
#include 
< functional >
#include 
< algorithm >

using   namespace  std;
class  Widget
{
public :
    
int  m_weight;
    
// 成员函数
     int  printWithClassMemberFunction()
    {
        cout
<< m_weight << "   " ;
        
return   0 ;
    }
    
// 内部函数子类
     struct  PrintWithInnerClass: public  unary_function < Widget, void >
    {
        
void   operator ()( const   Widget  & w)
        {
            cout
<< w.m_weight << "   " ;
        }
    };
};

// 外部函数子类
struct  PrintWithOuterClass: public  unary_function < Widget, void >
{
    
void   operator ()( const   Widget  & w)
    {
        cout
<< w.m_weight << "   " ;
    }
};
// 外部函数
int  PrintWithOuterFunction( const  Widget  & w)
{
    cout
<< w.m_weight << "   " ;
    
return   0 ;
}

int  main( int  argc,  char *  argv[])
{
    
const   int  MaxCount  =   20 ;
    
// 容器元素为非指针
    vector < Widget >  vDataWithNonPoint;
    
for int  i = 0 ; i < MaxCount; i ++ )
    {
        Widget w;w.m_weight 
=  rand()  %  MaxCount;
        vDataWithNonPoint.push_back(w);
    }
    cout
<< " PrintWithOuterFunction: " << endl;
    for_each(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),PrintWithOuterFunction);

    cout
<< endl << " ptr_fun(PrintWithOuterFunction): " << endl;
    for_each(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),ptr_fun(PrintWithOuterFunction));

    cout
<< endl << " mem_fun_ref(Widget::printWithClassMemberFunction) " << endl;
    for_each(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),mem_fun_ref(Widget::printWithClassMemberFunction));

    cout
<< endl << " Widget::PrintWithInnerClass() " << endl;
    for_each(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),Widget::PrintWithInnerClass());

    cout
<< endl << " PrintWithOuterClass() " << endl;
    for_each(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),PrintWithOuterClass());

    cout
<< endl;
    system(
" PAUSE " );
    
return   0 ;
}
 
输出如下:
PrintWithOuterFunction:
1 7 14 0 9 4 18 18 2 4 5 5 1 7 1 11 15 2 7 16
ptr_fun(PrintWithOuterFunction):
1 7 14 0 9 4 18 18 2 4 5 5 1 7 1 11 15 2 7 16
mem_fun_ref(Widget::printWithClassMemberFunction)
1 7 14 0 9 4 18 18 2 4 5 5 1 7 1 11 15 2 7 16
Widget::PrintWithInnerClass()
1 7 14 0 9 4 18 18 2 4 5 5 1 7 1 11 15 2 7 16
PrintWithOuterClass()
1 7 14 0 9 4 18 18 2 4 5 5 1 7 1 11 15 2 7 16
 
       有以下几个问题要注意:
1、  对PrintWithOuterFunction 和 ptr_fun(PrintWithOuterFunction) 操作,似乎ptr_fun是多余的。准确地说是在特定情况下ptr_fun可有可无,当要用not2,bind1st时就必须加上ptr_fun,因为ptr_fun的作用是把OuterFunction转unary_function<Widget,void>类似的类型,其它的还有binary_function,那正是not2,bind1st等函数所需要的
2、  为什么printWithClassMemberFunction返回int?如果不加ptr_fun则返回void也可以,但如果加了ptr_fun则必需要返回一个类型,不知是不是vc的原因,void似乎不认void为类型
3、  对函数子类的用法(外部类或内部类),类型名后一定要加()。似乎是调用operator(),其实不是,它是创建了一个匿名对象,俗称“函数子”,所以for_each里调用的都是一个函数子。
4、  为什么我要注明“容器元素为非指针”?回答这个问题,我要对上述每个函数作一个讲解。
4.1 for_each(。。。。,PrintWithOuterFunction):
        for_each每次迭代都传给 函数PrintWithOuterFunction一个Widget,这正是PrintWithOuterFunction形参的类型
 
4.2 for_each(。。。。, mem_fun_ref(Widget::printWithClassMemberFunction)):
        for_each每次迭代都对容器中的一个元素 I 调用 I. printWithClassMemberFunction()。注意,因为容器元素类型为“非指针”,所以调用”.”方法,当容器元素类型为“指针”时,则要将mem_fun_ref改为mem_fun,在内部,它对每个容器元素I,调用I->printWithClassMemberFunction()。(如果printWithClassMemberFunction有参数呢?那就要调用bind方法了)
 
4.3 Widget::PrintWithInnerClass()和PrintWithOuterClass():
        For_each会对函数子进行操作,调用void operator()(const Widget &w),那么for_each怎么会知道要传一个Widget参数和返回void呢?那是因为函数子类继承自unary_function<Widget,void>的原因,其中<>中,第一个为参数类型,第二个为返回类型。
 
到目前为止,我们的“函数子”都是一个参数或无参数的,现在要看有两个参数的情况,那就是要为Widget排序:
 
#include  < vector >
#include 
< iostream >
#include 
< functional >
#include 
< algorithm >

using   namespace  std;
class  Widget
{
public :
    
int  m_weight;
    
// 成员函数
     bool   operator < ( const  Widget &  rhs)
    {
        
return   this -> m_weight < rhs.m_weight;
    }
    
// 成员函数
     bool  LessWeightWithMemberFunction( const  Widget  & rhs)
    {
        
return   this -> m_weight < rhs.m_weight;
    }
    
// 内部类
     struct  LessWeightWithInnerClass: public  binary_function < Widget,Widget, bool >
    {
        
bool   operator ()( const  Widget &  lhs, const  Widget &  rhs)  const
        {
            
return  lhs.m_weight < rhs.m_weight;
        }
    };
};
// 调用less<Widget>时内部调用operator<
bool   operator < ( const  Widget &  lhs, const  Widget &  rhs)
{
    
return  lhs.m_weight < rhs.m_weight;
}

bool  lessWeightWithOutFunction( const  Widget &  lhs, const  Widget &  rhs)
{
    
return  lhs.m_weight < rhs.m_weight;
}
// 外部函数子类
struct  LessWeightWithOuterClass: public  binary_function < Widget,Widget, bool >
{
    
bool   operator ()( const  Widget &  lhs, const  Widget &  rhs)  const
    {
        
return  lhs.m_weight < rhs.m_weight;
    }
};

// 外部函数子类
struct  PrintWithOuterClass: public  unary_function < Widget, void >
{
    
void   operator ()( const   Widget  & w)
    {
        cout
<< w.m_weight << "   " ;
    }
};

int  main( int  argc,  char *  argv[])
{
    
const   int  MaxCount  =   20 ;
    
// 容器元素为非指针
    vector < Widget >  vDataWithNonPoint;
    
for int  i = 0 ; i < MaxCount; i ++ )
    {
        Widget w;w.m_weight 
=  rand()  %  MaxCount;
        vDataWithNonPoint.push_back(w);
    }
    
// 默认调用类内部的operator<
    sort(vDataWithNonPoint.begin(),vDataWithNonPoint.end());
    
// 调用外部的bool operator<(const Widget& lhs,const Widget& rhs)
    sort(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),less < Widget > ());
    
// 调用类成员函数
    sort(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),mem_fun1_ref(Widget::LessWeightWithMemberFunction ));
    
// 调用外部函数
    sort(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),lessWeightWithOutFunction);
    
// 调用内部函数子类
    sort(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),Widget::LessWeightWithInnerClass());
    
// 调用外部函数子类
    sort(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),LessWeightWithOuterClass());

    for_each(vDataWithNonPoint.begin(),vDataWithNonPoint.end(),PrintWithOuterClass());
    cout
<< endl;
    system(
" PAUSE " );
    
return   0 ;
}
 
有以下几个问题要注意:
1、函数子类继承自binary_function<Widget,Widget,bool>,它表示要输入两个参数,并返回bool。
2、成员函数的“包装”由mem_fun_ref改为mem_fun1_ref
 
 
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值