Search code examples
c++qtsignalssignals-slotsqt-signals

Why does this Qt example work with addresses instead of the objects and functions themselves? And no SLOT/SIGNAL keywords?


I've encountered this code in the Qt documentation:

Counter a, b;

QObject::connect(&a, &Counter::valueChanged,

                 &b, &Counter::setValue);

a.setValue(12);     // a.value() == 12, b.value() == 12
b.setValue(48);     // a.value() == 12, b.value() == 48

Why is there an & before a and b, and before the functions? a is the emitting object (provides the signal) and b is the receiving object (has the slot), so why is their address being taken here instead of just using the objects themselves (& takes the address of an object if I'm not mistaken)? In other Qt examples it's not like this (the address isn't used, the objects themselves are)

I'm not too sure how the & before the function calls (i.e. Counter::valueChanged and Counter::setValue) work...I think it forces them to return by reference, but I'm not sure how that's important here.

Lastly, why is it that there are not SLOT and SIGNAL keywords? Shouldn't it be SIGNAL(Counter::valueChanged) and SLOT(Counter::setValue)? Again, that's what I've seen in other examples of QObject:connect, and this example isn't making sense to me.

Any help is appreciated!


Solution

  • Look at this:

    Counter a, b; // objects created on the stack, they are not pointers
    
    // get the addresses of the objects and assign them as pointers.
    Counter *aPointer = &a;
    Counter *bPointer = &b;
    

    The following will not compile because a and b are not pointers and QObject connect expects pointers to instances of classes that inherit from QObject.

    QObject::connect(a, &Counter::valueChanged, b, &Counter::setValue);
    

    The following will compile because you supply pointers:

    QObject::connect(aPointer, &Counter::valueChanged, bPointer, &Counter::setValue);
    

    Similarly this also works, because you take the address(aka pointer) of the objects:

    QObject::connect(&a, &Counter::valueChanged, &b, &Counter::setValue);
    

    That hopefully explains the & before the objects. Then there are the &'s before the function names. It's the syntax for a pointer to a member function:

    &Counter::valueChanged 
    

    The the class name (Counter), appended with :: and the member function name (valueChanged), preceded with &.

    It's a member of the pointer that is provided as the first argument in this case. This one is called a signal. Under the hood Qt calls them together.

    QObject *sender = &a;
    std::function<void()> signal = std::bind(&Counter::valueChanged,sender);
    ...
    signal(); // the function is called here
    

    The same happens for the slot.

    Lastly, the SIGNAL() and SLOT() macros are used < Qt 5.0. So it's deprecated and should not be used anymore. In some rare cases you should still use it as there is no other alternative, e.g. with QtDBus but that's another topic.

    I hope that clears some of your questions.