型キャスト

Qt Developer Days 2010カンファレンスに参加して、Qtライブラリを使用するさまざまな外国企業のインタビューで最も人気のある質問の1つは、C ++での型変換の方法の違いの問題であることを学びました。 ここで、 static_castdynamic_castconst_castreinterpret_castCスタイルのキャストqobject_castqvariant_castの主な違いを見てみましょ







1. static_cast



構文:

  TYPE static_cast <TYPE>(オブジェクト); 




static_castは、ある静的タイプの式を別の静的タイプのオブジェクトと値に変換します。 数値型、ポインター、および継承階層への参照の変換は、上下両方でサポートされています。 チェックはコンパイルレベルで実行されるため、エラーが発生した場合は、アプリケーションまたはライブラリのビルド時にメッセージが受信されます。



2. dynamic_cast



構文:

  TYPE&dynamic_cast <TYPE&>(オブジェクト);
 TYPE * dynamic_cast <TYPE *>(オブジェクト); 




実行時の動的なキャストに使用されます。 リンクのキャストが正しくない場合、std :: bad_cast例外がスローされ、ポインターに0が返されますRTTI(Runtime Type Information)システムを使用します。 仮想継承を含む、継承階層に従った安全な型キャスト。



3. const_cast



構文:

  TYPE const_cast <TYPE>(オブジェクト); 




おそらく最も単純な型変換。 cv修飾子-constおよびvolatile、つまり、コンパイラーによる変数の最適化の不変性と拒否を削除します。 この変換はコンパイルレベルでチェックされ、型変換エラーの場合はメッセージが表示されます。



4. reinterpret_cast



構文:

  TYPE reinterpret_cast <TYPE>(オブジェクト); 




チェックせずに型キャストします。 reinterpret_cast-コンパイラへの直接参照。 プログラマーが自分の行動に完全に自信がある場合にのみ使用されます。 定数と揮発性を削除しません。 ポインターをポインターに、ポインターを全体に、またはその逆にキャストするために使用されます。



5. Cスタイルのキャスト



構文:

  TYPE(TYPE *)オブジェクト。 




型変換の一貫した方法。 おそらく最も望ましくない型変換方法です。 Straustrupの書き込み:

「たとえば、この式の意味-x =(T)y; 。 わかりません。 タイプT、タイプxおよびyに依存します。 Tは、型名、typedefにすることも、テンプレートパラメータにすることもできます。 xとyはスカラー変数であり、Tは変換の値を表します。 xはクラスYから派生したクラスのオブジェクトであり、Tは下方変換です。 このため、プログラマーは実際に何をしているのか分からない場合があります。」

Cスタイルでの型キャストの望ましくない使用の2番目の理由は、型キャストを見つけるプロセスの面倒さです。



6. qobject_cast



構文:

  TYPE qobject_cast <TYPE>(QObject *オブジェクト) 




タイプTYPEまたはタイプのオブジェクトがTYPEを継承する場合、QObject *オブジェクトをタイプTYPEにキャストします。それ以外の場合は0を返します。 クラスはQObjectを継承し、Q_OBJECTマクロを含む必要があります。 この関数は標準のdynamic_castと同様に動作しますが、RTTIは使用しません。 Qt 4.7.0でこの関数がどのように説明されるかを以下に示します。



template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  1. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  2. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  3. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  4. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  5. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  6. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  7. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



  8. template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .



template < class T> inline T qobject_cast(QObject * object ) { #if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>( object )); #endif return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast( object )); } * This source code was highlighted with Source Code Highlighter .







ここで何が起こっているのか:



まず、QT_NO_MEMBER_TEMPLATESが定義されていない場合(2002年より前のMicrosoft Visual Studioバージョンが使用されている場合にのみ定義されている)およびQT_NO_QOBJECT_CHECK(2003より前のMicrosoft Visual Studioバージョンが使用されている場合に定義されている場合)、クラス宣言でQ_OBJECTマクロがチェックされます。 その後、変換自体が直接実行されます-最初に、QMetaObjectクラスの静的オブジェクトを取得します。これはstaticMetaObjectと呼ばれ、キャストメソッドを呼び出します。キャストメソッドは、渡されたオブジェクトのconst_castを返し、同時にこのオブジェクトがQObjectから継承されているかどうかを確認します 次に、結果のオブジェクトがstatic_castになり、結果が返されます。



7. qvariant_cast



構文:

  TYPE qvariant_cast <TYPE>(定数QVariantおよび値) 




クラスQVariantのオブジェクトを目的のクラスにキャストします。 この関数は、qVariantValue関数に似ています。



内部で何が起こるか考えてください:







  1. テンプレート<typename T> inline T qvariant_cast( const QVariant&v)
  2. {
  3. const int vid = qMetaTypeId <T>(static_cast <T *>(0));
  4. if (vid == v.userType())
  5. return * reinterpret_cast < const T *>(v.constData());
  6. if (vid < int (QMetaType :: User)){
  7. T t;
  8. if (qvariant_cast_helper(v、QVariant :: Type(vid)、&t))
  9. tを返す ;
  10. }
  11. return T();
  12. }
*このソースコードは、 ソースコードハイライターで強調表示されました。




コードの最初のセクションでは、クラス識別子はQtメタシステムを通じて取得されます。 クラスがQ_DECLARE_METATYPEを介して登録されていない場合、コードをコンパイルしてこの型にキャストするとエラーが発生します。 さらに、メタシステムから受け取ったオブジェクトのタイプがQVariant値のタイプと一致する場合、クラス識別子が組み込みタイプではなく、そのIDがQVariant値の値と一致しない場合、オブジェクトのコンテンツのreinterpret_castが実行され、TYPE()が返されます。 組み込み型にキャストする場合、qvariant_cast_helper関数が呼び出され、その関数がconvert関数を呼び出します。この関数のアドレスはHandler構造に格納されています。 タイプTYPEに適した方法ですでにキャストしています。 変換が失敗した場合、TYPE()オブジェクトが返されます



UPD: Cスタイルのキャストは本質的に最も遅い変換です。この場合、次の呼び出しが順次スキャンされるためです。





UPD:ありがとうBaJlepa

1. const_castはcv修飾子を追加することもできます

2.ポインターを変換するには、reinterpret_castではなくvoid *を介してdouble static_castを使用することをお勧めします。このような変換により、ポインターのみがキャストに含まれることを確認できるためです。



ソース:

a) http://alenacpp.blogspot.com/2005/08/c.html

b) http://www.cppreference.com

c) http://www.cplusplus.com/doc/tutorial/typecasting/

d) http://doc.qt.nokia.com/4.7/qobject.html#qobject_cast

e) http://www2.research.att.com/~bs/bs_faq2.html

e) http://doc.qt.nokia.com/4.7/qvariant.html#qvariant_cast

UPD: g) http://www.rsdn.ru/Forum/Info/FAQ.cpp.c-stylecast.aspx



All Articles