转载声明:本文转自网络,稍加整理以备学习和參考之用。
函数对象/仿函数
什么是函数对象
顾名思义,函数对象首先是一个对象,即某个类的实例。
其次,函数对象的行为和函数一致,即是说能够像调用函数一样来使用函数对象,如參数传递、返回值等。
这样的行为是通过重载类的()操作符来实现的,
之所以要开发仿函数(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次 是有代价的
最后回到仿函数和回调函数
差别在于:
-
使用仿函数能够声明在业务相关的类内部 缩小作用域
-
使用仿函数能够使用类的成员属性和成员函数
-
仿函数是一个类 能够使用面向对象的各种机制(封装 继承 多态)
-
若使用回调函数 那么仅仅能声明为某个类的静态成员函数或全局函数。使用类内部的资源须要用一些手段传參,没有直接使用成员函数便捷