Inheritance

Some Qt APIs require you to override certain methods from an abstract base class, for example QAbstractItemModel.

To support creating such subclasses directly from within Rust, CXX-Qt provides you with multiple helpers.

Some superclasses may require special parameters for construction. This can be achieved by using a custom constructor.

Accessing base class methods

To access the methods of a base class in Rust, use the #[inherit] macro. It can be placed in front of a function in a extern "RustQt" block in a #[cxx_qt::bridge].

    extern "RustQt" {
        #[qobject]
        #[base = "QAbstractListModel"]
        #[qml_element]
        #[qproperty(State, state)]
        type CustomBaseClass = super::CustomBaseClassRust;
    }

    // Create Rust bindings for C++ functions of the base class (QAbstractItemModel)
    extern "RustQt" {
        /// Inherited beginInsertRows from the base class
        #[inherit]
        unsafe fn begin_insert_rows(
            self: Pin<&mut CustomBaseClass>,
            parent: &QModelIndex,
            first: i32,
            last: i32,
        );
        /// Inherited endInsertRows from the base class
        #[inherit]
        unsafe fn end_insert_rows(self: Pin<&mut CustomBaseClass>);

        /// Inherited beginRemoveRows from the base class
        #[inherit]
        unsafe fn begin_remove_rows(
            self: Pin<&mut CustomBaseClass>,
            parent: &QModelIndex,
            first: i32,
            last: i32,
        );
        /// Inherited endRemoveRows from the base class
        #[inherit]
        unsafe fn end_remove_rows(self: Pin<&mut CustomBaseClass>);

        /// Inherited beginResetModel from the base class
        #[inherit]
        unsafe fn begin_reset_model(self: Pin<&mut CustomBaseClass>);
        /// Inherited endResetModel from the base class
        #[inherit]
        unsafe fn end_reset_model(self: Pin<&mut CustomBaseClass>);
    }

    unsafe extern "RustQt" {
        /// Clear the rows in the QAbstractListModel
        #[qinvokable]
        pub fn clear(self: Pin<&mut CustomBaseClass>);
    }
impl qobject::CustomBaseClass {
    /// Clear the rows in the QAbstractListModel
    pub fn clear(mut self: Pin<&mut Self>) {
        unsafe {
            self.as_mut().begin_reset_model();
            self.as_mut().rust_mut().id = 0;
            self.as_mut().rust_mut().vector.clear();
            self.as_mut().end_reset_model();
        }
    }
}

Full example

This code implements a QAbstractListModel subclass. For this, the clear method implemented in Rust needs to call beginResetModel and related methods from the base class, which are made accessible by using #[inherit]. See the Qt docs for more details on the specific subclassing requirements.

Methods in a extern "RustQt" block similar to CXX can be tagged with an #[inherit] attribute, with the same restrictions regarding which types can be used. Additionally, the self type must be either self: Pin<&mut qobject::T> or self: &qobject::T, where qobject::T must refer to a QObject marked with #[qobject] in the #[cxx_qt::bridge]

The declared methods will be case-converted as in other CXX-Qt APIs. To explicitly declare the C++ method name, use the #[cxx_name = "myFunctionName"] attribute.

#[inherit] can also be used on signals that exist on the base class in an extern RustQt block

Overriding base class methods

CXX-Qt allows invokables to be generated with the C++ modifiers necessary to implement inheritance. This way methods can be overridden, declared as virtual or final.

C++ keywordCXX-Qt attribute
override#[cxx_override]
virtual#[cxx_virtual]
final#[cxx_final]

The example below overrides the data method inherited from the QAbstractListModel.

    extern "RustQt" {
        #[qobject]
        #[base = "QAbstractListModel"]
        #[qml_element]
        #[qproperty(State, state)]
        type CustomBaseClass = super::CustomBaseClassRust;
    }

    unsafe extern "RustQt" {
        #[qinvokable]
        #[cxx_override]
        fn data(self: &CustomBaseClass, index: &QModelIndex, role: i32) -> QVariant;
    }
impl qobject::CustomBaseClass {
    /// Retrieve the data for a given index and role
    pub fn data(&self, index: &QModelIndex, role: i32) -> QVariant {
        let role = qobject::Roles { repr: role };
        if let Some((id, value)) = self.vector.get(index.row() as usize) {
            return match role {
                qobject::Roles::Id => QVariant::from(id),
                qobject::Roles::Value => QVariant::from(value),
                _ => QVariant::default(),
            };
        }

        QVariant::default()
    }
}

Full example

When a method is overridden using cxx_override, the base class version of the method can be accessed by using #[inherit] in combination with the #[cxx_name] attribute. In this case the base class version of the function must get a different name because Rust can't have two functions with the same name on one type.

Example:

    extern "RustQt" {
        #[qobject]
        #[base = "QAbstractListModel"]
        #[qml_element]
        #[qproperty(State, state)]
        type CustomBaseClass = super::CustomBaseClassRust;
    }

    unsafe extern "RustQt" {
        /// Inherited canFetchMore from the base class
        #[cxx_name = "canFetchMore"]
        #[inherit]
        fn base_can_fetch_more(self: &CustomBaseClass, parent: &QModelIndex) -> bool;

        /// Inherited index from the base class
        #[inherit]
        fn index(
            self: &CustomBaseClass,
            row: i32,
            column: i32,
            parent: &QModelIndex,
        ) -> QModelIndex;
    }

    unsafe extern "RustQt" {
        /// Return whether the base class can fetch more
        // Example of overriding a C++ virtual method and calling the base class implementation.
        #[qinvokable]
        #[cxx_override]
        fn can_fetch_more(self: &CustomBaseClass, parent: &QModelIndex) -> bool;
    }
impl qobject::CustomBaseClass {
    /// Return whether the base class can fetch more
    // Example of overriding a C++ virtual method and calling the base class implementation.
    pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool {
        self.base_can_fetch_more(parent)
    }
}

Full example