📜 ⬆️ ⬇️

Cast

Being at the Qt Developer Days 2010 conference, I learned that one of the most popular questions at the interview with different foreign companies working with the Qt library is the issue of differences in the methods of type casting in C ++. So here I will review the main differences between static_cast , dynamic_cast , const_cast , reinterpret_cast , C-style cast , qobject_cast and qvariant_cast



1. static_cast .
')
Syntax:
  TYPE static_cast <TYPE> (object); 


static_cast converts expressions of one static type into objects and values ​​of another static type. It supports the conversion of numerical types, pointers and references according to the inheritance hierarchy both up and down. The check is performed at the compilation level, so in case of an error, the message will be received at the time of building the application or library.

2. dynamic_cast

Syntax:
  TYPE & dynamic_cast <TYPE &> (object);
 TYPE * dynamic_cast <TYPE *> (object); 


Used for dynamic type casting at run time. If the types are incorrectly cast, an exception std :: bad_cast is raised for references, and 0 is returned for pointers. It uses the RTTI (Runtime Type Information) system. Safe coercion of types across the inheritance hierarchy, including for virtual inheritance.

3. const_cast .

Syntax:
  TYPE const_cast <TYPE> (object); 


Perhaps the simplest type conversion. Removes cv qualifiers - const and volatile, that is, constancy and refusal to optimize the variable compiler. This conversion is checked at the compilation level and a message will be displayed in case of a typecast error.

4. reinterpret_cast

Syntax:
  TYPE reinterpret_cast <TYPE> (object); 


Type casting without checking. reinterpret_cast - direct indication to the compiler. It is applied only in case of full confidence of the programmer in his own actions. Does not remove constancy and volatile. used to bring a pointer to a pointer, a pointer to a whole and vice versa.

5. C-style cast

Syntax:
  TYPE (TYPE *) object; 


Si-shny method of coercion of types. Perhaps the most undesirable method of casting. Stroustrup writes:
“For example, what does the expression mean - x = (T) y; . We do not know. It depends on type T, types x and y. T may be a type name, a typedef, or it may be a template parameter. Maybe x and y are scalar variables and T is the value of the transform. Maybe x object of a class derived from class Y and T is a downward transform. For this reason, the programmer may not know what he is actually doing. ”
The second reason for the undesirable use of type casting in C-style is the complexity of the process of searching for type-casting places.

6. qobject_cast

Syntax:
  TYPE qobject_cast <TYPE> (QObject * object) 


Converts a QObject * object to a TYPE type if the object type of the TYPE object or type inherits from TYPE otherwise returns 0. qobject_cast from 0 also gives 0. Required condition. The class must inherit from QObject and contain the Q_OBJECT macro. The function behaves similarly to the standard dynamic_cast, but does not use RTTI. Here is how this function is described in 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 .


So, what is happening here:

First, if QT_NO_MEMBER_TEMPLATES is not defined (defined only if Microsoft Visual Studio is lower than 2002) and QT_NO_QOBJECT_CHECK (determined when Microsoft Visual Studio is lower than 2003), then the Q_OBJECT macro is present in the class declaration. And then the conversion itself is performed directly - first we get a static object of the QMetaObject class, called staticMetaObject, which calls the cast method, which returns the object passed to it by const_cast, checking whether the given object inherits from QObject. Next, the resulting object is static_cast and the result is returned.

7. qvariant_cast

Syntax:
  TYPE qvariant_cast <TYPE> (const QVariant & value) 


Brings the QVariant class object to the desired class. The function is similar to the qVariantValue function.

Consider what happens inside:

  1. template <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. return t;
  10. }
  11. return T ();
  12. }
* This source code was highlighted with Source Code Highlighter .


In the first section of the code, the class identifier is obtained via the Qt metasystem. In the event that the class is not registered through Q_DECLARE_METATYPE, compiling the code with a cast to this type will generate an error. Further, if the object type received from the metasystem coincides with the type in the QVariant value, the object content is reinterpret_cast, if the class identifier is not a built-in type and its id does not match the value embedded in the QVariant value, then TYPE () is returned. For cases when we cast to the built-in type, the qvariant_cast_helper function is called, which in turn calls the convert function, whose address is stored in the Handler structure. It is already being cast in a way suitable for the TYPE type. If the conversion fails, the TYPE () object is returned.

UPD: C-style cast is essentially the slowest conversion, since in this case the following calls are sequentially sorted:


UPD: Thank you BaJlepa :
1. const_cast can also add cv qualifiers
2. for the conversion of pointers, it is better to use double static_cast via void * instead of reinterpret_cast, because such a conversion allows you to be sure that only pointeres are involved in casting

Sources:
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

Source: https://habr.com/ru/post/106294/


All Articles