Думаю, я должен добавить следующее.
Существует another linked question - и есть a very good article, что можно считать довольно подробным расширением до его answer; here is this article again, с улучшенной (хотя и не идеальной) подсветкой синтаксиса кода.
Вот мой краткий пересказ его, которые могут быть склонны к ошибкам)
В основном, когда мы вставляем Q_OBJECT
макрос в нашем определении класса, препроцессор расширяет его к статическому декларации QMetaObject
например, тот, который будет совместно всеми экземплярами одного и того же класса:
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
Этот экземпляр, в свою очередь, при инициализации будет хранить подписи ("methodname(argtype1,argtype2)"
) сигналов и слотов, то, что позволит реализоватьвызова, который возвращает, а индекс метода по его подписи строка:
struct Q_CORE_EXPORT QMetaObject
{
// ... skip ...
int indexOfMethod(const char *method) const;
// ... skip ...
static void activate(QObject *sender, int signal_index, void **argv);
// ... skip ...
struct { // private data
const QMetaObject *superdata; // links to the parent class, I guess
const char *stringdata; // basically, "string1\0string2\0..." that contains signatures and other names
const uint *data; // the indices for the strings in stringdata and other stuff (e.g. flags)
// skip
} d;
};
Теперь, когда moc
создает файл moc_headername.cpp
для класса заголовка Qt headername.h
, он ставит там подписные строки и другие данные, которые необходимы для правильная инициализация структуры d
, а затем с помощью этих данных записывается код инициализации для staticMetaObject
singleton.
Еще одна важная вещь, которую она делает, это поколение кода qt_metacall()
метода объекта, который принимает метод идентификатор объекта и массив аргументов указателей и вызывает метод через длинный switch
как это:
int ClassName::qt_metacall(..., int _id, void **_args)
{
// ... skip ...
switch (_id) {
case 0: signalOrSlotMethod1(_args[1], _args[2]); break; // for a method with two args
case 1: signalOrSlotMethod2(_args[1]); break; // for a method with a single argument
// ... etc ...
}
// ... skip ...
}
Наконец, для каждого сигнал moc
генерирует реализацию, которая содержит QMetaObject::activate()
вызова:
void ClassName::signalName(argtype1 arg1, argtype2 arg2, /* ... */)
{
void *_args[] = { 0, // this entry stands for the return value
&arg1, // actually, there's a (void*) type conversion
&arg2, // in the C++ style
// ...
};
QMetaObject::activate(this,
&staticMetaObject,
0, /* this is the signal index in the qt_metacall() map, I suppose */
_args
);
}
Наконец, connect()
вызова переводит StrI ng к их целым идентификаторам (те, которые используются qt_metacall()
) и поддерживает список соединений «сигнал-слот»; когда сигнал испускается, код activate()
проходит через этот список и вызывает соответствующие «слоты» объекта через их метод qt_metacall()
.
Подводя итог, статический экземпляр QMetaObject
хранит «метаинформацию» (строки подписи метода и т. Д.), Сгенерированный метод qt_metacall()
предоставляет «таблицу методов», которая позволяет вызывать любой сигнал/слот индексом, сигналом реализации, генерируемые moc
, используют эти индексы через activate()
, и, наконец, connect()
выполняет работу по поддержанию списка карт индексов «сигнал-слот».
* Примечание: существует сложность этой схемы, используемой для случая, когда мы хотим доставлять сигналы между различными потоками (я подозреваю, что нужно смотреть на код blocking_activate()
), но я надеюсь, что общая идея остается той же)
Это мой очень грубое понимание связанного изделия, которое легко может быть неправильно, поэтому я рекомендую пойти и прочитать его прямо)
PS. Поскольку я хотел бы улучшить свое понимание реализации Qt - сообщите мне о любых несоответствиях в моем пересказе!
С другим моим (ранее) ответа был удален каким-то рьяным редактором, я добавить текст здесь (я пропускаю несколько деталей, которые были не включены в посте Павла Shved, и я сомневаюсь, что человек, который удалил ответ.)
@Pavel Швед:
Я уверен, что где-то в Qt заголовков существует строка:
#define emit
Просто, чтобы подтвердить: нашел в старом коде Qt путем поиска по коду Google. Вполне вероятно, что он все еще существует); найденный маршрут местоположения был:
ftp://ftp.slackware-brasil.com.br> Slackware-7.1> вно> КДЭ-1,90> кварты-2.1.1.tgz> USR> Lib> Qt-2.1.1> подачи> ядро> qobjectdefs.h
Другой complementory ссылка: http://lists.trolltech.com/qt-interest/2007-05/thread00691-0.html - смотрите ответ на Andreas Pakulat
А вот другая часть ответа: Qt question: How do signals and slots work?
Хороший вопрос. См. Также: http://stackoverflow.com/questions/1413777/how-boost-implements-signals-and-slots – elcuco