July 16, 2010

dmateer dmateer
Lab Rat
3 posts

Using Qt signals and slots with multiple inheritance

 

I need to use multiple inheritance because I need to (1) implement an “is-a” relationship from QGraphicsItem, and (2) implement an application-specific interface (MyInterface):

  1. class MyClass : public QGraphicsTextItem, public MyInterface

I would like to connect to signals from pointers to the interface, i.e.:

  1. MyInterface *my_interface_instance = GetInstance();
  2. connect(my_interface_instance, SIGNAL(MyInterfaceSignal()), this, SLOT(SomeSlot()));

Problem: To expose signals in MyInterface, it needs to derive from QObject. But then I have multiple-inheritance from QObject, which is not allowed. The solutions on this article [doc.trolltech.com] are IMO fairly useless in the common case (accessing an object through its interface), because you cannot connect the signals and slots from MyInterface* but must cast it to the derived-type. Since MyClass is one of many MyInterface-derived classes, this would necessitate “code-smelly” if-this-cast-to-this-else-if-that-cast-to-that statements and defeats the purpose of the interface.

The solution below seems to work, but I was hoping a Troll could let me know if this is supported or is going to cause undefined behavior. If I dynamic_cast a MyInterface* to QObject* (because I know all MyInterface-derived classes also inherit eventually from QObject), it seems to work:

  1. class MyInterface {
  2.  protected:
  3.   virtual void MyInterfaceSignal() = 0;
  4. };
  5.  
  6. class MyClass : public QGraphicsTextItem, public MyInterface {
  7.   Q_OBJECT
  8. signals:
  9.   void MyInterfaceSignal();
  10. };

Usage:

  1. MyInterface *my_interface_instance = GetInstance();
  2. connect(dynamic_cast<QObject*>(my_interface_instance), SIGNAL(MyInterfaceSignal()), this, SLOT(SomeSlot()));

Is this a bad idea?

4 replies

July 16, 2010

florent.revelut florent.reve..
Lab Rat
103 posts

I’m far from being a Troll but we used massively the same idea to work around QObjects not being able to be put into templates.

We had no issue with Qt 4.5, 4.6 and 4.7beta so far

July 16, 2010

harryF harryF
Lab Rat
33 posts

We had a similar discussion recently, and one of the options would be that in your interface’s constructor, you’d take a QObject* of the actual instance.

Your class’s constructor would look like:

  1. MyClass::MyClass()
  2.     : MyInterface(this) {}

That way, you could use the QObject pointer in your interface to connect signals and slots.

Also, you could take a look at QDBusAbstractAdaptor [doc.qt.nokia.com] that basically “attaches” an interface to any given QObject.

 Signature 

// happy hacking

July 16, 2010

Olivier Goffart Olivier Goffart
Lab Rat
21 posts

This is indeed a way to do it.

September 26, 2014

bvanderlaan bvanderlaan
Lab Rat
1 posts

I guess this is an old post but just wanted to add that harryF’s solution (i.e. pass in a pointer to the concrete class to the interface and do all the connections off that pointer) is pretty much exactly the same solution I implemented on a project I worked on recently.

 Signature 

Until next time think imaginatively and design creatively.

 
  ‹‹ QtHelp documentation      Difficulty to show only what I want in QGraphicsview ››

You must log in to post a reply. Not a member yet? Register here!