Что касается сигналов и слотов, макрос 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 *)
и просто проверяет наследование.