How does qobject_cast work?
This is a little complicated...
Remember that qobject_cast<T>(obj)
is a way to dynamically cast a QObject
to the target type T
which also derives from QObject
. Now, for this to work, the macro Q_OBJECT
should be included in the definition of class T
.
Apparently, the qt_check_for_QOBJECT_macro
call is for checking that the class really contains the Q_OBJECT macro. When the macro is expanded, it contains the following definitions:
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; }
template <typename T1, typename T2>
inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
So if you have an object x
of type T
and an object y
of type U
, the call x->qt_check_for_QOBJECT_macro(y)
calls the function qYouForgotTheQ_OBJECT_Macro
with parameters of types T*
and U*
. Because the function is templated with a single type parameter, the types T
and U
must be the same.
Now, if you call x->qt_check_for_QOBJECT_macro(x)
then you should expect the types to be the same and for the compilation to trivially succeed. However, remember that this
has the same type as the class the method was defined in. So if x
is of a class that was derived from T but doesn't contain its own definition of qt_check_for_QOBJECT_macro
, the call will fail.
So we have a way to check if the target type T contains the correct mechanism for the dynamic cast, but we don't have a object of type T to call this method on yet. That's what the reinterpret_cast<T>(0)
is for. We don't need an actual object as this
, since the compiler only needs the object types for the check to succeed. Instead, we call a method on a null pointer of type T.
I don't think this is allowed by the C++ standard, but it works since this
isn't actually used inside the method.
ronag
Master of Science (M.Sc.), Software Engineering and Technology at Chalmers University of Technology. I wrote most of CasparCG 2.0 Server, an open-source video- and graphics playout server used by the Swedish Broadcasting Corporation 24/4 for all regional and national broadcasts in Sweden. Big fan of the ffmpeg project.
Updated on January 06, 2020Comments
-
ronag over 4 years
I just found the following code in Qt and I'm a bit confused what's happening here.
Especially as to what
reinterpret_cast<T>(0)
does?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)))); }
Anyone care to explain?
-
Samuel Harmer over 12 yearsCould you clarify which part you don't think is allowed by the C++ standard? I'm curious.
-
Matthew Read over 11 yearsThe method is static, it's not called "on" the pointer.
this
would reference the caller and not a non-existent object. -
Amit Tomar over 11 years
Now, for this to work, the macro Q_OBJECT should be included in the definition of class T.
This might be wrong. Qt document here saysWhile it is possible to use QObject as a base class without the Q_OBJECT macro and without meta-object code, neither signals and slots nor the other features described here will be available if the Q_OBJECT macro is not used.