12.2.  Type Identification and qobject_cast

[ fromfile: qtrtti.xml id: qtrtti ]

RTTI, or Run Time Type Identification, as its name suggests, is a system for determining at runtime the actual type of an object, to which you may have only a base class pointer.

In addition to C++'s RTTI operators, dynamic_cast and typeid (Section 19.10), Qt provides two mechanisms for runtime type identification.

  1. qobject_cast

  2. QObject::inherits()

qobject_cast is an ANSI-style typecast operator (Section 19.8). ANSI typecasts look a lot like template functions:

  DestType* qobject_cast<DestType*> ( QObject * qoptr )

A typecast operator converts an expression from one type to another, following certain rules and restrictions imposed by the types and the language. Like other cast operators, qobject_cast takes the destination type as a template parameter. It returns a DestType pointer to the same object. If at runtime, the actual pointer type cannot be converted to DestType*, the conversion fails and the value returned is NULL.

As the signature suggests, qobject_cast is type-restricted to arguments of type ObjectType*, where ObjectType is derived from QObject and the class was fully processed by moc (which requires it to have the Q_OBJECT macro in its class definition).

qobject_cast is actually a downcast operator, similar to dynamic_cast. It permits you to cast pointers and references from a more general to a more specific type. You may find that qobject_cast works 5 to 10 times faster than dynamic_cast, depending on what compiler you use.

In situations where you have base class pointers to derived class objects, downcasting makes it possible to call derived class methods that do not exist in the base class interface.

A common place to find qobject_cast is in concrete implementations of QAbstractItemDelegate, such as Example 12.1. Most of the virtual functions take QWidget* as an argument, so you can do dynamic type checking to determine which kind of widget it is.

Example 12.1. src/modelview/playlists/stardelegate.cpp

[ . . . . ]

void StarDelegate::
    setEditorData(QWidget* editor, 
                  const QModelIndex& index) const {
    QVariant val = index.data(Qt::EditRole);
    StarEditor* starEditor = qobject_cast<StarEditor*>(editor);     1
    if (starEditor != 0) {
        StarRating sr = qVariantValue<StarRating>(val);             2
        starEditor->setStarRating(sr);
        return;
    }
    TimeDisplay* timeDisplay = qobject_cast<TimeDisplay*>(editor);  3
    if (timeDisplay != 0) {
        QTime t = val.toTime();
        timeDisplay->setTime(t);
        return;
    }
    SUPER::setEditorData(editor, index);                            4
    return;
}

1

Dynamic type checking.

2

Extract user type value from QVariant.

3

Dynamic type checking.

4

Let base class handle other types.


[Note] Note

The implementation of qobject_cast makes no use of C++ RTTI. The code for this operator is generated by the MetaObject Compiler (moc).

[Note] Multiple Inheritance and qobject_cast

For qobject_cast to work for the non-QObject base classes, you need to place each base class in a Q_INTERFACES(BaseClass1 BaseClass2) line, in the class definition after the Q_OBJECT macro.

QObject also offers a deprecated, Java-style typechecking function, inherits(). Unlike qobject_cast, inherits() accepts a char* type name instead of a type expression. This operation is slower than qobject_cast because it requires an extra hashtable lookup, but it can be useful if you need input-driven type checking. Example 12.2 shows some client-code that uses inherits().

Example 12.2. src/qtrtti/qtrtti.cpp

[ . . . . ]

//  QWidget* w = &s;            1
    
    if (w->inherits("QAbstractSlider"))  cout << "Yes, it is ";
    else cout << "No, it is not";
    cout << "a QAbstractSlider" << endl;
    
    if (w->inherits("QListView")) cout << "Yes, it is ";
    else  cout << "No, it is not ";
    cout << "a QListView" << endl; 

    return 0;
}

1

A pointer to some widget