Как работает qobject_cast? - PullRequest
       30

Как работает qobject_cast?

39 голосов
/ 23 декабря 2010

Я только что нашел следующий код в Qt, и я немного запутался, что здесь происходит.

Особенно, что reinterpret_cast<T>(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))));
}

Кто-нибудь хочет объяснить?

1 Ответ

38 голосов
/ 23 декабря 2010

Это немного сложно ...

Помните, что 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 фактически не используется внутри метода.

...