《C++标准程序库》学习笔记6 — 第八章

这一章讲的是仿函数(Functor),大陆叫函子(咋听起来那么别扭。。。),需要把第五章的仿函数部分看明白。

  • 1.(P124)

仿函数的基础:
行为类似函数,从实现的角度来看,仿函数是一种重载了Operator()的Class 或 Class Template。一般函数指针可视为狭义的仿函数。

函数行为:指可以”使用小括号传递参数,藉以调用某个东西”, eg. function(arg1, arg2)。

如果希望对象也可以这样,可以通过重载”()”操作符(operator() ),并给予合适的参数型别:

1
2
3
4
5
6
class X{
public:
    // define "function call" operator
    return-type operator() (arguements) const;
    ...
};

现在,就可以把这个对象当做函数调用了”

1
2
3
X tk;
...
tk(arg1, arg2);

上述调用等价于:

1
tk.operator() (arg1, arg2);
  • 2.(P125)

入门级的仿函数程序,可以更清楚的理解神马是仿函数。

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
#include <iostream> 
#include <string> 
#include <set> 
#include <vector> 
#include <algorithm> 
using namespace std; 
 
class PrintInt 
{ 
public: 
    void operator() (int elem) const { 
        cout << elem << " "; 
    } 
}; 
 
int main() 
{ 
    vector<int> coll; 
 
    for(int i=1; i<=9; ++i) 
        coll.push_back(i); 
 
    for_each(coll.begin(), coll.end(), PrintInt());   // ———- ① 
    cout << endl; 
    return 0; 
}
  • 3.(P128)

仿函数的优点:
①.仿函数可以拥有自己的状态(state),所以比一般函数更灵巧。
②.仿函数都有其型别。
③.执行速度上,仿函数比函数指针更快。

在编译期间像函数传递参数,可以使用模板,但是模板必须是常量。这时,可以选择用仿函数。
具体对比P(128)~P(129)的两个例子。

  • 4.(P294)

对于仿函数的个人理解:
仿函数就是一个类,而使用仿函数使其模拟函数行为就是利用类对象的()操作符,即调用Class()。
要使用仿函数的operator(),可以选择建一个临时对象或者普通的类对象。
建临时对象如上述第二点中的代码中,注意为①的那一行。
PrintInt()是建立一个临时仿函数对象。
当然,也可以选择:

1
2
PrintInt prin();
for_each(coll.begin(), coll.end(), prin);   //这样就容易理解一些。

关于更多对仿函数对象使用的讨论,可以看我在CSDN上的求助帖:
http://topic.csdn.net/u/20110129/00/1a9db6ac-a65e-460b-aaaa-554e2bdf6450.html?seed=1711992303&r=71476802

  • 5.(P298)

将仿函数以passed by reference方式传递。
这样就可以改变仿函数的状态。

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
// print.h 
#include <iostream> 
using namespace std; 
 
template <class T> 
inline void PRINT_ELEMENTS(const T& coll, const char* optcstr="") 
{ 
    typename T::const_iterator pos; 
    cout << optcstr; 
    for(pos=coll.begin(); pos!=coll.end(); ++pos) 
        cout << *pos << ‘ ‘; 
    cout << endl; 
}
 
 
 
// main.cpp
#include <iostream> 
#include <string> 
#include <set> 
#include <vector> 
#include <list> 
#include <algorithm> 
#include "print.h" 
using namespace std; 
 
class IntSequence{ 
private: 
    int value; 
public: 
    IntSequence (int initialValue) 
        : value(initialValue) {} 
    int operator() () { 
        return value++; 
    } 
}; 
 
int main() 
{ 
    //freopen("out.txt", "w", stdout); 
    list<int> coll; 
    IntSequence seq(1); 
 
    generate_n<back_insert_iterator<list<int> >, 
                int, IntSequence&>(back_inserter(coll), 
                4, 
                seq); 
 
    PRINT_ELEMENTS(coll); 
 
    generate_n(back_inserter(coll), 
                4, 
                IntSequence(42)); 
    PRINT_ELEMENTS(coll); 
 
    generate_n(back_inserter(coll), 
                4, 
                seq); 
    PRINT_ELEMENTS(coll); 
 
    generate_n(back_inserter(coll), 
                4, 
                seq); 
    PRINT_ELEMENTS(coll); 
}

输出结果:
1 2 3 4
1 2 3 4 42 43 44 45
1 2 3 4 42 43 44 45 1 2 3 4
1 2 3 4 42 43 44 45 1 2 3 4 1 2 3 4

  • 6.(P305)

预定义的仿函数
要使用这些仿函数,必须包含头文件

1
#include <functional>

functor

发布者

Tanky Woo

Tanky Woo,[个人主页:https://tankywoo.com] / [新博客:https://blog.tankywoo.com]

《《C++标准程序库》学习笔记6 — 第八章》有3个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注