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))));
}
誰かが説明してくれますか?
これは少し複雑です...
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型のnullポインターのメソッドを呼び出します。
これはC++標準では許可されていないと思いますが、this
は実際にはメソッド内で使用されていないため、機能します。