Come funziona qobject_cast?
-
12-10-2019 - |
Domanda
Ho appena trovato il seguente codice in Qt e io sono un po 'confuso quello che sta succedendo qui.
Tanto più che a ciò che reinterpret_cast<T>(0)
fa?
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))));
}
Chiunque si preoccupa di spiegare?
Soluzione
Questo è un po 'complicato ...
Ricordate che qobject_cast<T>(obj)
è un modo per lanciare in modo dinamico un QObject
a il tipo di destinazione T
che deriva anche da QObject
. Ora, per questo al lavoro, il Q_OBJECT
macro dovrebbe essere inclusa nella definizione della classe di T
.
A quanto pare, la chiamata qt_check_for_QOBJECT_macro
è per controllare che la classe non contiene effettivamente la macro Q_OBJECT. Quando la macro viene espansa, contiene le seguenti definizioni:
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; }
Quindi, se si dispone di un oggetto di tipo x
T
ed un y
oggetto di tipo U
, il x->qt_check_for_QOBJECT_macro(y)
chiamata chiama la funzione qYouForgotTheQ_OBJECT_Macro
con i parametri di tipi T*
e U*
. Poiché la funzione viene templato con un parametro singolo tipo, i tipi T
e U
devono essere uguali.
Ora, se si chiama x->qt_check_for_QOBJECT_macro(x)
allora si dovrebbe aspettare i tipi di essere lo stesso e per la compilazione a banalmente avere successo. Tuttavia, ricorda che this
ha lo stesso tipo come la classe il metodo è stato definito in. Quindi, se x
è di una classe che è stato derivato dal T ma non contiene la propria definizione di qt_check_for_QOBJECT_macro
, la chiamata avrà esito negativo.
Quindi abbiamo un modo per verificare se il tipo di destinazione T contiene il meccanismo corretto per il cast dinamico, ma non abbiamo un oggetto di tipo T per chiamare questo metodo su ancora. Questo è ciò che la reinterpret_cast<T>(0)
è per. Non abbiamo bisogno di un oggetto reale come this
, dal momento che il compilatore ha bisogno solo i tipi di oggetti per il controllo per avere successo. Invece, noi chiamiamo un metodo su un puntatore nullo di tipo T.
Non credo che ciò sia consentito dal C ++ standard, ma opera da this
non viene effettivamente utilizzato all'interno del metodo.