Ответ 1
Что касается сигналов и слотов, макрос Q_OBJECT
добавляет декларацию виртуальной функции qt_metacall()
в объявление классов, которое должно быть определено позже moc
. (Он также добавляет некоторые декларации для преобразования, но это не слишком важно здесь.)
Затем moc
считывает файл заголовка, и когда он видит макрос, он генерирует другой файл .cpp
с именем moc_headerfilename.cpp
с определениями для виртуальных функций и, возможно, вы спросили себя, почему вы можете уйти с упомянув signals:
в вашем файле заголовка без правильного определения - сигналов.
Итак, когда вызывается сигнал, выполняется определение из файла moc и вызывается QMetaObject::activate()
с именем сигналов и аргументами сигналов.
Затем функция activate()
определяет, какие соединения были установлены и выбраны имена соответствующих слотов.
Затем он вызывает qt_metacall
с именами слотов, а аргументы, передаваемые сигналу, и функция metacall делегирует это с помощью большого выражения switch
- case
в настоящие слоты.
Поскольку в С++ нет реальной информации о времени выполнения, касающейся фактических имен сигналов и слотов, как уже было отмечено, они будут закодированы макросами SIGNAL
и SLOT
до простого const char*
(с либо "1", либо "2", добавленные к имени, чтобы отличать сигналы от слотов).
Как определено в qobjectdefs.h
:
#define SLOT(a) "1"#a
#define SIGNAL(a) "2"#a
-
Другое дело, что макрос Q_OBJECT
определяет функции tr()
внутри вашего объекта, которые могут использоваться для перевода вашего приложения.
Edit
Когда вы спросили, что делает 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 *)
и просто проверяет наследование.