Собираем
информацию
по крупицам

Программирование на C++ и Qt

Пример функции обратного вызова на C++ / Qt
05-06-2011
19:53:54

В этой статье я кратко опишу готовое решение по вопросу о том, как в C++ / Qt написать функцию обратного вызова (callback-функцию).

 

Задача: есть некий класс Airplane (самолетик). Нужно сделать этому классу интерфейсный метод, через который можно указать, какую внешнюю функцию использовать для управления поведением самолетика. Затем надо создать объект класса Airplane, и задать ему функцию поведения.

 

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

 

class Airplane : public QObject

{

 Airplane(QObject *pobj=0);

 virtual ~Airplane();

 

 void setCallbackFunc(void (*func)(QObject *airplane,

                                   int &x,

                                   int &y));

 

 ...

 

private:

 int x;

 int y;

 

 // Указатель в котором запоминается

 // указатель на функцию поведения самолетика

 void (*callbackFunc)(QObject *airplane, int &x, int &y));
};

 

Вопрос: сколько параметров мы видим в прототипе метода setCallbackFunc? Для тех, кто слабо понимает жуткий синтаксис C++, скажу, что правильный ответ - один. Почему так, будет объяснено чуть ниже. Теперь непосредственно реализация метода, который устанавливает функцию обратного вызова:

 

void Airplane::setCallbackFunc( void (*func)(QObject *airplane,

                                             int &x,

                                             int &y) )

{

 // Эапоминается переданный указатель

 callbackFunc=func;

}

 

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

 

Как видно из вышеприведенного кода, функция, которая должна управлять поведением самолетика, принимает указатель на объект, который ее вызвал (переменная *airplane). Можно обойтись и без этого указателя, но в дальнейшем он может пригодиться для вызова каких-то методов объекта самолетика. Так же эта функция принимает текущие координаты x и y самолетика по ссыке, чтобы функция могла эти координаты изменять.

 

Важный момент для понимания. Найдите в вышеприведенном коде конструкцию:

 

void (*func)(QObject *airplane,

             int &x,

             int &y)

 

Эта монструозная конструкция ни что иное, как указатель на функцию. Причем не на абы какую функцию, а только на ту, которая возвращает тип void и принимает три аргумента с типами QObject*, int&, int&. Имя этого указателя - func.

 

Функция управления самолетиком может выглядеть так:

 

Прототип в h-файле:

 

static void fly(QObject *airplane, int &x, int &y);

 

Обратите внимание, что прототип функции fly() описывается как static. Это важно, так как только статические функции (или методы классов) могут работать как callback-функции. Если забыть указать ключевое слово static, то в момент компиляции будет ошибка вида:

 

error: no matching function for call to ‘Airplane::setCallbackFunc(<unresolved overloaded function type>)’
candidates are: void Airplane::setCallbackFunc(void (*)(QObject*, int&, int&))

 

Реализация функции управления самолетиком:

 

void fly(QObject *airplane, int &x, int &y)

{

 ...

 x=x+y;

 y=y+1;

}

 

С такой реализацией самолетик полетит по мягкой параболе. Обратите внимание, что в реализации ключевое слово static не указывается. Это особенность синтаксиса C++: ключевое слово static нужно указывать только в прототипе.

 

Далее возникает вопрос: а как вызывать эту функцию обратного вызова? А очень просто! Предположим, что у класса Airplane есть метод update(), и в нем нужно сделать вызов нашей callback-функции. Код этого метода может выглядеть так:

 

void Airplane::update()

{

  // Вызов функции управления поведением самолетика

  // qobject_cast<QObject *>(this) - это указатель

  //                                 на текущий объект самолетика

  // x и y - текущие координаты самолетика

  callbackFunc(qobject_cast<QObject *>(this), x, y);

 

  ...

 

  redraw();

}

 

Теперь последний штрих. Создаем объект самолетика, и задаем ему функцию поведения:

 

 Airplane mig29;

 mig29.setCallbackFunc(fly);

 

Все! Если теперь постоянно вызывать метод mig29.update(), то координаты самолетика будут меняться согласно алгоритму, заданному в функции fly().

 


К списку "Компьютерное"

Интересное на сайте


ПЭВМ "Микроша" » Комплект программ "Редактор и Ассемблер" для ПЭВМ "Микроша"

Часть документации на ПЭВМ "Микроша" с описанием работы текстового редактора и транслятора ассемблера. Данный комплект программ занимал 4Кб: 2Кб уходи...


Web - разработка » Пример простого Flash приложения на Action Script 3, компилируемого с помощью MXMLC

Недавно мне нужно было сделать небольшой SWF-ролик с парой кнопок и несколькими картинками. Так как мой основной рабочий инструмент - Linux, то и дела...


Система контроля версий GIT » Установка GIT и настройка GitHub: полное руководство (Windows, Linux)

Здесь описывается практическая часть вопроса использования Git - его установка и регистрация на сервере GitHub.com.    GitHub.com - это серв...

RSS подписка

Подпишитесь на новости сайта по RSS


О, смотри-ка какое хорошее место. Дайте два!

Внимание!

На этом сайте разрабатывается программа MyTetra и её родственные проекты.

Доступны к просмотру следующие базы знаний:

База Xintrea (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)

База Rarrugas (1, 2)

База Balas

База YellowRaven

База Yurons

База Lesnik757

База Shandor

База Sirrichar

 

Подробности на странице MyTetra Share.

 WebHamster.Ru
 Домик любопытного хомячка
Яндекс индекс цитирования
Почтовый ящик