Функциональные объекты

Feb 07, 2009 20:19


Функциональные объекты (или функторы) - шикарная штука. По воле случая (а точнее, по моей воле) объяснял своим студентам, что это такое - теперь напишу о них и в блоге.


Функциональным объектом называется объект класса, в котором определён (переопределён) оператор выполнения - круглые скобки. Это означает, что данный объект можно использовать как функцию:

class functor_
{
    int data;
public:
    functor_(int p = 0): data(p) {}
    int operator()(){return data;}
};

int main()
{
    functor_ f;
    f();
    return 0;
}

Как видно, функтор ведет себя как указатель на функцию. Однако для меня лично писать конструкции типа int (*pmin)(const int& a, const int& b) всегда было жутко, хотя ничего страшного в этом нет. Так вот, какие преимущества у функторов перед указателями на функции? Основной плюс - функтор может содержать дополнительную информацию о параметрах. Собственно, один и тот же функтор даже может менять своё поведение, в зависимости от существующих условий (состояния окружающей среды). Ярким примером преимуществ функторов являет собой стандартная библиотека с++.

Пример использования - предположим, у нас есть список строк. Необходимо найти первую строку, содержащую некоторую подстроку (вообще-то, даже все). Как это сделать? В стандартной библиотеке с++ есть функция find и её вариант fin_if - как раз данными вещами занимающаяся. Но если мы ищем наличие подстроки в строке, то одним сравнением не обойтись. В нашем случае подходит как раз вариант find_if, принимающий в качестве последнего параметра указатель на функцию (или функциональный объект) - унарный предикат. Унарный предикат - это функция, принимающаяодин параметр и возвращающая true/false. Этот предикат применяется к каждому элементу списка. А как же он получит информацию о подстроке, наличие которой мы ищем?! Здесь нам и помогает функтор. Смотреть пример!

#include
#include
#include
#include

using namespace std;

class substr_
{
    string str;
public:
    bool operator()(const string& s)
    {
        if(s.find(str) == s.npos)    // когда подстрока не найдена, значение функции равно количеству символов в строке.
        {
            return false;
        }
        return true;
    }
    substr_(string s = "") :str(s) {}    // конструктор функтора.
};

int main()
{
    list ls;
    ls.push_back("vasea");
    ls.push_back("petea");
    ls.push_back("vanea");
    ls.push_back("olea");
    ls.push_back("liuda");

substr_ contain("l");     // теперь функтор знает, какую подстроку искать

list::iterator i = find_if(ls.begin(), ls.end(), contain);
    cout << *i << endl;
    return 0;
}

Как видно, ничего сложного. А иногда и полезно.

С++, функторы, программирование

Previous post Next post
Up