Question about connect() function with the SIGNAL and SLOT macros
-
I have some questions about how the
connect()function with theSIGNALandSLOTmacros locates the signals and slots. Here is my code:Interface.h defines two classes,
ClassAfor providing an interface andClassBfor inheriting fromQObject.#pragma once #include <QObject> class ClassA { public: virtual void test() = 0; virtual void emitSignal() = 0; }; class ClassB: public QObject {};Entity.h defines the multiple inheritance class
Entityand declares a signal and a slot.class Entity: public ClassB, public ClassA { Q_OBJECT public: Entity() = default; virtual void test() override { qDebug() << "virtual function"; } virtual void emitSignal() override { emit sig_e(); } void test1() { qDebug() << "member function"; } signals: void sig_e(); public slots: void slot_e() { qDebug() << "slot triggered"; } };Creator.h defines the
Creatorclass for generatingEntityobjects.#pragma once #include "Interface.h" class Creator { public: Creator() = default; ClassA* CreateEntity(); };In Creator.cpp, Entity.h is included to ensure that
Entityis not visible to users of Creator.#include "Creator.h" #include "Entity.h" ClassA* Creator::CreateEntity() { ClassA* e = new Entity; return e; }In the main file, I include Interface.h and Creator.h. The code and the running result are as follows:
#include "Interface.h" #include "Creator.h" #include <QtCore> #include <QObject> int main(int argc, char *argv[]) { Creator c; ClassA* ca = c.CreateEntity(); ca->test(); //ca->test1(); //No member named 'test1' in 'ClassA' qDebug() << "----- 1 -----"; ca->emitSignal(); ClassB* cb = dynamic_cast<ClassB*>(ca); QObject::connect(cb, SIGNAL(sig_e()), cb, SLOT(slot_e())); // why does this work? // QObject::connect(cb, &ClassA::sig_e, cb, &ClassA::slot_e); //No member named 'sig_e' in 'ClassA' // QObject::connect(cb, &ClassB::sig_e, cb, &ClassB::slot_e); //No member named 'sig_e' in 'ClassB' // QObject::connect(cb, &Entity::sig_e, cb, &Entity::slot_e); //Use of undeclared identifier 'Entity' qDebug() << "----- 2 -----"; ca->emitSignal(); return 0; }virtual function ----- 1 ----- ----- 2 ----- slot triggeredWhy does the
connect()function with theSIGNALandSLOTmacros accurately locate and connect the signals and slots of theEntityclass? -
Hi, when you're using the SIGNAL and SLOT macros all the locating and connecting are done when you start the program (not when you compile it).
When you're using connect() without those macros, the locating of the classes are done when you compile the program.So for the 2nd case (but not the 1st) the compiler needs to see all the classes involved.
-
Hi, when you're using the SIGNAL and SLOT macros all the locating and connecting are done when you start the program (not when you compile it).
When you're using connect() without those macros, the locating of the classes are done when you compile the program.So for the 2nd case (but not the 1st) the compiler needs to see all the classes involved.
@hskoglund Thank you for your response. I think I have a general understanding of the reason.
TheSIGNALandSLOTmacros in essence are strings. The code snippetQObject::connect(cb, SIGNAL(sig_e()), cb, SLOT(slot_e()));is equivalent toQObject::connect(cb, "2sig_e()", cb, "1slot_e()");. By using these macros, the code bypasses the compiler's type checking. This is why the code can compile successfully.
The process of searching for signals and slots and establishing connections is handled by the meta-object system. -
S szmf has marked this topic as solved on
-
@hskoglund Thank you for your response. I think I have a general understanding of the reason.
TheSIGNALandSLOTmacros in essence are strings. The code snippetQObject::connect(cb, SIGNAL(sig_e()), cb, SLOT(slot_e()));is equivalent toQObject::connect(cb, "2sig_e()", cb, "1slot_e()");. By using these macros, the code bypasses the compiler's type checking. This is why the code can compile successfully.
The process of searching for signals and slots and establishing connections is handled by the meta-object system. -
@hskoglund Thank you for your response. I think I have a general understanding of the reason.
TheSIGNALandSLOTmacros in essence are strings. The code snippetQObject::connect(cb, SIGNAL(sig_e()), cb, SLOT(slot_e()));is equivalent toQObject::connect(cb, "2sig_e()", cb, "1slot_e()");. By using these macros, the code bypasses the compiler's type checking. This is why the code can compile successfully.
The process of searching for signals and slots and establishing connections is handled by the meta-object system.To add:
One more situation where you could face different behavior is when you are dealing with
parentinside aQObject.
Let's say yourQObjecthas a fixed parent, which never changes (important) during its lifetime.
Assume a signalfoo()that is connected to a slot calledbar()in your parent class.This works (besides it's not recommended or a good practise to do so):
connect(this, SIGNAL(foo()), parent(), SLOT(bar());while none of these work, for the same reason mentioned above:
connect(this, &MyClass::foo, parent(), &ParentClass::bar); connect(this, &MyClass::foo, parent(), &QObject::bar); connect(this, &MyClass::foo, parentWidget(), &QWidget::bar);During compilation
parentis not definite, therefore you would get an error that slotbar()can't be resolved / was not found.
Whereas the first example works, as the check is performed at runtime whereparent()is already linked to your actual parent class, which should hold a slot calledbar().