seim
30th December 2008, 17:23
Hi,
I have a question for advanced users or Qt developers..
As far as I can imagine, the qobject_cast provides a safe cast in the QObject* inheritance hierarchy where each node uses Q_OBJECT macro.
Dynamic_cast does practicly the same, but needs RTTI. RTTI isn't always available (for example for objects shared cross two shared libraries in windows, sometimes also in linux as I realized after some tests (ABI)..)
I want to have an interface implemented in one shared library that is used in another shared library... Each interface is managed by PluginManager (singleton object) as an QObject*. Lets have an example:
class IObjekt2 : public QObject
{
Q_OBJECT
protected:
int m_id;
public:
IObjekt2( int id, QObject *parent = 0 ) : QObject(parent), m_id(id) {}
virtual ~IObjekt2() {}
virtual int id() = 0;
};
implementation in one plugin (s.l.):
class Objekt2 : public IObjekt2
{
Q_OBJECT
public:
Objekt2( int id, QObject *parent = 0 ) : IObjekt2(id, parent) {}
~Objekt2() {}
int id() { return m_id; }
};
If we write in the plugin that defines Objekt2:
QObject *o = new Objekt2(199);
IObjekt2 *obj = qobject_cast<IObjekt2 *>(o);
The "obj" will have correct pointer.
But if we use the "o" instance in second plugin, and try to write
IObjekt2 *obj = qobject_cast<IObjekt2 *>(o);
the result is 0 pointer.
I found the reason in:
QObject *QMetaObject::cast(QObject *obj) const
{
if (obj) {
const QMetaObject *m = obj->metaObject();
do {
if (m == this)
return const_cast<QObject*>(obj);
} while ((m = m->d.superdata));
}
return 0;
}
because qobject_cast is practicaly defined as:
template <class T>
inline T qobject_cast(QObject *object)
{
return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast(object));
}
What is important, MOC transforms Q_OBJECT macro to declaration of two static objects describing our class (one of the is const QMetaObject*staticMetaObject) and some methods.., and qobject_cast uses the "staticMetaObject" defined for our class and calls its cast(QObject*) method. This method goes throw all pointers to static objects that are defined for all classes in the inheritance tree of our class and if some pointer equals to THIS (= pointer to static object describing our class), it knows that QObject* can be static_casted to IObjekt2* without any problems....
Now the question...
Shouldn't there be something like:
template <class T> T my_cast( QObject *object )
{
if (object)
{
const QMetaObject *m = object->metaObject();
const QMetaObject *class_m = reinterpret_cast<T>(0)->staticMetaObject.d.superdata;
do {
if (m == class_m)
return static_cast<T>(object);
} while ((m = m->d.superdata));
}
return (T)0;
}
that compares SUPERDATAs and not THIS pointer (pointer to static data)? The casting cross shared libraries is functional now... Isn't the example with SUPERDATA more general than the previous version?
thanks for your opinion...
I have a question for advanced users or Qt developers..
As far as I can imagine, the qobject_cast provides a safe cast in the QObject* inheritance hierarchy where each node uses Q_OBJECT macro.
Dynamic_cast does practicly the same, but needs RTTI. RTTI isn't always available (for example for objects shared cross two shared libraries in windows, sometimes also in linux as I realized after some tests (ABI)..)
I want to have an interface implemented in one shared library that is used in another shared library... Each interface is managed by PluginManager (singleton object) as an QObject*. Lets have an example:
class IObjekt2 : public QObject
{
Q_OBJECT
protected:
int m_id;
public:
IObjekt2( int id, QObject *parent = 0 ) : QObject(parent), m_id(id) {}
virtual ~IObjekt2() {}
virtual int id() = 0;
};
implementation in one plugin (s.l.):
class Objekt2 : public IObjekt2
{
Q_OBJECT
public:
Objekt2( int id, QObject *parent = 0 ) : IObjekt2(id, parent) {}
~Objekt2() {}
int id() { return m_id; }
};
If we write in the plugin that defines Objekt2:
QObject *o = new Objekt2(199);
IObjekt2 *obj = qobject_cast<IObjekt2 *>(o);
The "obj" will have correct pointer.
But if we use the "o" instance in second plugin, and try to write
IObjekt2 *obj = qobject_cast<IObjekt2 *>(o);
the result is 0 pointer.
I found the reason in:
QObject *QMetaObject::cast(QObject *obj) const
{
if (obj) {
const QMetaObject *m = obj->metaObject();
do {
if (m == this)
return const_cast<QObject*>(obj);
} while ((m = m->d.superdata));
}
return 0;
}
because qobject_cast is practicaly defined as:
template <class T>
inline T qobject_cast(QObject *object)
{
return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast(object));
}
What is important, MOC transforms Q_OBJECT macro to declaration of two static objects describing our class (one of the is const QMetaObject*staticMetaObject) and some methods.., and qobject_cast uses the "staticMetaObject" defined for our class and calls its cast(QObject*) method. This method goes throw all pointers to static objects that are defined for all classes in the inheritance tree of our class and if some pointer equals to THIS (= pointer to static object describing our class), it knows that QObject* can be static_casted to IObjekt2* without any problems....
Now the question...
Shouldn't there be something like:
template <class T> T my_cast( QObject *object )
{
if (object)
{
const QMetaObject *m = object->metaObject();
const QMetaObject *class_m = reinterpret_cast<T>(0)->staticMetaObject.d.superdata;
do {
if (m == class_m)
return static_cast<T>(object);
} while ((m = m->d.superdata));
}
return (T)0;
}
that compares SUPERDATAs and not THIS pointer (pointer to static data)? The casting cross shared libraries is functional now... Isn't the example with SUPERDATA more general than the previous version?
thanks for your opinion...