Qobject_cast triggers an assertion on QML components [SOLVED]



  • I'm using this code to iterate through the children of my custom object (C++, derived from QObject) and check for a certain type:

    @
    foreach (QObject *o, children()) {
    Foo f = qobject_cast<Foo>(o);
    if (f) {
    // do foo stuff with f
    }
    }
    @

    This works great as long as there are only C++ objects in children(). However, when I make a component that extends a "Foo", like this:

    @import FooLib 1.0

    Foo {
    ...
    }
    @

    qobject_cast<Foo *> triggers an assertion failure:

    @ASSERT: "!dp->isFunction()" in file qml/qqmlpropertycache.cpp, line 1509@

    Here's a stack trace:

    @148 raise() 0x0000003562a32885
    147 abort() 0x0000003562a34065
    146 qt_message_fatal() qlogging.cpp:806 0x00007ffff6758da9
    145 QMessageLogger::fatal() qlogging.cpp:355 0x00007ffff6756ffa
    144 qt_assert() qglobal.cpp:1951 0x00007ffff675233c
    143 QQmlPropertyCache::toMetaObjectBuilder() qqmlpropertycache.cpp:1509 0x00007ffff7c21db5
    142 QQmlPropertyCache::createMetaObject() qqmlpropertycache.cpp:528 0x00007ffff7c1dc69
    141 QQmlVMEMetaObject::toDynamicMetaObject() qqmlvmemetaobject.cpp:539 0x00007ffff7b66944
    140 QObjectData::dynamicMetaObject() qobject.cpp:189 0x00007ffff69732f4
    139 ShotgunEntity::metaObject() moc_shotgunentity.cpp:100 0x00007fffec20e16b
    138 QMetaObject::cast() qmetaobject.cpp:338 0x00007ffff6941eda
    137 qobject_cast<Property*>() qobject.h:451 0x00007fffec1d03b6
    136 NodeBase::inputs() nodebase.cpp:364 0x00007fffec1cf758 @

    Am I doing something wrong?

    thanks,
    -Mark



  • This is because your QML type is not "Foo". It's some internal type like QMLTYPE_123. You can check

    @
    Foo {
    id: object
    Component.onCompleted: console.log(object)
    }
    @

    My guess is that in QML, inheritance works differently, for example through composition.



  • This seems to be a bug in QML. The meta data from QML Components is stored in a structure called QQmlPropertyCache. The QMetaObject is then created on demand (In this case the qobject_cast).

    The creation of the QMetaObject seems to fail/assert in your case.



  • bq. My guess is that in QML, inheritance works differently, for example through composition.

    Good point, I think they're all internally instances of QQmlComponent or some such. I'll have to figure out a different way to check if a QObject conforms to a particular interface.

    bq. The QMetaObject is then created on demand (In this case the qobject_cast).

    Well, it tries to create the metaobject on demand, anyway. I'm not sure why, but QML component objects do not have an associated QMetaObject. I discovered this when trying to see how hard it would be to add support for native QML attached properties objects (answer: hard enough that I gave up).

    I'll whip up a small test case when I have a chance and file a bug report.

    So bug aside, anyone know how to check if a QML instance conforms to an interface?

    edit: I tried guarding the qobject_cast with
    @if (o->inherits("Foo"))@

    The qobject_cast still triggers an assertion for QML instances "derived" from Foo.



  • Solved!

    I figured it out after being unable to reproduce it in a simplified test case.

    The base class of Foo has a default property called "data", patterned after QQmlItem. I had forgotten this and added an invokable method, also called "data", to Foo. In concrete instances of Foo, this wasn't a problem because they had different method signatures, but as soon as I started using QML instances, the invokable clobbered the default property.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.