Функциональные объекты (или функторы) - шикарная штука. По воле случая (а точнее, по моей воле) объяснял своим студентам, что это такое - теперь напишу о них и в блоге.
Функциональным объектом называется объект класса, в котором определён (переопределён) оператор выполнения - круглые скобки. Это означает, что данный объект можно использовать как функцию:
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;
}
Как видно, ничего сложного. А иногда и полезно.