Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

struct Simple_window:Graph_lib::Window {

Simple_window(Point xy,int w,int h,const string& title );

void wait_for_button; // простой цикл событий

// ...

};

Другими словами, пользователь может создать окно и ожидать, пока не произойдет щелчок на кнопке.

16.3.1. Функции обратного вызова

Функция
cb_next
— новая и интересная деталь. Именно эта функция должна быть вызвана системой графического пользовательского интерфейса, когда будет зарегистрирован щелчок на кнопке. Поскольку мы передаем такие функции системе графического пользовательского интерфейса, для того чтобы система вызвала их для нас, их часто называют функциями обратного вызова (callback function). Этот факт отображается в префиксе функции
cb_next
(
cb_
— “callback”).

Такое имя выбирается просто для того, чтобы мы помнили о предназначении этой функции, — ни язык, ни библиотека этого не требуют. Очевидно, что мы выбрали имя

cb_next
потому, что эта функция должна быть вызвана для кнопки Next. Определение функции
cb_next
выглядит уродливым куском “шаблонов”. Перед демонстрацией ее кода посмотрим, что она делает.

Наша программа проходит через несколько уровней кода. Она использует нашу библиотеку графики, которую мы реализовали с помощью библиотеки FLTK, которая в свою очередь реализована на основе возможностей операционной системы. В системе есть еще больше уровней и подуровней. Каким-то образом щелчок мыши, идентифицированный драйвером мыши, становится причиной вызова функции
cb_next
. Мы передаем адрес функции
cb_next
и адрес нашего объекта класса
Simple_window
вниз через уровни программного обеспечения; затем какой-то код “где-то внизу” вызывает функцию
cb_next
, когда выполняется щелчок на кнопке Next.

Система графического пользовательского интерфейса (и операционная система) может использоваться программами, написанными на разных языках, но они не могут навязывать всем пользователям стиль языка С++. В частности, ей ничего не известно о наших классах

Simple_window
и
Button
. Фактически она вообще ничего не знает о классах и их членах. Тип, требуемый для обратного вызова функции, выбирается так, чтобы его можно было использовать на самых низких уровнях программирования, включая язык C и ассемблер. Функция обратного вызова не возвращает значений и принимает в качестве аргументов два адреса. Мы можем объявить функцию-член так, чтобы она подчинялась этим требованиям.

static void cb_next(Address, Address); // обратный вызов для

// next_button

Здесь ключевое слово
static
гарантирует, что функция
cb_next
может быть вызвана как обычная функция, т.е. не как функция-член, вызываемая через конкретный объект. Если бы функцию-член могла вызывать сама операционная система, было бы намного лучше. Однако интерфейс обратного вызова нужен для программ, написанных на многих языках, поэтому мы используем статическую функцию-член. Аргументы
Address
указывают на то, что функция
cb_next
получает аргументы, имеющие адреса “где-то в памяти”. Ссылки, существующие в языке C++, во многих языках неизвестны, поэтому мы не можем их использовать. Компилятор не знает, какие типы имеют эти аргументы, расположенные “где-то”. Здесь мы снижаемся на уровень аппаратного обеспечения и не можем использовать обычные средства языка. Система вызовет функцию обратного вызова, первый аргумент которой должен представлять собой адрес некоторого элемента графического пользовательского интерфейса (объекта класса
Widget
), для которого был сделан обратный вызов. Мы не хотим использовать этот первый аргумент, поэтому его имя нам не нужно. Второй аргумент — это адрес окна, содержащего данный объект класса
Widget
; для функции
cb_next
аргументом является объект класса
Simple_window
.

Эту информацию можно использовать следующим образом:

void Simple_window::cb_next(Address,Address pw)

// вызов Simple_window::next для окна, расположенного по адресу pw

{

reference_to<Simple_window>(pw).next;

}

Вызов функции

reference_to<Simple_window>(pw)
сообщает компьютеру, что адрес, хранящийся в переменной
pw
, должен интерпретироваться как адрес объекта класса
Simple_window
; иначе говоря, мы можем использовать значение
reference_to<Simple_window>(pw)
как ссылку на объект класса
Simple_window
. В главах 17-18 мы еще вернемся к вопросам адресации памяти. Определение функции
reference_to
(кстати, совершенно тривиальное) мы покажем в разделе Д.1. А пока просто рады наконец получить ссылку на наш объект класса
Simple_window
и непосредственный доступ к нашим данным и функциям, которые собирались использовать. Теперь поскорее выходим из этого системно-зависимого кода, вызывая нашу функцию-член
next
.

Мы могли бы привести весь код, который следовало бы выполнить в функции
cb_next
, но мы, как и большинство хороших программистов, разрабатывающих графические пользовательские интерфейсы, предпочитаем отделять запутанный низкоуровневый код от нашего превосходного пользовательского кода, поэтому решили обрабатывать обратный вызов с помощью двух функций.

• Функция

cb_next
превращает системные соглашения об обратных вызовах в вызов обычной функции-члена next.

• Функция

next
делает то, что мы хотели (ничего не зная о запутанном механизме обратного вызова).

Мы используем здесь две функции, руководствуясь общим принципом, гласящим: каждая функция должна выполнять отдельное логическое действие, т.е. функция
cb_next
скрывает низкоуровневую системно-зависимую часть программы, а функция
next
выполняет требуемое действие. В ситуациях, когда необходим обратный вызов (из системы) в одном из окон, мы всегда определяем пару таких функций; например, см. разделы 16.5–16.7. Перед тем как идти дальше, повторим сказанное.

  • Читать дальше
  • 1
  • ...
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • ...

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

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: