Это немного сложно ...
Помните, что qobject_cast<T>(obj)
- это способ динамического приведения QObject
к типу цели T
, который также происходит от QObject
. Теперь, чтобы это работало, макрос Q_OBJECT
должен быть включен в определение класса T
.
Очевидно, вызов qt_check_for_QOBJECT_macro
предназначен для проверки того, что класс действительно содержит макрос Q_OBJECT. Когда макрос развернут, он содержит следующие определения:
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; }
Итак, если у вас есть объект x
типа T
и объект y
типа U
, вызов x->qt_check_for_QOBJECT_macro(y)
вызывает функцию qYouForgotTheQ_OBJECT_Macro
с параметрами типов T*
и U*
. Поскольку функция шаблонизируется одним параметром типа, типы T
и U
должны быть одинаковыми.
Теперь, если вы позвоните x->qt_check_for_QOBJECT_macro(x)
, вы должны ожидать, что типы будут одинаковыми, и компиляция будет тривиально успешной. Однако помните, что this
имеет тот же тип, что и класс, в котором был определен метод. Поэтому, если x
относится к классу, который был получен из T, но не содержит своего собственного определения qt_check_for_QOBJECT_macro
, вызов потерпеть неудачу.
Таким образом, у нас есть способ проверить, содержит ли целевой тип T правильный механизм для динамического приведения, но у нас пока нет объекта типа T для вызова этого метода. Вот для чего reinterpret_cast<T>(0)
. Нам не нужен фактический объект как this
, так как компилятору нужны только типы объектов для успешной проверки. Вместо этого мы вызываем метод для нулевого указателя типа T.
Я не думаю, что это разрешено стандартом C ++, но оно работает, поскольку this
фактически не используется внутри метода.