mem_fun所用的模板的具体化
仿函数是一种具有函数特质的对象,由于内部重载了括号操作符(),所以调用者可以像使用函数一样使用仿函数。
mem_fun()是一个适配器(adapter),该函数能将类的成员函数包装成仿函数使用,于是成员函数可以搭配各种泛型算法完成所谓的多态调用。
具体例子如下面的代码所示。用vector<D*>
存放E和F的指针,在泛型算法for_each()
中使用D的成员函数print()
遍历vector。
#include <iostream>
#include <functional>
#include <vector>
#include<algorithm>
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<D*> 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<void, D>的构造函数,
//并参与构造一个临时对象(作为之后泛型算法使用的仿函数)
//在这里,仿函数等于临时对象
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_function<D*, void>
{ // 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