Question about connect() function with the SIGNAL and SLOT macros
-
I have some questions about how the
connect()
function with theSIGNAL
andSLOT
macros locates the signals and slots. Here is my code:Interface.h defines two classes,
ClassA
for providing an interface andClassB
for 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
Entity
and 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
Creator
class for generatingEntity
objects.#pragma once #include "Interface.h" class Creator { public: Creator() = default; ClassA* CreateEntity(); };
In Creator.cpp, Entity.h is included to ensure that
Entity
is 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 triggered
Why does the
connect()
function with theSIGNAL
andSLOT
macros accurately locate and connect the signals and slots of theEntity
class? -
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.
TheSIGNAL
andSLOT
macros 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.
TheSIGNAL
andSLOT
macros 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.
TheSIGNAL
andSLOT
macros 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
parent
inside aQObject
.
Let's say yourQObject
has 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
parent
is 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()
.