53

I am trying to use mix in classes for C++/Qt to provide a whole bunch of widgets with a common interface. The interface is defined in such as way so that if it is defined as the base class for other widget classes, then the widget themselves will have those signals:

class SignalInterface: public QObject {
    Q_OBJECT

    public:
    SignalInterface();
    virtual ~SignalInterface();

    signals:
    void iconChanged(QIcon);
    void titleChanged(QString);
}

class Widget1: public SignalInterface, QWidget{

    public:
    Widget1()
    virtual ~Widget1()

    // The Widget Should Inherit the signals
}

Looking at the class hierarchy the problem becomes apparent, I have stumbled on to the dreaded diamond in multiple inheritance, where the Widget1 inherits from QWidget and SignalInterface, and both which inherit from QObject. Will this cause any issues?

We know that this problem can be easily solved if the QObject class is pure virtual (which is not the case).

A possible solution would be:

class Interface: public QWidget {
Q_OBJECT

signals:
void IconChanged(QIcon);
void titleChanged(QString);
}

class Widget1: public Interface {

}

The issue here is that I already have lot of code that inherit from QWidget, and its painful to hack that in. Is there another way?

2
  • Take a look at: stackoverflow.com/questions/17943496/… Commented Dec 8, 2014 at 15:41
  • 1
    I encountered this problem and just added a signal emitter as a member of base interface instead of its base class. Commented Jun 18, 2019 at 15:01

3 Answers 3

62

Unfortunately inheriting QObject twice will cause problems in moc.

From http://qt-project.org:

If you are using multiple inheritance, moc assumes that the first inherited class is a subclass of QObject. Also, be sure that only the first inherited class is a QObject.

I would suggest using something more like the delegate pattern, or recreate with a HasA not a IsA relationship.

Sign up to request clarification or add additional context in comments.

2 Comments

Just a note that for Qt5 this rule remains the same: doc.qt.io/qt-5/… (you gave a link to Qt4 docs)
(Qt5 didn't exist in 2011 when this question was asked and answered)
10

Qt allows multiple inheritance if the base class inherits privately from QObject.

Example:

class Base: private QObject {
   Q_OBJECT
   /*Can use signals and slots like any other QObject-derived class*/
};

class Derived1: public Base {
   /*Cannot use signals/slots because it does not "see" that Base inherits from QObject*/
};

class Derived2: public QWidget, public Base {
   Q_OBJECT
   /*Can use signals/slots plus has all the functionality of QWidget and Base*/
};

Of course, private inheritance is a different animal altogether and may not give you the solution you really need. What I use it for is when I can get away with using signals/slots only in the base class. When I really do need QObject behavior in a derived class, I inherit from QObject specifically for just that class.

3 Comments

Using Qt5.9, this solution does an error while compiling the moc's generated files: 'static_cast': ambiguous conversions from 'QObject *' to 'myClass *'
Likely an unsupported happens to work for some versions/configurations of qt technique. See docs for the official answer.
Qt 6.5 does not work as well.
3

Why using inheritance, why not composition? For example, you can rewrite your case the next way:

class IMyWidgetSignals : public QObject
{
    Q_OBJECT
signals:
    void iconChanged(QIcon);
    void titleChanged(QString);
};

//------------------------------------------------------------------------------

class IMyWidget {
public:
    IMyWidget () {}
    // virtual functions:
    // ...
    
    IMyWidgetSignals _signals;
};


//------------------------------------------------------------------------------

class Widget1: public QWidget, public IMyWidget
{
public:
    using QWidget::QWidget;
}
//------------------------------------------------------------------------------

int main(...)
{
    
    Widget1 w1;
    w1.show();

    QObject::connect(&w1._signals, &IMyWidgetSignals::iconChanged, [] (const auto &icon) { 
        // ... do smth with icon
    });
}

1 Comment

By the way, KDAB developers have presented a new signals / slot / properties mechanism which doesn't require any QObject stuff and could be a solution. kdab.com/signals-slots-properties-bindings

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.