1

Let's say SomeClass has members Object1 and Object2 and there is a connection between Object1 and Object2 like:

connect(Object1, signal1, Object2, slot1)

After some refactoring Object3 was added to SomeClass and Object2 was moved to be a member of Object3, but still exist the need for the connection between Object1 and Object2.

The communication between Object1 and Object2 will have to go through Object3 now. This means Object3 needs to be modified, adding a pair of signal/slot just to implement that communication between Object1 and Object2.

This means both Object3's .h and .cpp will be modified, adding many lines of code to do a thing previously done in just one line.

My lazy side is telling that there is something strange in this story. Is there some way to make that connection more straight forward?

jpnurmi
  • 5,716
  • 2
  • 21
  • 37
KcFnMi
  • 5,516
  • 10
  • 62
  • 136
  • _"This means Object3 needs to be modified..."_ - why??? the same `connect(Object1, signal1, Object2, slot1)` will work as before (I suppose `Object1` and `Object2` are pointers in your code) – mvidelgauz Jul 07 '16 at 17:48

1 Answers1

5

You're encapsulating Object2 within Object3. From the point of view of the user of Object3, nothing is changing: there's still only one line of code to set up the connection. Object3 needs an extra slot that forwards to the Object2 instance it now encapsulates. That's one extra line here. And that's it.

struct Object1 : QObject {
  Q_SIGNAL void signal1();
  Q_OBJECT
};
struct Object2 : QObject {
  Q_SLOT void slot1() {}
  Q_OBJECT
};
class Object3 : QObject {
  Q_OBJECT
  Object2 m_object2;
public:
  // one line to expose object2's slot
  Q_SLOT void slot1() { m_object2.slot1(); }
};

class SomeClass {
  Object1 m_object1;
  Object3 m_object2;
public:
  SomeClass() {
    // still one line
    connect(&m_object1, &Object1::signal1, &m_object3, &Object3::slot1);
  }
};
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Should I prefer Q_SLOT/Q_SLOTS (and Q-SIGNAL/Q_SIGNALS, EMIT ...) over the classic public slots? I understand why they are required from http://doc.qt.io/qt-5/signalsandslots.html#using-qt-with-3rd-party-signals-and-slots, but should use this as the default style even not using 3rd Party Signals and Slots? – KcFnMi Jul 07 '16 at 20:55
  • 1
    @KcFnMi I prefer the `Q_` prefix so that the global namespace isn't polluted by macros such as `signals` or `slots`. I prefer `Q_SIGNAL` and `Q_SLOT` over `Q_SIGNALS` and `Q_SLOTS` when the number of signals/slots is small and doesn't warrant an entire section. Furthermore, often logically the signals/slots don't belong together, but with other methods. I like to use `emit` over `Q_EMIT`, since it makes the code self-document in a non-ugly fashion. The use of `emit`/`Q_EMIT` is optional anyway, it's only for human consumption. – Kuba hasn't forgotten Monica Jul 07 '16 at 21:01
  • Is the call to the slot still asynchronous this way (`Q_SLOT void slot1() { m_object2.slot1(); }`) ? – KcFnMi Jul 09 '16 at 22:57
  • 1
    @KcFnMi It can't be - it's a direct C++ method call. The slot designation plays no role when you call things directly. But of course if `Object3::slot1` is called asynchronously, then `m_object2::slot1` will be, too, in object3's thread context. It is important, then that `m_object2` is in the same thread as `Object3`. If it isn't, Object3 will have to implement an asynchronous call through `QMetaObject::invokeMethod` or [other mechanisms](http://stackoverflow.com/q/21646467/1329652). – Kuba hasn't forgotten Monica Jul 11 '16 at 14:25