Собираем
информацию
по крупицам
Статьи - Компьютерное

Программирование на 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().

 



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

Поделиться этой страницей


Статистика


RSS подписка

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


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