Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Connecting to signal of another class



  • Hello, I am attempting to connect a signal from one class instance to another but am having trouble.

    Here is the scenario. I have 3 classes, ClassA, ClassB and ClassC. ClassA inherits ClassB, ClassB inherits QObject, and ClassC inherits QObject.

    The idea is that I will create potentially multiple instances of ClassA, whose inherited class B instance needs to receive signals from the same single instance of ClassC. ClassA registers a pointer to the ClassC instance upon creation, and ClassB will use that to connect to the signal.

    However, this method is crashing upon invoking connect in the constructor of Class B. I get a seg fault, which is probably because of some type of null pointer, but I can't tell exactly. See code below:

    // classa.cpp
    #include <classa.h>
    
    ClassA::ClassA(ClassC * somecclass)
    {
        classc = somecclass;
    }
    
    
    // classa.h
    #ifndef CLASSA_H
    #define CLASSA_H
    
    #include <classb.h>
    #include <classc.h>
    #include <QObject>
    
    class ClassA: ClassB
    {
        Q_OBJECT
    public:
        ClassA(ClassC * somecclass);
    };
    
    #endif // CLASSA_H
    
    
    // classb.cpp
    #include "classb.h"
    
    ClassB::ClassB()
    {
        // Crash happens here
        connect(classc, SIGNAL(classCsignal()), this, SLOT(classBslot()));
    }
    
    void ClassB::classBslot(void)
    {
    
    }
    
    
    // classb.h
    
    #ifndef CLASSB_H
    #define CLASSB_H
    
    #include <QObject>
    #include <classc.h>
    
    class ClassB : public QObject
    {
        Q_OBJECT
    public:
        ClassB();
        ClassC * classc;
    
    signals:
    public slots:
        void classBslot(void);
    };
    
    #endif // CLASSB_H
    
    
    // classc.cpp
    #include "classc.h"
    
    ClassC::ClassC()
    {
    
    }
    
    
    // classc.h
    #ifndef CLASSC_H
    #define CLASSC_H
    
    #include <QObject>
    
    class ClassC : public QObject
    {
        Q_OBJECT
    public:
        ClassC();
    
    signals:
        void classCsignal();
    public slots:
    };
    
    
    #endif // CLASSC_H
    
    // main.cpp
    
    ClassC classc;
    ClassA classa(&classc);
    
    // loop and do other stuff
        
    
    

    If however in ClassB, instead of having a pointer, I create a local instance of ClassC and then use this in connect, it works. Why can't I do the original way? Is there some weird order of QObject initialization where the signals aren't there yet or something, or am I missing something else? I'm simply use a pointer to an outside already initialize outside instance of a class vs. a local instance.

    Thanks


  • Lifetime Qt Champion

    Hi,

    Looks like your classC object is not initialised before you use it.


  • Lifetime Qt Champion

    Hi
    That should work fine as longs ClassC classc; stays in scope.
    So i would check my cached pointer

    in .h
    ClassC * classc=nullptr;

    and

    ClassB::ClassB() // it has no parameter here of type ClassC ???? so where do you store it ?
    {
    // Crash happens here
    if (!classc )
    qDebug() << "ptr is null";
    else
    connect(classc, SIGNAL(classCsignal()), this, SLOT(classBslot()));
    }



  • @SGaist said in Connecting to signal of another class:

    Hi,

    Looks like your classC object is not initialised before you use it.

    What do you mean? I create an instance of it in main before creating a ClassB instance.

    @mrjj said in Connecting to signal of another class:

    Hi
    That should work fine as longs ClassC classc; stays in scope.
    So i would check my cached pointer

    in .h
    ClassC * classc=nullptr;

    and

    ClassB::ClassB() // it has no parameter here of type ClassC ???? so where do you store it ?
    {
    // Crash happens here
    if (!classc )
    qDebug() << "ptr is null";
    else
    connect(classc, SIGNAL(classCsignal()), this, SLOT(classBslot()));
    }

    I verified that classc is not a NULL pointer.

    The ClassC pointer is indeed stored in the ClassB instance:

    // classb.h
    public:
        ClassB();
        ClassC * classc;
    

    This should not go out of scope because main never returns. Also, I verified that if I do this same exact method, but instead call connect in a separate function call, it works fine. It seems that this just doesn't work when called from the constructor.


  • Lifetime Qt Champion

    So
    the real code looks like
    ClassB(ClassC *theptr) : classc(theptr ) {

    connect(classc, xxxx )
    }

    ?



  • @mrjj said in Connecting to signal of another class:

    So
    the real code looks like
    ClassB(ClassC *theptr) : classc(theptr ) {

    connect(classc, xxxx )
    }

    ?

    No ClassB doesn't inherit ClassC. There's simply a static ClassC * pointer called "classc" in ClassB. This holds a reference to an instance of ClassC .

    The reason for doing it this way, is there will be a single instance of ClassC, which ClassA/(and inherited ClassB) need to all reference.

    i.e.

    ClassC globalCinstance;
    
    ClassA classAinstance1(&globalCinstance);
    ClassA classAinstance2(&globalCinstance);
    ClassA classAinstance3(&globalCinstance);
    

    What I was saying that does work, is doing something like this:

    // main.cpp
    ClassC someclassC;
    ClassA someclassA;
    someclassA.registerSignal();
    

    where

    // classb.cpp
    void ClassB::registerSignal()
    {
    connect(classc, SIGNAL(classCsignal()), this, SLOT(classBslot()));
    }
    

    and even this works too:

    // main.cpp
    ClassC someclassC;
    ClassA someclassA;
    
    // classa.cpp
    ClassA::ClassA(ClassC * somecclass)
    {
        classc = somecclass;
    
       // Call registerSignal from inherited ClassB
       registerSignal();
    }
    
    // classb.cpp
    void ClassB::registerSignal()
    {
    connect(classc, SIGNAL(classCsignal()), this, SLOT(classBslot()));
    }
    
    

    It seems that it just can't be called from the constructor of ClassB



  • @kengineer said in Connecting to signal of another class:

    connect(classc, SIGNAL(classCsignal()), this, SLOT(classBslot()));

    You may want to use signals and slots new syntax as it provides information at compile time which may shed some light about your issue



  • @kengineer
    That's because A INHERITS from B. That means that B is being constructed before A and at that point the classC member variable has not been assigned a value.


  • Moderators

    Well spotted!



  • @mranger90 thanks yes that would be an issue wouldn't it. I'm a C programmer that's rather new to C++, I was actually reading about construction order but had it mixed around in my head. This makes sense, thanks!


Log in to reply