Originally Posted by
Sanuden
Yeah, that was another route I was considering, however, maybe if I put this into context you'll understand what I'm trying to do. Basically, I'm writing a generic logical expression interpreter so that if you want to know if the value of myObject1->propertyA()->propertyB()->propertyC() is greater than 4 (or any value) where myObject1 has a function that exposes another QObject through propertyA(), which then exposes another QObject through propertyB() which has a function called propertyC() that returns an int, you could pass in myObject1 with a property qualitfier of "propertyA.propertyB.propertyC" and a value of 4 (and comparison type), and it could use reflection to dig into the properties to find the final value.
The goal is to be able to pass any generic object to this type of logic operator and be able to reflect on the desired comparison value (which will always be a QVariant).
Well, the problem is this pseudocode immediately crashes your application:
o1->setProperty("child", o2);
delete o2;
o1->property("child")->anything();
QObject *o1 = new QObject;
QObject *o2 = new QObject;
o1->setProperty("child", o2);
delete o2;
o1->property("child")->anything();
To copy to clipboard, switch view to plain text mode
and you don't even know why (value returned by o1->property() is not null).
What you want to achieve is essentially this (using object names instead of properties):
path.removeLast();
obj = obj->findChild<QObject*>(subobj);
if(!obj
) return QVariant();
// invalid path }
// here we have the final object to call the method on.
QMetaMethod meth
= obj
->metaObject
()->method
(obj
->metaObject
()->indexOfMethod
(qPrintable
(method
));
// for string return type:
if(meth.invoke(obj, Q_RETURN_ARG(ret))) {
return ret;
} else {
}
}
QVariant evaluate(QObject *obj, const QString &expression){
QStringList path = expression.split(".");
QString method = path.last();
path.removeLast();
foreach(QString subobj, path){
obj = obj->findChild<QObject*>(subobj);
if(!obj) return QVariant(); // invalid path
}
// here we have the final object to call the method on.
QMetaMethod meth = obj->metaObject()->method(obj->metaObject()->indexOfMethod(qPrintable(method));
// for string return type:
QString ret;
if(meth.invoke(obj, Q_RETURN_ARG(ret))) {
return ret;
} else {
return QVariant(); // call failed
}
}
To copy to clipboard, switch view to plain text mode
You can do the same with a custom QObject subclass and a custom method if you don't want to use the built-in parent-child relationship. The thing is you should have a single place to control existance of the objects. It will not let you have constness guarantee but I doubt you can have it anyway (you can always cheat the compiler with e.g. a const_cast).
Bookmarks