differences Signal Slot vs function



  • I just wonder about the differences between signal slot and a simple function call. What is the better choice??
    Maybe there is sometimes no function call possible? (i cannot imagine such an scenario)


  • Moderators

    @QT-static-prgm
    basically all of those are simple functions.
    But Signal/Slots just give a very convenient way to create common scenarios with just one line of code. Implementations for signals are provided by moc.
    And since signal/slots are bound to QObject instances you do have to care less about type safety (and casting) like with a normal function call.


  • Moderators

    The signal/slot mechanism ensures separation of concerns, which is a very important design principle. With function calls the calling class needs to know (includes, linking etc.) about an instance of another class. This creates tight coupling which is undesirable for extensibility, maintenance and testability.

    In contrast, when you emit a signal you don't need to know who's gonna react to it. In fact no one might and that's fine too. Similarly, the receiving instance doesn't need to know about where the signal came from. Creating a connection becomes an outside concern.

    As another feature signals allow you to deffer slot invocations via queued connections. They also automatically give you inter-thread communication without synchronization primitives in user's code.



  • thank you.

    Just one question, is it possible to have the slot function in class 1 and connect it with the signal of every instance from class 2? And how would I do that??
    Normally I need to do something like that:
    Connect(instance signal, signal, instance slot, slot)
    But maybe you know a way to get ride of the first instance and just listen to every signal from that class, no matter where and when it was created


  • Moderators

    Unfortunately it's the same question as "how can I get every instance of some class in c++". In general you can't. It might be possible if you put some restrains on the class.
    For example - if you make all the instances children of a single object you could use findChildren() on it to get them. Other way is to create the instances via a factory and that factory could take care of connections.
    In any case you need a single place that knows about all of them. That's just how c++ works.



  • Ok, that's bad. I just hoped there is a way to have a kind of public static signal, that can be used to connect and so every instance of the class emit that signal will call the connected slot.



  • Would it be impossible or too complicated to create one delgator object and delegate the signal through that? For example Sender, Delegator, Receiver.

    class Delegator // QObject stuff...
        signals: void someSignal();
        public slots: void someSlot();
    }
    
    Sender::Sender(Delegator d) {
        connect(/*this to d's slot*/.... );
    }
    Receiver::Receiver(Delegator d){
        connect(/*d's signal to slot of this);
    }
    


  • Now when I think of it, it should be possible to leave the delegator out and just connect directly to the receiver, if there is one receiver object which exists when you create senders.

    Sender::Sender(Receiver* r) { // of course a pointer or reference, not copy, as in previous post...
        connect(/* signal of this to slot of r*/....);
    }
    

  • Moderators

    @Eeli-K Your first example is basically what QSignalMapper does, except there is no coupling between the receiver and the delegator (that's bad design). Similarly - your second code creates coupling between sender and receiver. That's not good. You need a 3rd party to manage the connections . Sender and receiver should not know about each other.

    A pseudocode with a factory would look like this:

    Receiver* receiver = ...;
    SenderFactory* factory = ...; //emits a createdInstance signal when it creates an instance
    
    connect(factory, &SenderFactory::createdInstance, [=](Sender* obj){
       connect(obj, &Sender::someSignal, receiver, &Receiver::someSlot);
    });
    
    SenderObject* sender = factory.createInstance(); 
    //this now automatically connects sender signal to receiver slot without sender or receiver knowing about themselves.
    //factory is the enabler of this mechanism and your own code is the 3rd party that makes the connections
    


  • ok, looks a bit complicate, I'll look into that when i fixed my other problems. For now i made it that way

    MainWindow* tmp = dynamic_cast<MainWindow*>(parent->parent()->parent());
    if(tmp != NULL)
    	connect(this, SIGNAL(sendMessage(QString, int)), tmp, SLOT(showMessage(QString, int)));
    

    But i thought there is maybe a more elegant way.


  • Qt Champions 2016

    Hi
    just a note:
    (parent->parent()->parent());
    is dangerous. as if parent->parent() return NULL u can crash
    as NULL->parent() is not fun.
    Might be ok in your case so just a note :)


  • Moderators

    MainWindow* tmp = dynamic_cast<MainWindow*>(parent->parent()->parent());
    

    Apart from the potential crash that @mrjj mentioned that looks like terrible design. Be prepared that at some point the structure of parents will change and you'll spend some quality time debugging "Why on earth did my connection stop working? I haven't changed anything with it..."



  • That's why i asked for static signals :P


  • Moderators

    Yeah, there are no static signals but that doesn't justify such awful solution. What you want can be achieved without ugly hacks (I mentioned one possible way but there are others).
    Semantically speaking static signal would have no meaning, as a signal indicates a change in state of some object. If there is no object the meaning is lost.



  • @Chris-Kawa i'm currently cleaning my code to make it more readable and to improve the performance.
    and so i came back to my signal slot problem here and the really really bad implementation using parent()->parent()->parent()
    I ddidn't find a good way to implement your factory solution, but i found an other way. So maybe you can take a look at it and tell me if this is a good implementation or not.

    In words:
    i made a new class OutputDevice as singleton and get the first instance of it in my MainWindow. I set the parent and connect the sendMessage with my print function.
    In all other classes i removed the sendMessage signal and now i call OutputDevice::getInstance()->print(QString, int); That way my fileinterface is no longer a QObject and i don't need all the signals anymore.

    In code (only the commit changes):
    https://git.rwth-aachen.de/carstenf/OpenGL/commit/98302664ca365c838c9c585f87d0d4229780976e


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.