Functor仿函数

转载声明:本文转自网络,稍加整理以备学习和參考之用。

函数对象/仿函数

提到C++ STL。首先被人想到的是它的三大组件:Containers, Iterators, Algorithms,即容器,迭代器和算法。容器为用户提供了经常使用的数据结构,算法大多是独立于容器的经常使用的基本算法,迭代器是由容器提供的一种接口。算法通过迭代器来操控容器。接下来要介绍的是另外的一种组件。 函数对象 (Function Object,JJHou译作Functor 仿函数 )。
什么是函数对象

  顾名思义,函数对象首先是一个对象,即某个类的实例

其次,函数对象的行为和函数一致,即是说能够像调用函数一样来使用函数对象,如參数传递、返回值等。

这样的行为是通过重载类的()操作符来实现的

仿函数:用途和适用的场合
  之所以要开发仿函数(functors),是由于函数不能容纳不论什么有意义的状态。

比如。使用函数,你不能为某个元素加一个随意值。再将其应用于一个范围。可是,使用仿函数可轻易做到这一点。

举个栗子。。。

#include <iostream>
#include <algorithm>
using  namespace  std;
//回调函数
void  call_back( char  elem)
{
  cout << elem << endl;
}
//仿函数
struct  Functor
{
  void  operator() ( char  elem) 
  {
   cout << elem << endl;
 
};
int  main()
{
  string strA =  "hello" ;
  string strB =  "world" ;
  
  for_each(strA.begin(),strA.end(),Functor());
  cout<< "===========GAP===============" <<endl;
  for_each(strB.begin(),strB.end(),call_back);
  getchar ();
  return  0;
}

h
e
l
l
o
===========GAP===============
w
o
r
l
d

可能会有疑问两者有什么差别?

假如我要for_each遍历的不是字符串而是int类型的vector呢?

是不是又要重写一个int类型作为參数的回调函数,那假设有N种类型的容器遍历岂不是要写N个回调函数或N个仿函数类?

非也!!!

C++有类模板 也有 函数模板 相同能够用于回调

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <algorithm>
#include <vector>
using  namespace  std;
//模板函数
template < typename  T>
void  call_back(T elem)
  cout<< elem <<endl;
}
//仿函数
template < typename  T>
class  Functor
{
public :
  Functor()
   :m_val(0)
  {
   cout<<  "Functor()"  <<endl;
  }
  ~Functor()
  {
   cout<< "~Functor()" <<endl;
  }
  void  operator() (T elem) 
  {
   Do(elem);
  }
  
  //举个栗子
  void  Do(T elem)
  {
   m_val+=elem;
   cout<<elem<< "/" <<m_val<<endl;
  }
private :
  T m_val;
};
  
int  main()
{
  vector< int > vec;
  vec.push_back(1);
  vec.push_back(2);
  vec.push_back(3);
  vec.push_back(4);
  vec.push_back(5);
  for_each(vec.begin(),vec.end(),call_back< int >);
  cout<< "===========GAP===============" <<endl; 
  for_each(vec.begin(),vec.end(),Functor< int >());
  return  0;
}

1
2
3
4
5
===========GAP===============
Functor()
1/1
2/3
3/6
4/10
5/15
~Functor()
~Functor()
~Functor()

 

三次析构的原因:

先附上for_each的源代码(VC2008)

?

1
2
3
4
5
6
7
8
9
10
11
template < class  _InIt, class  _Fn1>
inline  _Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
// perform function for each element
  _DEBUG_RANGE(_First, _Last);
  _DEBUG_POINTER(_Func);
  _CHECKED_BASE_TYPE(_InIt) _ChkFirst(_CHECKED_BASE(_First));
  _CHECKED_BASE_TYPE(_InIt) _ChkLast(_CHECKED_BASE(_Last));
  for  (; _ChkFirst != _ChkLast; ++_ChkFirst)
   _Func(*_ChkFirst);
  return  (_Func);
}
?
1
2
3
4
5
Functor<int>() 产生暂时对象传參(值) 构造一次,析构一次 
for_each參数值传递,拷贝构造一次,析构一次(函数内部)
for_each返回仿函数的对象(值),拷贝构造一次,析构一次
由于没有重载拷贝构造函数 所以打印出第一次创建暂时对象时的普通构造函数
实际上在这个过程中一共产生过三个仿函数对象

 

假设把代码改变下:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <algorithm>
#include <vector>
using  namespace  std;
 
template < typename  T>
class  Functor
{
public :
  Functor()
   :m_val(0)
  {
   cout<<  "Functor()" << this <<endl;
  }
  Functor(Functor& that)
  {
   this ->m_val = that.m_val;
   cout<<  "Copy Functor()"  << this <<endl;
  }
  ~Functor()
  {
   cout<< "~Functor()" << this <<endl;
  }
  void  operator() (T elem) 
  {
   Do(elem);
  }
  
  //举个栗子
  void  Do(T elem)
  {
   m_val+=elem;
   cout<<elem<< "/" <<m_val<<endl;
  }
  T getVal()
  {
   return  m_val;
  }
private :
  T m_val;
};
  
int  main()
{
  vector< int > vec;
  vec.push_back(1);
  vec.push_back(2);
  vec.push_back(3);
  vec.push_back(4);
  vec.push_back(5);
 
  Functor< int > func;
  Functor< int >&  ref  = for_each(vec.begin(),vec.end(),func);
  cout<< ref .getVal()<<endl;
  
  return  0;
}

执行结果

Functor()0032F800           //main函数中的实參仿函数对象
Copy Functor()0032F68C  //值传递 对【实參对象】拷贝构造了形參对象

1/1
2/3
3/6
4/10
5/15
Copy Functor()0032F7E8 //返回对象的值类型  对【形參对象】拷贝构造

~Functor()0032F68C       //析构形參对象
15
~Functor()0032F7E8       //析构返回值对象
~Functor()0032F800      //析构实參对象

如今一目了然了吧!

 

使用回调函数高效 由上面的样例能够看出 构造1次 拷贝构造2次 析构3次  是有代价的

 

最后回到仿函数和回调函数

差别在于:

  1. 使用仿函数能够声明在业务相关的类内部 缩小作用域

  2. 使用仿函数能够使用类的成员属性和成员函数

  3. 仿函数是一个 能够使用面向对象的各种机制(封装 继承 多态)

  4. 若使用回调函数 那么仅仅能声明为某个类的静态成员函数或全局函数。使用类内部的资源须要用一些手段传參,没有直接使用成员函数便捷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值