Картинка для общего примерного представления :
Теперь о главном - о практических нюансах .
Сигнал выпускается в коде командой emit.
На практике emit не преобразуется ни во что. Это просто подсказка разработчику. А вот следующая за emit сентенция это обычная функция, которая будет сгенерировано через moc.
То есть в строке с emit идёт вызов обычной функции.о
Пока все соединенные слоты не будут выполнены (кстати в непредсказуемом порядке) , то выполнение кода после emit не происходит. То есть очередей тут никаких нет.
Правда есть исключение - это queued connections.
Чтобы дождаться окончания выполнение асинхронных команд и НЕ подвешивать обработчик событий часто используют такую конcтрукцию:
QEventLoop loop;
QNetworkReply *reply = qnam.post(request , ba);
connect(reply, SIGNAL(finished()),&loop, SLOT(quit()));
loop.exec();
Это связано с тем , что QNetworkReply создает и использует свой поток, синхронизацию с которым как раз удобно релизовывать через сигналы/слоты.
Это пример выполнения http запроса к серверу. Пока запрос не отработает , то есть не придет сигнал finished от QNetworkReply , код далее (чем loop.exec();) выполняться не будет.
Минус технологии сигнал/слот в том , что если что-то поменять , то надо очищать проект и делать заново qmake и пересборку проекта.
Неоспоримым преимуществом технологии является возможность где угодно делать вызовы сигналов emit и не беспокоится связан с ними какой-нибудь слот (слоты) или нет... Это реально просто удобно.
Вообще говоря по нашему скромному опыту сигнал/слот удобен для релизации обратной связи процессов.
Для "прямого" управления существуют абстрактные классы и по-видимому этого вполне достаточно.
Именно так и поступали разработчики Qt при создании своей библиотеки, пихали везде emit-ты и вы могли их соединять со своими слотами в своих объектах , а могли и не соединять (и даже вообще могли не подозревать о их существовании).
Слоты - возвращаемые значения
Передавать как параметры слотов можно похоже все, что угодно: QVariantMap например, структуры.
Передаются параметры не по ссылке или указателю , в полностью с выделением памяти под их копию.
Можно возвращать тип int , перечисления enum и т.д.
То есть делаем примерно так int res= emit sig_connecTest();
Еще замечено , что на перепутанные большие / маленькие буквы в названиях слотов в конструкции connect(..) компилятор не ругается.
Интересное наблюдение
На самом деле вы можете связывать сигнал / слот для объектов , которые передаются как указатель на QObject, но самом деле это какой-то класс унаследованный от QObject, но мы даже можем не знать какой именно класс.
Например есть классы
class A: public QObject
A::A(QObject * obj){}
class B: public QObject
B* b=new B()
A* a = new A(b)
В конструкторе А передадим указатель QObject* , на самом деле это указатель на класс B :
Теперь в классе A мы ничено не знаем о классе B, но тем не менее можем сделать connect на слот класса B:
connect(this ,SIGNAL(...), obj ,SLOT(...))
И это будет работать.