Qt signals and slots: permissions

18,548

Solution 1

  • 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.

Solution 2

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.

Solution 3

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.

Share:
18,548

Related videos on Youtube

johnbakers
Author by

johnbakers

likes programming computers, but never studied it anywhere. asks a few good questions and a lot of dumb ones (i've actually learned more from the stupid questions). looks up to nearly all other programmers, regardless of their age.

Updated on July 27, 2022

Comments

  • johnbakers
    johnbakers almost 2 years

    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)
    • Kamil Klimek
      Kamil Klimek over 10 years
      Even in Qt4 you were able to emit signal from outside of class with QMetaObject::invokeMethod
  • johnbakers
    johnbakers over 10 years
    that must have changed as I believe it used to be define signals protected. So this means a signal can be emitted from any other class. It is curious however why the docs indicate that a private slot can also be called from another class.
  • Sebastian Lange
    Sebastian Lange over 10 years
    You can invoke the private slot from a foreign class through a connection, this is true and is afaik implemented through the Q_OBJECT macro and the 'moc' magic. But you can't call the slot directly when declared as private.
  • johnbakers
    johnbakers over 10 years
    interesting, so it is valid for a foreign class to connect any signal to another class's private slot? so the word private only refers to the normal function call use case, while the word slot means the function is always public in a connection use case.
  • Sebastian Lange
    Sebastian Lange over 10 years
    Yes, you can always connect to slots form foreign classes. We experienced this also in our software and we've been surprised too, but it is the intended behaviour for signal-slot connections.
  • Boris Dalstein
    Boris Dalstein over 9 years
    Small typo: signals is defined as public (note that there is no colon). Therefore, private signals: actually expands to private public:, not to private: public:.