С++ - язык, который изучается постепенно.ФУНКТОРЫ
создание сайта визитки
Студия Web-дизайна, создание, раскрутка сайтов интернет реклама, подача объявлений на доски, продвижение и сопровождение сайтов
Карта сайта | Зарабатывайте с нами  | Сделать заказ
Наши услуги
Справочники
Самоучитель Internet Explorer
PHP и MySQL
Компьютерные сети
Самоучитель о С++
Новости
Новости для PDA
Реклама
Студия WebKuban.Ru - Создание и поддержка сайтов, интернет магазинов Каталог сайтов Всего.RU Интернет-каталог WWW.SABRINA.RU Refo.ru - русские сайты Каталог HeadNet.Ru Интернет-магазин цифровых товаров Каталог Ресурсов Интернет
Реклама
Язык С++
По последним данным, на рынке продается по крайней мере 2 768 942 книги о С++, не говоря уже о всевозможных курсах, обучающих программах, журналах и семинарах с коктейлями.
И все же в этом изобилии наблюдается удручающее однообразие.
Добро пожаловать на сайт студии Web-дизайна "САР"


Материалы книги получены с 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");

}

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


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



Специальное предложение


Сайт визитка за 90 $
создание, разработка сайта
  • Регистрация доменного имени в зоне .net.ru или .pp.ru (1 год)
  • Хостинг (1 год)
  • Готовый дизайн
  • Поддержка РНР
  • 3 страницы сайта (главная, о фирме, контакты)
  • Регистрация в 256 поисковых системах и каталогах
  • Форма сообщений
заказать создание сайта визитки
Размещение объявлений
Недорого предлагаем разослать ваше рекламное предложение о товарах или услугах на сотни досок объявлений по всему Рунету.
размещение объявлений на электронных досках
Друзья сайта
  • Реклама - каталог ресурсов Реклама - каталог ресурсов - Реклама Карта сайта
  • Просто добавь свой сайт
  • Ипотека, коммерческая и загородная недвижимость, продажа квартир и коттеджей
  • Выставки, выставки России, Выставки Москвы, зарубежные выставки
  • Music singer R&B song
  • Язык С++
    Просматривать полку книг о С++ в книжном магазине ничуть не интереснее, чем литературу по бухгалтерии. В сущности, все книги пересказывают одно и то же и отличаются разве что по весу и количеству цветов в диаграммах и таблицах.
    Copyright студия Web-дизайна САР © 2007
    Используются технологии uCoz