web-dev-qa-db-fra.com

Comment fonctionne qobject_cast?

Je viens de trouver le code suivant dans Qt et je suis un peu confus ce qui se passe ici.

Surtout pour ce que fait 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))));
}

Quelqu'un veut-il expliquer?

39
ronag

C'est un peu compliqué ...

Rappelez-vous que qobject_cast<T>(obj) est un moyen de convertir dynamiquement un QObject en type cible T qui dérive également de QObject. Maintenant, pour que cela fonctionne, la macro Q_OBJECT Doit être incluse dans la définition de la classe T.

Apparemment, l'appel qt_check_for_QOBJECT_macro Sert à vérifier que la classe contient vraiment la macro Q_OBJECT. Lorsque la macro est développée, elle contient les définitions suivantes:

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; }

Donc, si vous avez un objet x de type T et un objet y de type U, l'appel x->qt_check_for_QOBJECT_macro(y) appelle la fonction qYouForgotTheQ_OBJECT_Macro Avec les paramètres des types T* Et U*. Étant donné que la fonction est basée sur un modèle avec un seul paramètre de type, les types T et U doivent être identiques.

Maintenant, si vous appelez x->qt_check_for_QOBJECT_macro(x), vous devez vous attendre à ce que les types soient les mêmes et que la compilation réussisse trivialement. Cependant, n'oubliez pas que this a le même type que la classe dans laquelle la méthode a été définie. Donc, si x appartient à une classe dérivée de T mais ne contient pas sa propre définition de qt_check_for_QOBJECT_macro, L'appel échouera.

Nous avons donc un moyen de vérifier si le type cible T contient le mécanisme correct pour la distribution dynamique, mais nous n'avons pas encore d'objet de type T pour appeler cette méthode. C'est à cela que sert la reinterpret_cast<T>(0). Nous n'avons pas besoin d'un objet réel comme this, car le compilateur n'a besoin que des types d'objet pour que la vérification réussisse. Au lieu de cela, nous appelons une méthode sur un pointeur nul de type T.

Je ne pense pas que cela soit autorisé par la norme C++, mais cela fonctionne puisque this n'est pas réellement utilisé à l'intérieur de la méthode.

38
Amnon