您的位置:首页 > 编程语言 > C语言/C++

C++之STL(八):函数对象、 函数对象与容器、函数对象与算法

2014-09-11 08:59 417 查看
一、函数对象

1、函数对象(function object)也称为仿函数(functor)

2、一个行为类似函数的对象,它可以没有参数,也可以带有若干参数。

3、任何重载了调用运算符operator()的类的对象都满足函数对象的特征

4、函数对象可以把它称之为smart function。

5、STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件<functional>。

二、自定义函数对象

C++ Code
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream>

using namespace std;

class CFunObj

{

public:

void operator()()

{

cout << "hello,function object!" << endl;

}

};

int main()

{

CFunObj fo;

fo();

CFunObj()();

return 0;

}
注意:CFunObj()(); 表示先构造一个匿名对象,再调用operator();

三、函数对象与容器

在这边举map 容器的例子,大家都知道map 在插入元素的时候会自动排序,默认是根据key 从小到大排序,看map 的定义:

C++ Code
1

2

3

4

5

6

7

8

9

10

// TEMPLATE CLASS map

template < class _Kty,

class _Ty,

class _Pr = less<_Kty>,

class _Alloc = allocator<pair<const _Kty, _Ty> > >

class map

: public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false> >

{

// ordered red-black tree of {key, mapped} values, unique keys

};
假设现在我们这样使用 map< int, string > mapTest; 那么默认的第三个参数 _Pr = less<int>,再者,map 继承的其中一个类

_Tmap_traits 中有个成员:

_Pr comp;// the comparator predicate for keys

跟踪进insert 函数,其中有这样一句:

if (_DEBUG_LT_PRED(this->comp, _Key(_Where._Mynode()), this->_Kfn(_Val)))

已知 #define _DEBUG_LT_PRED(pred, x, y) pred(x, y) 很明显地,comp 在这里当作函数对象使用,传入两个参数,回头看less 类的

模板实现:

C++ Code
1

2

3

4

5

6

7

8

9

10

11

12

13

// TEMPLATE STRUCT less

template<class _Ty>

struct less

: public binary_function<_Ty, _Ty, bool>

{

// functor for operator<

bool operator()(const _Ty &_Left, const _Ty &_Right) const

{

// apply operator< to operands

return (_Left < _Right);

}

};

即实现了operator() 函数,左操作数小于右操作数时返回为真。

我们也可以在定义的时候传递第三个参数,如map< int, string, greater<int> > mapTest; 则插入时按key 值从大到小排序(less,

greater 都是STL内置的类,里面实现了operator() 函数),甚至也可以自己实现一个类传递进去,如下面例程所示:

C++ Code
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

#include <map>

#include <string>

#include <iostream>

using namespace std;

struct MyGreater

{

bool operator()(int left, int right)

{

return left > right;

}

};

int main(void)

{

map < int, string, /*greater<int> */MyGreater > mapTest;

mapTest.insert(map<int, string>::value_type(1, "aaaa"));

mapTest.insert(map<int, string>::value_type(3, "cccc"));

mapTest.insert(map<int, string>::value_type(2, "bbbb"));

for (map < int, string, /*greater<int> */MyGreater >::const_iterator it = mapTest.begin(); it != mapTest.end(); ++it)

{

cout << it->first << " " << it->second << endl;

}

return 0;

}
输出为:

3 cccc

2 bbbb

1 aaaa

MyGreater 类并不是以模板实现,只是比较key 值为int 类型的大小。

四、函数对象与算法

在STL一些算法中可以传入函数指针,实现自定义比较逻辑或者计算,同样地这些函数也可以使用函数对象来代替,直接看例程再稍

作分析:

C++ Code
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

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

#include <vector>

#include <string>

#include <iostream>

#include <algorithm>

using namespace std;

void PrintFun(int n)

{

cout << n << ' ';

}

void Add3(int &n)

{

n += 3;

}

class PrintObj

{

public:

void operator()(int n)

{

cout << n << ' ';

}

};

class AddObj

{

public:

AddObj(int number) : number_(number)

{

}

void operator()(int &n)

{

n += number_;

}

private:

int number_;

};

class GreaterObj

{

public:

GreaterObj(int number) : number_(number)

{

}

bool operator()(int n)

{

return n > number_;

}

private:

int number_;

};

int main(void)

{

int a[] = {1, 2, 3, 4, 5};

vector<int> v(a, a + 5);

/*for_each(v.begin(), v.end(), PrintFun);

cout<<endl;*/

for_each(v.begin(), v.end(), PrintObj());

cout << endl;

/*for_each(v.begin(), v.end(), Add3);

for_each(v.begin(), v.end(), PrintFun);

cout<<endl;*/

for_each(v.begin(), v.end(), AddObj(5));

for_each(v.begin(), v.end(), PrintFun);

cout << endl;

cout << count_if(a, a + 5, GreaterObj(3)) << endl; //计算大于3的元素个数

return 0;

}
输出为:

1 2 3 4 5

6 7 8 9 10

2

回顾for_each 的源码,其中有这样一句: _Func(*_ChkFirst);
也就是将遍历得到的元素当作参数传入函数。

上面程序使用了函数对象,实际上可以这样理解 PrintObj()(*_ChkFirst); 即 PrintObj() 是一个匿名的函数对象,传入参

数,调用了operator() 函数进行打印输出。使用函数对象的好处是比较灵活,比如直接使用函数Add3,那么只能将元素加3,而

使用函数对象Addobj(x), 想让元素加上多少就传递给Addobj类,构造一个对象即可,因为它可以保存一种状态(类成员)。

count_if 中的 GreaterObj(3) 就类似了,将遍历的元素当作参数传递给operator(), 即若元素比3大则返回为真。

五、STL内置的函数对象类



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: