web-dev-qa-db-ja.com

qobject_castはどのように機能しますか?

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

誰かが説明してくれますか?

39
ronag

これは少し複雑です...

qobject_cast<T>(obj) は、QObjectTから派生するターゲットタイプ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*。関数は単一の型パラメーターでテンプレート化されるため、TUは同じ型でなければなりません。

ここで、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は実際にはメソッド内で使用されていないため、機能します。

38
Amnon