STL:深入mem_fun

mem_fun所用的模板的具体化

 仿函数是一种具有函数特质的对象,由于内部重载了括号操作符(),所以调用者可以像使用函数一样使用仿函数。
 mem_fun()是一个适配器(adapter),该函数能将类的成员函数包装成仿函数使用,于是成员函数可以搭配各种泛型算法完成所谓的多态调用。
 具体例子如下面的代码所示。用vector存放E和F的指针,在泛型算法for_each()中使用D的成员函数print()遍历vector。

#include 
#include 
#include 
#include
using namespace std;

class D {
public:
    int num;
    D(int i = 0) { num = i; }
    virtual void print() = 0;

};
class E :public D {
public:
    E(int i = 0) { num = i; }
    void print() { cout << "I'm a E. my num=" << num << endl; }
};

class F :public D {
public:
    F(int i = 0) { num = i; }
    void print() { cout << "I'm a F. my num=" << num << endl; }
};
int main()
{
    vector v;
    v.push_back(new E(1));
    v.push_back(new F(2));
    for_each(v.begin(), v.end(), mem_fun(&D::print));
    delete v[0];
    delete v[1];
    return 0;
}

运行结果:
这里写图片描述

 接下来详细介绍一下mem_fun()执行的原理。该函数的功能由一个模板函数和一个模板类实现

//1、模板函数mem_fun本身
        // TEMPLATE FUNCTION mem_fun
template<class _Result,
    class _Ty> inline
    mem_fun_t<_Result, _Ty> mem_fun(_Result (_Ty::*_Pm)())
    {   // return a mem_fun_t functor adapter
    return (mem_fun_t<_Result, _Ty>(_Pm));
    }

//2、模板类mem_fun_t
        // TEMPLATE CLASS mem_fun_t
template<class _Result,
    class _Ty>
    class mem_fun_t
        : public unary_function<_Ty *, _Result>
    {   // functor adapter (*p->*pfunc)(), non-const *pfunc
public:
    explicit mem_fun_t(_Result (_Ty::*_Pm)())
        : _Pmemfun(_Pm)
        {   // construct from pointer
        }

    _Result operator()(_Ty *_Pleft) const
        {   // call function
        return ((_Pleft->*_Pmemfun)());
        }

private:
    _Result (_Ty::*_Pmemfun)(); // the member function pointer
};

以最初的代码为例,以上的两个模板具体化后为:

//1、函数mem_fun本身
//mem_fun()的传入参数是void (D::*)()类型的函数指针,
//传入的函数指针&D::print被赋给了_Pm,
//_Pm又传入mem_fun_t的构造函数,
//并参与构造一个临时对象(作为之后泛型算法使用的仿函数)
//在这里,仿函数等于临时对象
mem_fun_t<void, D> mem_fun(void (D::*_Pm)())
{   // return a mem_fun_t functor adapter
return (mem_fun_t<void, D>(_Pm));
}

//2、模板类mem_fun_t
//类中有一个私有变量_Pmemfun,是类型为void (D::*)()的函数指针
//mem_fun_t调用构造函数时,传入的_Pm被拷贝给_Pmemfun
//mem_fun_t重载了括号操作符(),使得mem_fun_t实例出来的对象成为仿函数
//操作符()的功能是对传入的D*对象,调用其成员函数_Pmemfun
class mem_fun_t : public unary_functionvoid>
{   // functor adapter (*p->*pfunc)(), non-const *pfunc
public:
explicit mem_fun_t(void (D::*_Pm)())
    : _Pmemfun(_Pm)
    {   // construct from pointer
    }

void operator()(D *_Pleft) const
    {   // call function
    return ((_Pleft->*_Pmemfun)());
    }

private:
    void (D::*_Pmemfun)();  // the member function pointer
};

明白了原理后就可以针对性地把模板特化为一个类,我将其设计为func,示例代码可以改写为:

......
class func {
    void (D::*_Pmemfun)();  
public:
    explicit func(void (D::*_Pm)())
        : _Pmemfun(_Pm){}
    void operator()(D *_Pleft) const
    {   // call function
        return ((_Pleft->*_Pmemfun)());
    }
};
......
for_each(v.begin(), v.end(), func(&D::print));
......

最终的实现效果是一样的。

结论

 简而言之,for_each()函数的功能是遍历一个集合,并依次对集合中的每个元素执行一种操作。mem_fun()抽象出了这种操作(泛型算法),这种操作是借由仿函数完成的,同时这种操作也是类的成员函数实现的,仿函数包裹了类的成员函数。而类的纯虚函数和子类的成员函数一起实现了多态。至此,泛型算法和多态调用完美的结合在了一起。
 另一方面,这份代码中的操作符重载部分涉及到了纯虚函数的地址和调用问题,见我的另一篇文章:http://blog.csdn.net/popvip44/article/details/72763004

你可能感兴趣的:(C/C++)