Blog·Tanky WooABOUTRSS

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

29 Jan 2011
这篇博客是从旧博客 WordPress 迁移过来,内容可能存在转换异常。

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

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

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

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

class X{
public:
    // define "function call" operator
    return-type operator() (arguements) const;
    ...
};

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

X tk;
...
tk(arg1, arg2);

上述调用等价于:

tk.operator() (arg1, arg2);

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

#include  
#include  
#include  
#include  
#include  
using namespace std; 

class PrintInt 
{ 
public: 
    void operator() (int elem) const { 
        cout << elem << " "; 
    } 
}; 

int main() 
{ 
    vector coll; 

    for(int i=1; i<=9; ++i) 
        coll.push_back(i); 

    for_each(coll.begin(), coll.end(), PrintInt());   // ———- ① 
    cout << endl; 
    return 0; 
}

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

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

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

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

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

// print.h 
#include  
using namespace std; 

template  
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  
#include  
#include  
#include  
#include  
#include  
#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 coll; 
    IntSequence seq(1); 

    generate_n >, 
                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

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

#include 

functor