- Shiboken
- » Type System Reference

# Type Discovery

When converting objects which are part of a class hierarchy from a pointer to a base class, it is expected to get the Python type of the actual, most derived type, as opposed to C++ which requires a cast for this:

    def event(self, event):
        if event.type() == QEvent.Type.MousePress:
            self.do_things(event.position())
    ...

    bool event(QEvent *event) override
    {
        if (event->type() == QEvent::MousePress) {
            auto *mouseEvent = static_cast<QMouseEvent *>(event);
            doThings(mouseEvent->position());
        ...
    }

The process of determining the type of the event is called type discovery.

Shiboken generates code to automatically detect the type. First, it tries to find a converter for the name obtained by `typeid(*pointer).name()`. This should normally work as this name is registered by the binding. If that fails, it starts walking a type inheritance graph built up in libshiboken to find the most derived class by using a cast function (`dynamic_cast<>` by default) to check.

For normal class hierarchies with virtual destructors, no special handling is required since `typeid()` usually detects the proper class name.

## Multiple inheritance

In case of multiple inheritance in C++, the conversion to the derived class is not done in case it is not a single-line direct inheritance. For example, in Qt, the class `QWidget` inherits both `QObject` (base of the `QObject` hierarchy) and `QPaintDevice`.

When calling a function returning a `QPaintDevice *`, for example `QPainter.device()`, a Python type representing `QPaintDevice` is returned instead of the underlying widget type. This restriction exists because the underlying pointer in C++ is a pointer to a `QPaintDevice *` and differs from the pointer to the `QWidget`.

## Hierarchies of classes with non-virtual destructors

There are some hierarchies of value-ish C++ classes that do not have virtual destructors. This makes type discovery based on `typeid()` and `dynamic_cast<>` impossible.

Examples in Qt are the `QStyleOption`-derived or the `QGradient` -derived classes.

For such classes, some attributes need to be specified on the type entries:

Primarily, a polymorphic-id-expression attribute must be specified to be used as a check replacing `dynamic_cast<>`.

In addition, a polymorphic-name-function attribute can be specified. This replaces the type name guess obtained by `typeid()` and is mainly a hint to speed things up by skipping the checks for each type in the inheritance graph.

A polymorphic-base attribute identifies the base class of a hierarchy. It should be given in case the base class inherits from another class to prevent the logic from going below the base class.

## Using type discovery attributes for class hierarchies with virtual destructors

It is possible to use polymorphic-id-expression and polymorphic-name-function for normal class hierarchies with virtual destructors as well since they basically replace `typeid()` and `dynamic_cast<>`. This makes sense if expressions can be specified that are faster than the checks on virtual tables.

Specifying polymorphic-base can also make sense for generating special cast functions in case of multiple inheritance. For example, in Qt, `QWindow`, `QLayout`, `QWidget` are base classes of hierarchies. Since they all inherit from `QObject`, indicating the base classes prevents the logic from using `QObject` as a base class.

## Type discovery attributes reference

The following attributes related to type discovery may be be specified on the object-type or value-type elements:

### polymorphic-id-expression

The polymorphic-id-expression attribute specifies an expression checking whether a base class pointer is of the matching type. For example, in a `virtual eventHandler(BaseEvent *e)` function, this is used to construct a Python wrapper matching the derived class (for example, a `MouseEvent` or similar). The attribute value may contain placeholders:

%1

  Fully qualified class name

%B

  Fully qualified name of the base class (found by base class search or as indicated by polymorphic-base).

To check for a class inheriting `BaseEvent`, specify:

    <object-type name="MouseEvent"
                 polymorphic-id-expression="%B-&gt;type() == BaseEvent::MouseEvent"/>

### polymorphic-name-function

The polymorphic-name-function attribute specifies the name of a function returning the type name of a derived class on the base class type entry. Normally, `typeid(ptr).name()` is used for this.

The function is expected to return `const char *`.

### polymorphic-base

The boolean polymorphic-base attribute indicates whether the class is the base class of a class hierarchy. It is used for the %B placeholder in polymorphic-id-expression and for cast operations in multiple inheritance.