QT API里关于qobject_cast的描述:
Returns the given object cast to type T if the object is of type T (or of a subclass); otherwise returns 0. If object is 0 then it will also return 0.
The class T must inherit (directly or indirectly) QObject and be declared with the Q_OBJECT macro.
A class is considered to inherit itself.
Example:
QObject *obj = new QTimer; // QTimer inherits QObject QTimer *timer = qobject_cast<QTimer *>(obj); // timer == (QObject *)obj QAbstractButton *button = qobject_cast<QAbstractButton *>(obj); // button == 0
The qobject_cast() function behaves similarly to the standard C++ dynamic_cast(), with the advantages that it doesn't require RTTI support and it works across dynamic library boundaries.
Warning: If T isn't declared with the Q_OBJECT macro, this function's return value is undefined.
大体意思就鼓励大家使用qobject_cast而非dynamic_cast。xxx_cast<TA>(TB),转换是否成功主要看TA/TB是否在一个类继承体系中,TB是否是TA相同类型或者子类。dynamic_cast依赖RTTI类判断,而qobject_cast依赖QMetaObject信息来判断。下面来看看源代码吧:
// */src/corelib/kernel/qmetaobject.cpp
- template <class T>
- inline T qobject_cast(QObject *object)
- {
- #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK)
- reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(object));
- //首先检查是类T定义中是否使用了宏Q_OBJECT。如果使用了,那么qt_check_for_QOBJECT_macro就有了定义,
- //但是操作实际上是没有任何意义;如果没用到这个宏,那么就出现编译错误,因为Q_OBJECT的展开中
- //才有这个函数的定义
- #endif
- return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast(object));
- //真正检查对象的元信息的代码,具体看下边的QObject::cast(QObject*)。这里staticMetaObject
- //是static变量,所以可以用强制转换0地址为对象指针的方法来调用。又是一个0地址的用处哦
- }
- template <class T>
- inline T qobject_cast(const QObject *object)
- {
- // this will cause a compilation error if T is not const
- register T ptr = static_cast<T>(object);
- Q_UNUSED(ptr);
- #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK)
- reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(const_cast<QObject *>(object)));
- #endif
- return static_cast<T>(const_cast<QObject *>(reinterpret_cast<T>(0)->staticMetaObject.cast(const_cast<QObject *>(object))));
- }
// */src/corelib/kernel/qobjectdefs.h
- /* This is a compile time check that ensures that any class cast with qobject_cast
- actually contains a Q_OBJECT macro. Note: qobject_cast will fail if a QObject
- subclass doesn't contain Q_OBJECT.
- In qt_check_for_QOBJECT_macro, we call a dummy templated function with two
- parameters, the first being "this" and the other the target of the qobject
- cast. If the types are not identical, we know that a Q_OBJECT macro is missing.
- If you get a compiler error here, make sure that the class you are casting
- to contains a Q_OBJECT macro.
- */
- /* tmake ignore Q_OBJECT */
- #define Q_OBJECT_CHECK \
- template <typename T> inline void qt_check_for_QOBJECT_macro(const T &_q_argument) const \
- { int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i; }
- //这个"i=i;“是多余之笔吗?如果谁看出门道来告诉我,好不好?
- //上边注释中第二段说的不是废话吗?能进到这个函数里就说明Q_OBJECT已经有使用了,已经达到目的了
- template <typename T>
- inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
- //没用啊
- template <typename T1, typename T2>
- inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
// */src/corelib/kernel/qobjectdefs.h
- #define Q_OBJECT \
- public: \
- Q_OBJECT_CHECK \ //上边几个函数就此展开
- static const QMetaObject staticMetaObject; \
- Q_OBJECT_GETSTATICMETAOBJECT \
- virtual const QMetaObject *metaObject() const; \
- virtual void *qt_metacast(const char *); \
- QT_TR_FUNCTIONS \
- virtual int qt_metacall(QMetaObject::Call, int, void **); \
- private:
// */src/corelib/kernel/qmetaobject.cpp
- /*!
- \internal
- Returns \a obj if object \a obj inherits from this
- meta-object; otherwise returns 0.
- */
- 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)); //通过MetaObject信息比对来决定返回的内容
- }
- return 0; //如果在继承体系中没找到相应的metaobject信息,那么返回0
- }
最后说一句,上边说qobject_cast可以跨动态库的。网上没找到有人解释这句话,我猜想,可能意思是支持不同动态库的对象的转换,例如QObject和QWidget,隐含的条件当然是“被转换的对象,都从QObject这个根上继承下来的”,这个就好理解了。
以上就是qobject_cast()相关的代码。读一读然后写一些自己的理解和不懂的地方,收获还是很大的。有问题也请指正。