In Qt, I understand that I cannot multiply inherit QObject
s. It appears that a QObject
can inherit a Q_GADGET
, but it appears that I cannot invoke gadget methods by name. It seems like Qt’s Q_INTERFACES
features are appropriate for this, but I can’t seem to make it work.
My particular use case is I have a collection of classes that I want to use through QML (so their methods are invoked by name by Qt) and I want to mix in different interfaces, so I want to be able to do
class Concrete0 : public QObject, public InterfaceA { ... };
class Concrete1 : public QObject, public InterfaceA, public InterfaceB { ... };
and have the methods exposed by the interface classes be invokable from QML.
Can Q_INTERFACES
do this? I’ve adapted the example from Qt interfaces or abstract classes and qobject_cast() as follows:
class YourInterface {
public:
Q_INVOKABLE virtual void someMethod() {}
};
Q_DECLARE_INTERFACE(YourInterface, "Timothy.YourInterface/1.0")
class OtherInterface {
public:
// Empty class for now.
};
Q_DECLARE_INTERFACE(OtherInterface, "Timothy.OtherInterface/1.0")
class YourClass : public QObject, public YourInterface, public OtherInterface {
Q_OBJECT
Q_INTERFACES(YourInterface OtherInterface)
public:
YourClass() = default;
};
and to test it:
YourClass* c = new YourClass();
YourInterface* i = qobject_cast<YourInterface*>(c);
assert(i); //< We can qobject_cast it!
const auto& mo = *c->metaObject();
for (auto j = 0; j != mo.methodCount(); ++j) {
fmt::print("{}n", mo.method(j).methodSignature().toStdString());
}
fmt::print("n");
mo.invokeMethod(c, "someMethod");
which prints
destroyed(QObject*)
destroyed()
objectNameChanged(QString)
deleteLater()
_q_reregisterTimers(void*)
qWarning(): QMetaObject::invokeMethod: No such method YourClass::someMethod()
So it appears that something is working, in that qobject_cast
works (and removing the Q_INTERFACES(YourInterface OtherInterface)
line makes that fail), but the base-class Q_INVOKABLE virtual void someMethod() {}
can’t be invoked by name.
How can I make it find someMethod
by name? (I can do Q_INVOKABLE void someMethod() override { YourInterface::someMethod(); }
in YourClass
, but that mostly defeats the purpose of the mixin pattern.