Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top