Skip to content

QMetaObject::newInstance() in Qt 4.5

Thursday, 19 February 2009  |  richard dale

Yesterday I was getting the smoke bindings lib to build with Qt 4.5 with krege on irc, and one of the errors we were getting was with a private class called 'QMetaObjectExtras' that was failing to compile. I fixed it by making the generator skip that class, but I wondered what was in it. This morning I had a look and it turns out that the new moc has a very interesting and useful new feature; you can now have constructors in your QMetaObjects.

To get a constructor added to the QMetaObject, you just prefix it with Q_INVOKABLE like this:

Q_INVOKABLE MyWidget(QWidget* parent = 0);

The moc generates a static_metacall() function that looks like this:

static int MyWidget_qt_static_metacall(QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::CreateInstance) {
        switch (_id) {
        case 0: { MyWidget *_r = new MyWidget((*reinterpret_cast< QWidget*(*)>(_a[1])));
            if (_a[0]) *reinterpret_cast(_a[0]) = _r; } break;
        case 1: { MyWidget *_r = new MyWidget();
            if (_a[0]) *reinterpret_cast(_a[0]) = _r; } break;
        }
        _id -= 2;
        return _id;
    }
    _id = MyWidget::staticMetaObject.superClass()->static_metacall(_c, _id, _a);
    if (_id < 0)
        return _id;
    return _id;
}

Note that it generates a handy no args constructor too. You can query the QMetaObject for constructors using constructorCount() and constructor(int) to obtain the QMetaMethods corresponding to the constructors. To dynamically invoke the constructor you call the newInstance() method on the staticMetaObject like this:

MyWidget * widget = MyWidget::staticMetaObject::newInstance( Q_ARG(QObject, myParent) );

This is really useful for language bindings as you can pretty much get a complete binding 'for free', that will allow you to call slots, connect to signals, get and set properties, create new instances and retrieve enum values. In a language like Ruby it is just a matter of getting hold of a QMetaObject to do all of this with no extra code. With a static language like C# it would still be necessary to generate a C# wrapper, but no extra native code would be needed. I think we can hack the moc to generate the C# wrappers, and the only thing that would be nice would be a plugin code generator option for the moc so we don't have to fork the code in bindings projects.

For the GObject Introspection QMetaObject project that I'm working on, the ability to put the constructors in the per instance QMetaObjects is very useful. Otherwise, I was going to put them in the per-GObject namespace singleton classes.