Как Qt реализует сигналы и слоты? - PullRequest
15 голосов
/ 05 января 2010

Может кто-нибудь объяснить мне основную идею механизма реализации сигналов и слотов Qt? Я хочу знать, что все эти макросы Q_OBJECT делают "на простом C ++". Этот вопрос НЕ касается использования сигналов и слотов.

добавлено: Я знаю, что Qt использует компилятор moc для преобразования Qt-C ++ в простой C ++. Но что делает МОК? Я пытался прочитать файлы "moc_filename.cpp", но я понятия не имею, что может означать что-то подобное

void *Widget::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_Widget))
    return static_cast<void*>(const_cast< Widget*>(this));
return QDialog::qt_metacast(_clname);
}

Ответы [ 3 ]

17 голосов
/ 05 января 2010

Что касается сигналов и слотов, макрос Q_OBJECT добавляет виртуальную функцию qt_metacall() объявление в объявление класса, которое будет определено позже moc. (Также добавлены некоторые объявления для преобразования, но это не так уж важно здесь.)

Затем moc читает файл заголовка, и когда он видит макрос, он генерирует еще один .cpp файл с именем moc_headerfilename.cpp с определениями для виртуальных функций и - вы, возможно, спросили себя, почему вы можете обойтись без упоминание signals: в вашем заголовочном файле без правильного определения - сигналов.

Итак, когда вызывается сигнал, выполняется определение из mocfile и вызывается QMetaObject::activate() с именем сигнала и его аргументами. Затем функция activate() выясняет, какие соединения были установлены, и выбирает имена для соответствующих слотов.

Затем он вызывает qt_metacall с именами слотов и аргументами, данными для сигнала, а функция metacall делегирует это с помощью большого оператора switch - case реальным слотам.

Поскольку в C ++ нет реальной информации о времени выполнения, касающейся действительных имен сигналов и слотов, как уже отмечалось, они будут кодироваться макросами SIGNAL и SLOT в простые const char* s ( с именем "1" или "2", добавленным к названию, чтобы отличать сигналы от слотов).

Как определено в qobjectdefs.h:

#define SLOT(a)     "1"#a
#define SIGNAL(a)   "2"#a

-

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

Редактировать Как вы спросили, что делает qt_metacast. Он проверяет, принадлежит ли объект определенному классу и возвращает ли он указатель на него. Если нет, возвращается 0.

Widget* w = new Widget();
Q_ASSERT(w->qt_metacast("Widget") != 0);
Q_ASSERT(w->qt_metacast("QWidget") != 0);
Q_ASSERT(w->qt_metacast("QObject") != 0);
Q_ASSERT(w->qt_metacast("UnrelatedClass") == 0);

Это необходимо для обеспечения некоторого отражения во время выполнения, которое иначе невозможно. Например, функция вызывается в QObject::inherits(const char *) и просто проверяет наследование.

3 голосов
/ 05 января 2010

Эти макросы абсолютно ничего не делают "в простом C ++", - они расширяются до пустых строк (я думаю).

QT использует мета-объектный компилятор, который генерирует код C ++ для классов с поддержкой Q_OBJECT (реализуя определенные вами сигналы / слоты).

Подробнее об этом можно прочитать в официальной документации .

0 голосов
/ 05 января 2010

Основная идея состоит в том, что вы можете соединять ваши объекты, позволяя им выполнять метод (слот), когда сигнал закончен.

connect(pistol,SIGNAL(sigShoot()),runner,SLOT(slotRun()))

При выполнении вышеуказанного соединения, когда пистолет издает сигнал, бегун выполнит свой слот.

Чтобы сделать это, вы должны объявить свои сигналы и слоты в соответствующих классах.

Это основная идея.

Удачи!

...