Qt signals and slots: permissions - c++

There are discrepancies between respected answers here on SO and the actual Qt docs.
I've read this question and I want some further clarification. Can anyone confirm:
A signal is always protected, therefore it can be emitted only by the class or any of its subclasses. I'm not sure this is true; the question above shows answers supporting this statement. But the Qt docs say: Signals are public access functions and can be emitted from anywhere, but we recommend to only emit them from the class that defines the signal and its subclasses. So which is it?
Slots are just functions, and thus may be public, private or protected. Obviously an outside class will have the ability to control if your class connects one of its own signals to one of its own slots if the slot is public. However, again the SO information differs from the docs, which say: a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class. This means that private is not honored by the signal/slot mechanism?
The words public, private, protected have no use with working with the signal keyword
The emitted signal is always available to all other classes, that is, any other class may always connect to that signal (regardless of its permission to emit the signal).
Despite that all signals are viewable to by all classes, you could still have two classes with signals of the same name since the connect function takes the class name as a signal prefix (i.e. SomeClass::itsSignal)

Signals are protected in Qt4 but are public in Qt5, thus the contradictory information.
Slots are functions and public/protected/private is honored when calling them as such, when connecting to a signal, the metaobject system ignores it though.
As signals is defined as public:, prepending them with e.g. private leads
to:
private:
public: //signals:
void theSignal();
Thus it's without effect.
All classes can be connected to any signal, correct. Signals are part of the public API in that regard.
Having identical signal signatures is not a problem. The context is defined by the object specified as sender.
Using old-style connect:
Apple *apple ... Orange* orange
connect(apple, SIGNAL(changed()), this, SLOT(appleChanged()));
connect(orange, SIGNAL(changed()), this, SLOT(orangeChanged()));
The signal is specified as string here (without the class name in it), but as apple and orange have only one signal changed() each and the lookup is done in the metaobject of the QObject instance, which exists one per class (not instance), they cannot collide.
Qt 5 version with compile-time checking:
connect(apple, &Apple::changed, this, &MyReceiver::appleChanged);
Here one must specify a function, so depending on the scope, one must specify a class name (and maybe namespaces). As an ambiguous function name wouldn't be valid C++ and thus not compile, so one is safe here.

Take a look at qobjectdefs.h (QT5.0+). In there are defined the moc macros
# define signals public
As you can see the macros used in header files for signals are defined as public. As for the explicit statet public,private,protected directives, these are ignored in the signals section. Prior 5.0 versions of QT have signals defined as protected. Those were still available for connections using the SIGNAL() macro.
The slots macro
# define slots
is defined as an empty macro and therefore can be used with:
public slots:
private slots:
protected slots:
The method visibility is used for direct method calls, so private/protected cannot be called from foreign classes directly.
Using the a connect statement still works independently from the visibility. This is the intended behaviour and is implemented in the moc-generated code.
If i remember correctly in earlier versions of Qt a slot was also public automatically, but i did not find a reference for that now.
Any other class can connect to a signal from a foreign class, as long the Q_OBJECT macro is given in the class and the foreign class is known (header included). Since signals are defined per-class it is perfectly legal to have the same signal in different classes. This is also pretty convenient, for example have a signal sendInfo(QString) in all classes makes it easier to remember. The Q_OBJECT macro makes the moc to create code needed to connect signals to slots independent to visibility.

The emitted signal is always available to all other classes, that is, any other class may always connect to that signal (regardless of its permission to emit the signal).
In Qt5, this isn't necessarily true. A signal can be defined with QPrivateSignal as its final argument, and in that case, only the object which declared the signal would be able to connect to it.

Related

Qt : cannot connect signals to slots of promoted QWidget [duplicate]

The documentation states that:
The Q_OBJECT macro must appear in the
private section of a class definition
that declares its own signals and
slots or that uses other services
provided by Qt's meta-object system.
But exactly what does that mean? On which QObject-derived classes can I safely omit it? Will problems arise if you omit Q_OBJECT on a QObject-derived class, and then inherit from that one? Basically I would like a little more information on when I can omit it from my Qt classes.
You should use the Q_OBJECT macro for any non-templated classes that derive from QObject.
Besides signals and slots, the Q_OBJECT macro provides the meta object information that is associated with given class.
As stated in the documentation:
we strongly recommend that all subclasses of QObject use the Q_OBJECT macro regardless of whether or not they actually use signals, slots, and properties.
Suppose we have the following class:
class Class : public QObject {
public:
Class() {}
};
Without Q_OBJECT, the following metaobject system features (among others) will not work for Class:
qobject_cast<Class>() - due to missing metadata
QObject::tr() - due to missing metadata
slots and invokables first declared in Class, when invoked or looked up by name - none of QMetaObject methods will work for these methods, neither will the Qt 4 connect - due to missing metadata
signals - since moc won't generate their implementations and the code won't compile.
You can omit it, of course, but if you ever use these features, you'll need to remember to put the macro into the class's declaration. This is a rather brittle practice and best avoided. The savings are not worth it. So, don't wait - add the Q_OBJECT macro to every class that derives from QObject as a matter of coding policy.
The Q_OBJECT macro should never be used on classes that don't derive from QObject. To add invokables and properties to such classes, use the Q_GADGET macro instead.
If you want to use signals/slots you MUST include the Q_OBJECT macro and derive the class from QObject.
Otherwise you can leave it out, but it doesn't do any harm to include it in all the Qt gui classes
Well the first part is pretty clear as you probably already know.. signals and slots, the rest of the Meta-object system is a little lesser known. Perhaps one of the more useful features is dynamic properties. Although these have many uses, I used them to take advantage of Qt's animation system QPropertyAnimation.
There's a little more info about the meta-object system here: http://doc.qt.io/archives/4.6/metaobjects.html
I think the bottom line is, if you inherit from the QObject hierarchy, throw in the Q_OBJECT macro regardless. It's simple to do and will save you from some potentially baffling problems down the road.
What #liaK said is correct (in short: you should always use the Q_OBJECT macro in any class that derives from QObject).
One thing that I haven't seen highlighted is that if you don't explicitly put the Q_OBJECT macro then using the sometimes very handy qobject_cast won't work!!!

Where do the arguments passed to slots come from? [duplicate]

Is there a way to use any C++ function as a Qt slot, without having its class inheriting from QWidget?
You cannot in Qt versions < Qt 5.
In order to use signals/slots the meta object compiler has to be invoked. To make this happen your class should meet the following requirements:
Inherit from QObject or any other subclass (eg QWidget, QPushButton etc)
The Q_OBJECT macro should be defined in the private section of the class in order to enable meta-object features such as slots
Use the Qt keywords slots and signals in order to declare which functions should be handles by the meta compiler as slots or signals
For more details check the corresponding documentation pages about the meta-object system and the signals & slots
Also check the QObject documentation:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the
Meta Object Compiler on the source file. We strongly recommend the use
of this macro in all subclasses of QObject regardless of whether or
not they actually use signals, slots and properties, since failure to
do so may lead certain functions to exhibit strange behavior.
Edit: Since Qt 5, functors and lambda expressions can be used as slot. See New Signal Slot Syntax in Qt 5
Since Qt 5, functors and lambda expressions can be used as slot (as previously mentioned, here: http://qt-project.org/wiki/New_Signal_Slot_Syntax).
As I could not find example code, I added the following:
This example uses boost::function for a class member ClassName::classMember() without parameters.
boost::function<void()> f= boost::bind(&ClassName::classMember, classInstance);
connect(QObjectInstance, &QObject::signalName, f);
When the Qt signal and class member have parameters (for instance ClassName::classMember(int)), the boost function should be adapted as follows:
boost::function<void(int)> f= boost::bind(&ClassName::classMember, classInstance, _1);
More information on boost::bind can be found in the documentation: http://www.boost.org/doc/libs/1_55_0/libs/bind/bind.html
In Qt 5, you can. See http://qt-project.org/wiki/New_Signal_Slot_Syntax
In Qt 4, this is not directly supported but there are a couple of libraries which provide this functionality by proxying the signal via a slot in a hidden QObject which then calls your non-slot function. My attempt at this can be found at https://github.com/robertknight/qt-signal-tools . There are links to other implementations on the bottom of the README.
Unlikely. The Qt-meta-object-compiler (moc) wraps the function, are marked as slot-s, in relatively large code-wrapper. Files, created by moc, begin with moc_, look them.
It is enough to inherit QObject: http://qt-project.org/doc/qt-4.8/signalsandslots.html

Connecting to a base class' signal when overriding it in a subclass

Qt provides the QSpinBox, which is some far QObject derivative that provides a signal:
class QSpinBox:
public /* ... */ QObject {
signals:
void valueChanged(int i);
};
When deriving from this spin box, I might provide an override for this signal to emit some beautified version of the value:
class MySpinBox:
public QSpinBox {
private slots:
void originalValueChanged(int i) {
/* Beautify */
emit valueChanged( 42 * i );
}
signals:
void valueChanged(int myPersonalI);
};
This seems perfectly fine: The signal MySpinBox::valueChanged(int) hides the inherited signal. The only bit missing is to connect the inherited QSpinBox::valueChanged(int) to the private slot MySpinBox::originalValueChanged(int).
While this is possible using the new signals and slot syntax:
connect(
static_cast<QSpinBox *>(this), &QSpinBox::valueChanged,
this, &MySpinBox::originalValueChanged);
I am neither sure if this is allowed or sensible, nor how to connect the signal using the conventional string based signal/slot syntax. Using the latter, the slot is obviously connected to the MySpinBox::originalValueChanged(int) signal, which is clearly not intended.
Purpose
The above example is reduced to the problem I think I face. To understand why I ran into the problem and maybe to guide me out of this (pretended) broken design, think of a QDoubleSpinBox derivative to enter some physical quantitiy, e.g. speed. The user may want to enter this in some preferred unit, which may be km/h or mph. To get the unit conversion logic out of the application, I composed a new widget, derived from QWidget and containing only a QDoubleSpinBox. Then I implemented the usual spin box methods (setMinimum, setSingleStep etc.) that take the respective properties in SI dimension (i.e., m/s in this example), convert them to some chosen unit and then configure the inferior double spin box.
A setValue(double) converts its argument to the user's unit and passes it on to the inferior. In turn, there is a valueChanged(double) signal that is emitted whenever the inferior spin box emits valueChanged, but with the quantity converted back to the SI dimension.
So in the end I was tinkering about not composing a QWidget derivative with an inferior spin box but to derive from the QDoubleSpinBox and reimplement.
Pros and cons appear partly clear, including the issue explained by #Pavel Strakhov below already. Composing the widget in fact gets me rid of wrongly inherited methods being called (due to not being virtual), at the cost of a wrapping QWidget. So as an intermediate step, I'm tinkering of deriving private from QDoubleSpinBox. This is surely not a matter of resources in a GUI application, but to me it's also a matter of learning and tinkering.
Then I stumbled about the signal and wondered what Qt might think about it.
Note that QSpinBox::valueChanged is not virtual, meaning that if one have an instance of MySpinBox stored in QSpinBox* pointer and calls its valueChanged method, QSpinBox::valueChanged will be executed instead of MySpinBox::valueChanged. And Qt internal functions will definitely have QSpinBox* pointer to the instance. This inconsistency can be a source of errors. Non-virtual functions are not meant to be redefined in subclasses, and you should not do that. Neither of Qt built-in classes uses such redefinition. Subclasses usually add new signals leaving base class signals untouched.

Using any c++ function as a Qt slot

Is there a way to use any C++ function as a Qt slot, without having its class inheriting from QWidget?
You cannot in Qt versions < Qt 5.
In order to use signals/slots the meta object compiler has to be invoked. To make this happen your class should meet the following requirements:
Inherit from QObject or any other subclass (eg QWidget, QPushButton etc)
The Q_OBJECT macro should be defined in the private section of the class in order to enable meta-object features such as slots
Use the Qt keywords slots and signals in order to declare which functions should be handles by the meta compiler as slots or signals
For more details check the corresponding documentation pages about the meta-object system and the signals & slots
Also check the QObject documentation:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the
Meta Object Compiler on the source file. We strongly recommend the use
of this macro in all subclasses of QObject regardless of whether or
not they actually use signals, slots and properties, since failure to
do so may lead certain functions to exhibit strange behavior.
Edit: Since Qt 5, functors and lambda expressions can be used as slot. See New Signal Slot Syntax in Qt 5
Since Qt 5, functors and lambda expressions can be used as slot (as previously mentioned, here: http://qt-project.org/wiki/New_Signal_Slot_Syntax).
As I could not find example code, I added the following:
This example uses boost::function for a class member ClassName::classMember() without parameters.
boost::function<void()> f= boost::bind(&ClassName::classMember, classInstance);
connect(QObjectInstance, &QObject::signalName, f);
When the Qt signal and class member have parameters (for instance ClassName::classMember(int)), the boost function should be adapted as follows:
boost::function<void(int)> f= boost::bind(&ClassName::classMember, classInstance, _1);
More information on boost::bind can be found in the documentation: http://www.boost.org/doc/libs/1_55_0/libs/bind/bind.html
In Qt 5, you can. See http://qt-project.org/wiki/New_Signal_Slot_Syntax
In Qt 4, this is not directly supported but there are a couple of libraries which provide this functionality by proxying the signal via a slot in a hidden QObject which then calls your non-slot function. My attempt at this can be found at https://github.com/robertknight/qt-signal-tools . There are links to other implementations on the bottom of the README.
Unlikely. The Qt-meta-object-compiler (moc) wraps the function, are marked as slot-s, in relatively large code-wrapper. Files, created by moc, begin with moc_, look them.
It is enough to inherit QObject: http://qt-project.org/doc/qt-4.8/signalsandslots.html

Can Qt signals be public or private?

Can Qt signals be public or private? Can I create internal signals, which are seen only inside the class?
Update: I have a class with some internal signals. How can I make those signals invisible for other classes (encapsulation & information hiding)?
No. Signals cannot be public or private. Qt signals are protected class methods.
"signals" keyword is defined in qobjectdefs.h (line 69 as for Qt 4.6.1):
# define signals protected
UPDATE: signals are only protected upto and including all minor versions of Qt 4. From Qt 5.0 onwards they are public. See https://stackoverflow.com/a/19130831.
A common way, e.g. seen in kdelibs, is this:
Q_SIGNALS:
#ifndef Q_MOC_RUN
private: // don't tell moc, doxygen or kdevelop, but those signals are in fact private
#endif
void somePrivateSignal();
This makes the signal private, i.e. it can only be emitted by the class itself but not by its subclasses. To not make the "private:" overrule Q_SIGNALS (moc wouldn't see somePrivateSignal as signal then), it's inside Q_MOC_RUN, which is only defined when moc runs.
Edit: This approach doesn't work for the new-style connects introduced with Qt 5 (connect(a, &A::someSignal, b, &B::someSlot)), as they require the signal to be accessible.
Signals was protected in Qt4, in Qt5 they are public. Int Qt5 you can make them private by adding QPrivateSignal as the last argument. More on this: http://woboq.com/blog/how-qt-signals-slots-work-part2-qt5.html
Slots are simple methods which can be public, protected, or private.
As Andrei pointed it out, signal are only a redefinition of protected, meaning they can only be emitted by the class in which they are defined.
If you want to make a class emit a signal from anoter one, you have to add it a public method (or slot) like this one:
void emitTheSignal(...) {
emit theSignal(...);
}
Qt signals are public in the sense that any object can connect to any signal.
All the existing answers are incorrect.
A signal can be made private by adding a QPrivateSignal type to its definition as the last argument:
signals:
void mySignal(QPrivateSignal);
QPrivateSignal is a private struct created in each QObject subclass by the Q_OBJECT macro, so you can only create QPrivateSignal objects in the current class.
Technically, the signal still has public visibility, but it can only be emitted by the class that created it.
Nowadays you can use Q_SIGNAL macro and normal C++ access specifier:
protected:
Q_SIGNAL void myProtectedSignal();
private:
Q_SIGNAL void myPrivateSignal();
You can use the PIMPL pattern for that. Your private signals exists in the private implementation only.