Multiple Inheritance in Qt

Multiple Inheritance in Qt

By ICS Development Team

Introduction

A quick trivia quiz:

  1. Does Qt use multiple inheritance?
  2. If so, how many public Qt classes use it?
  3. Does any Qt class directly inherit from more than two classes?
  4. Does Qt let you multiply inherit (directly or indirectly) from QObject?

If you can correctly answer these questions off the top of your head you're definitely a Qt and C++ guru and can stop reading now. If not, then by the end of this article you will be able to answer these questions and impress your colleagues with your knowledge.

What is Multiple Inheritance?

Multiple inheritance is a feature of some object-oriented programming languages, including C++, in which a class can inherit from more than one superclass.

Use of multiple inheritance in programming has been a controversial issue over the years. One reason is that it introduces the so-called "diamond problem". Suppose we have two classes B and C that each inherit from class A, and class D that inherits from both B and C. If D calls a method defined in A, and B and C have overridden that method differently, then from which class is the method called: B or C?

By default C++ follows each inheritance path separately so a D object would contain two separate A objects and uses of A's members have to be properly qualified. However, if the inheritance from A to B and from A to C are both marked as virtual (e.g. class B : virtual public A and class C : virtual public A), C++ will only create one A object and uses of A's members work correctly without being qualified.

Some programming languages do not support multiple inheritance at all. Others, like Java and Objective-C, allow multiple inheritance of only abstract classes (sometimes called interfaces or protocols) that specify method signatures without implementing any behavior.

Since inheritance describes an "is a" relationship, multiple inheritance can be appropriate when a class has two orthogonal types of behavior, each of which is provided by a different superclass. Often one of the superclasses is abstract.

For a detailed article on multiple inheritance, see this Wikipedia entry.

Use of Multiple Inheritance of Qt

By my count, there are 17 public classes in Qt 5.0.1 that make use of multiple inheritance. Here is the complete list (by the way, we just answered trivia questions 1 and 2):

QAxObject inherits QObject and QAxBase
QCameraImageCapture inherits QObject and QMediaBindableInterface
QDBusPendingCallWatcher inherits QObject and QDBusPendingCall
QExtensionFactory inherits QObject and QAbstractExtensionFactory
QExtensionManager inherits QObject and QAbstractExtensionManager
QGraphicsObject inherits QObject and QGraphicsItem
QGraphicsWidget inherits QGraphicsObject and QGraphicsLayoutItem
QLayout inherits QObject and QLayoutItem
QMediaPlaylist inherits QObject and QMediaBindableInterface
QMediaRecorder inherits QObject and QMediaBindableInterface
QPdfWriter inherits QObject and QPagedPaintDevice
QQuickItem inherits QObject and QQmlParserStatus
QRadioData inherits QObject and QMediaBindableInterface
QSignalSpy inherits QObject and QList<QList<QVariant> >
QWidget inherits QObject and QPaintDevice
QWindow inherits QObject and QSurface
QXmlDefaultHandler inherits QXmlContentHandler, QXmlErrorHandler, QXmlDTDHandler, QXmlEntityResolver, QXmlLexicalHandler, and QXmlDeclHandler

15 of these classes inherit from QObject and something else, so that seems to be the most common use by far. Two others, QGraphicsWidget and QXmlDefaultHandler, use multiple inheritance but not from QObject.

A Deeper Look

Let's briefly look at each of these classes individually, or grouped where they are similar.

QWidget inherits QObject and QPaintDevice

This is the most well known example of multiple inheritance in Qt, although many Qt developers probably aren't consciously aware that they are using multiple inheritance in such a common class as QWidget. This fits in with the earlier statement that multiple inheritance can be appropriate when a class has two orthogonal types of behavior, each of which is provided by a different superclass.

The QObject class is the base class of all Qt objects. QObject is the heart of the Qt object model providing support for signals, slots, and the meta object system. The QPaintDevice class is the base class of objects that can be painted on with QPainter.

The QWidget class is the base class of all widget-type user interface objects. Widgets are both a Qt object and a paint device. As we saw, many of the classes in Qt that use multiple inheritance have QObject as one of their superclasses. This makes sense, as the Qt object model provides behavior that is desired for many classes.

QMediaRecorder inherits QObject and QMediaBindableInterface
QCameraImageCapture inherits QObject and QMediaBindableInterface
QRadioData inherits QObject and QMediaBindableInterface
QMediaPlaylist inherits QObject and QMediaBindableInterface

These classes are related to multimedia and all have the same inheritance hierarchy. QMediaBindableInterface is the base class for objects extending media object functionality and is pure virtual (as indicated by "Interface" in the class name. The subclasses specialize this interface for various types of media, and inherit from QObject so we gain the Qt object model behavior we want.

QSignalSpy inherits QObject and QList<QList<QVariant> >

This is an interesting one. It inherits from both a class (QObject) and a template class. A QSignalSpy object can connect to any signal of any object and record its emission. A QSignalSpy object itself is a list of QVariant lists.

If you need to do some specialized debugging or testing, or are developing a tool for debugging or testing, you may find this class useful.

QLayout inherits QObject and QLayoutItem

This is an important Qt class although not often used directly. QLayout is an abstract class that is inherited by the concrete layout managers that you use all the time when laying out widgets: QBoxLayout, QFormLayout, QGridLayout, and QStackedLayout. If you usually use Qt Designer, you'll see these classes use in the code that the uic tool generates from the Qt Designer ui files. This is another example of deriving from an abstract class as well as QObject.

QAxObject inherits QObject and QAxBase

This is part of ActiveQt, Qt's support for ActiveX. Since ActiveX is supported only on Windows, you may not have used it. It wraps Microsoft COM objects in Qt, and also makes them QObjects.

QPdfWriter inherits QObject and QPagedPaintDevice

This use of multiple inheritance is analogous to QWidget: we inherit from QObject as well as a paint device, in this case a special one for page-oriented paint devices. QPdfWriter is currently the only class that derives from QPagedPaintDevice but one could imagine implementing other classes to support other page-based printing formats.

QWindow inherits QObject and QSurface

QWindow is new in Qt 5. The QWindow class represents a window in the underlying windowing system. Applications typically use QWidget or QQuickView for UI and not QWindow directly so you may not have occasion to use it.

QDBusPendingCallWatcher inherits QObject and QDBusPendingCall

This is part of the Qt D-Bus module. The watcher class needs the behavior of the QDBusPendingCall class as well as QObject (e.g. support for signals).

QExtensionManager inherits QObject and QAbstractExtensionManager
QExtensionFactory inherits QObject and QAbstractExtensionFactory

These classes are used for creating Qt Designer extensions. They are two similar examples that derive from an abstract class and QObject to make a concrete class.

QQuickItem inherits QObject and QQmlParserStatus

QQuickItem is new in Qt 5. It is a commonly used class when using Qt Quick and QML that is the base class of all visual items. It also gives you visibility into the QML parser, hence the use of multiple inheritance.

QGraphicsWidget inherits QGraphicsObject and QGraphicsLayoutItem
QGraphicsObject inherits QObject and QGraphicsItem

QGraphicsWidget is one of the two cases where multiple inheritance is done without a parent class being QObject. But as we can see, the superclass QGraphicsObject that QGraphicsWidget is derived from does in turn derive from QObject, so a QGraphicsWidget "is" also a QObject. These classes are part of the graphics view framework. Conceptually this is analogous to QWidget being derived from QObject and QPaintDevice, only for graphics view rather than widgets.

QXmlDefaultHandler inherits QXmlContentHandler, QXmlErrorHandler, QXmlDTDHandler, QXmlEntityResolver, QXmlLexicalHandler, and QXmlDeclHandler

This is the real oddball. Not only does it not inherit from QObject, but it inherits from six classes! The method to the apparent madness here is that Qt supports handlers for various types of XML content. These classes are all pure virtual. Let me quote the Qt documentation since it has a good explanation of what QXmlDefaultHandler is for:

The QXmlDefaultHandler class provides a default implementation of all the XML handler classes. This class gathers together the features of the specialized handler classes, making it a convenient starting point when implementing custom handlers for subclasses of QXmlReader, particularly QXmlSimpleReader. The virtual functions from each of the base classes are reimplemented in this class, providing sensible default behavior for many common cases. By subclassing this class, and overriding these functions, you can concentrate on implementing the parts of the handler relevant to your application.

(Note that we just answered trivia question 3).

Conclusions

When using Qt Designer, a form can be used in your application using at least three different approaches. The Qt documentation refers to them as the Direct Approach, the Single Inheritance Approach, and the Multiple Inheritance Approach. This is an example where you may use multiple inheritance in your application. Generally however, the Single Inheritance Approach using a pointer member variable is the preferred method and the one used by the code generated by Qt Creator's new project wizard.

Qt has a limitation that a class must not derive (directly or indirectly) from QObject more than once. The meta object system does not support or allow it. Typically you will get a compile error if you try (e.g. moc_mywidget.cpp:70:50: error: 'QObject' is an ambiguous base of 'MyWidget'). In practice this should not be a problem - usually it reflects an error.

There is also a limitation of moc, the meta object compiler tool, that if you are using multiple inheritance, moc assumes that the first inherited class is a subclass of QObject.

One final wrinkle related to multiple inheritance: you may recall that you can declare properties in your class declarations using the Q_PROPERTY() macro in a class that inherits QObject to expose them to the Qt property system. The READ, WRITE, and RESET functions can be inherited. When they are inherited in classes where multiple inheritance is used, they must come from the first inherited class.

With that, we have now answered all of the questions from our trivia quiz. I hope you found it interesting and perhaps enlightening.