С++ - язык, который изучается постепенно.ФУНКТОРЫ
                   Справочники Всё для создания сайта

Ссылки


Home
Бизнес
Справочники
Советы







Материалы книги получены с http://www.itlibitum.ru/

Функторы

Напоследок мы познакомимся с одной диковинкой C++, которая называется функтором (functor).

Функторы играют для функций ту же роль, что и интерфейсные указатели для объектов. Одна из

проблем, вечно мучивших программистов на С - то, что все функции находятся в глобальном

пространстве имен, то есть вызванная функция имеет доступ только к данным, хранящимся в ее

аргументах, и глобальным переменным. Если передать адрес функции еще кому-то, то при вызове

функции по адресу она не будет помнить, как выглядел окружающий мир во время получения ее

адреса.

В таких языках, как Паскаль, эта проблема изящно решается получением замыкания (closure) на

момент получения адреса функции.

procedure p(n: integer);

var

procedure fn;

begin

do_something(n);

end;

begin

callback(@fn);

end;

В качестве аргумента процедура саllbackfn получает адрес другой процедуры. В данном примере ей передается адрес fn. При вызове fn из callbackfn первая имеет доступ к переменным,

находившимся в стеке в момент получения адреса. В нашем примере fn знает значение переменной n на момент вызова саllbackfn.

Замыкания чрезвычайно полезны для обработки обратных вызовов (callback), поскольку функция

обратного вызова кое-что знает о том, почему она была вызвана. В С вложенных функций не

существует, а следовательно, замыкания невозможны - их место занимают функторы.

class Fn {

private:

int number;

public:

f(int n) : number(n) {}

void operator() () { do_something(number); }

};

void callbackfn(Fn);

void p(int n)

{

callbackfn(Fn(n));

}

void callbackfn(Fn fn)

{

// Что-то делаем

fn(); // Вызвать «функцию» fn с помощью функции operator()

}

Весь секрет кроется в двух выражениях. Функция callbackfn(Fn(n)) передает функции анонимный

экземпляр класса Fn. Аргумент его конструктора содержит информацию, включаемую в

«псевдозамыкание», которое поддерживается переменными класса Fn. Выражение fn(); может

показаться обычным вызовом функции, но на самом деле в нем вызывается операторная функция

operator() класса Fn. В свою очередь, эта функция вызывает глобальную функцию do_something с

использованием данных замыкания. И кому после этого нужен Паскаль?

Операторная функция operator() может вызываться с произвольным набором аргументов. Чтобы

добавить новые аргументы, укажите их во вторых скобках в объявлении класса. Также разрешается многократная перегрузка оператора () с разными сигнатурами. Ниже приведен тот же пример, в котором одна из версий операторной функции operator() вызывается с аргументом.

class Fn {

private:

int number;

public:

f(int n) : number(n) {}

void operator() () { do_something(number); }

void operator() (char* s)

{

do_something(number);

cout << "Что-то делаю с " << s << endl;

}

};

void callbackfn(Fn);

void p(int n)

{

callbackfn(Fn(n));

}

void callbackfn(Fn fn)

{

// Что-то делаем

fn("callbackfn");

}

Эта маленькая идиома выглядит довольно изящно, однако того же эффекта можно добиться и без

оператора ().

class Fn {

private:

int number;

public:

f(int n) : number(n) {}

void do_something() () { ::do_something(number); }

void do_something() (char* s)

{

do_something(number);

cout << "Что-то делаю с " << s << endl;

}

};

void callbackfn(Fn);

void p(int n)

{

callbackfn(Fn(n));

}

void callbackfn(Fn fn)

{

// Что-то делаем

fn.do_something("callbackfn");

}

Как видите, с таким же успехом можно воспользоваться именем любой функции класса. Единственная причина для использования оператора () - в том, что он предельно ясно выражает ваши намерения. Если класс существует лишь для того, чтобы обслуживать обратные вызовы подобного рода, пользуйтесь оператором (); в противном случае пользуйтесь обычными функциями класса.


Назад    Содержание    Далее    

Home  Создание сайтов  Учебник по записи CD  Справочник Web дизайнера Самоучитель IE PHP и MySQL Компьютерные сети С++ E-mail me

Copyright 2007. Климов Александр. All Right Reserved.
Hosted by uCoz