Cast casting

  • C cast
  • C++ cast
    • Static_cast Static conversion (check at compile time)
    • Const_cast Constant conversion
    • Reinterpret_cast reinterpret_conversion
    • Dynamic_cast Dynamic conversion (runtime check)
  • The point to summarize

C cast

The C language is mainly used to cast common data types and Pointers. There is no type check and conversion is not secure. The syntax is:

(type-id)expression// Convert format 1 type-id(expression)// Convert format 2 (almost no longer used) Copy codeCopy the code

C++ cast

In addition to casting in C language, C++ also has four new casting types: Static_cast, dynamic_cast, CONST_cast, and reinterpret_cast, which are mainly used for casting between inheritance relation classes. The syntax is:

// Static_cast <new_type> (expression) // static_cast<new_type> (expression) (expression) // Reinterpret_cast <new_type> (expression) Copy codeCopy the code

New type indicates the converted new type, and expression indicates the old type

Static_cast Static conversion (check at compile time)

Usage: Static_cast < type specifier > (variable or expression)

A static_cast is equivalent to a CAST in C, but cannot be used to cast ordinary pointer data (except null Pointers). It is used to cast parent and subclass Pointers and references.

  1. Used to convert Pointers or references between base (parent) and derived (subclass) classes in a class hierarchy. Whether polymorphic or not, the compiler does not report errors when a parent and child cross paths. (1) It is safe to perform upstream conversions (to convert a pointer or reference to a derived class to a base class representation); (2) Downconversion (converting a base pointer or reference to a derived class representation) is not safe because there is no dynamic type checking, but the compiler does not report an error.
  2. Used to convert basic data types, such as int to char and int to enum. The security of this transformation is also up to the developer.
  3. Converts a null pointer to a null pointer of the target type.
  4. Converts any pointer type to a null pointer type.

Note: Static_cast does not convert the const, volatile, or __unaligned attribute of expression

If classes are involved, static_cast can only be converted between related types and does not necessarily contain virtual functions.


In C++, static_cast is used to cast data types, forcing a cast from one data type to another. For example, converting integer data to floating point data.

[Example 1] The type conversion method used by LANGUAGE C:

#include <iostream> using namespace std; int main() { int a = 10; int b = 3; double result = (double)a / (double)b; cout << result << endl; / / 3.33333 return 0; } Duplicate codeCopy the code

Example 1 converts integer variables A and b to a double-precision floating-point type and then divides. In C++, we can use the static_cast keyword for casting, as shown below.

[example 2] Static_cast

#include <iostream> using namespace std; int main() { int a = 10; int b = 3; double result = static_cast<double> (a) / static_cast<double> (b); // Static_cast <double> cout << result << endl; / / 3.33333 return 0; } Duplicate codeCopy the code

In this case, the integer variable A is also converted to a double precision floating point. When casting static_cast, place the data type you want to convert into Angle brackets and the variable or expression you want to convert into meta-brackets.

Const_cast Constant conversion

In C, the const qualifier is usually used to qualify a variable to indicate that its value cannot be modified.

Static_cast does not convert const int* to int*, const_cast does,

Usage: const_cast

(expression)

Const_cast, used to modify the const or volatile property of a type. Const can only be added or removed from variables that are references or Pointers. (Type_id and expression are of the same type except for const or volatile modifiers.)

Const_cast is used to enforce the removal of constants that cannot be modified. It is important to note that const_cast is not used to remove the constancy of variables. It is used to remove the constancy of Pointers or references to constant objects, which must be Pointers or references.

Constant Pointers are converted to nonconstant Pointers that still point to the original object;

Constant references are converted to nonconstant references and still refer to the original object; Constant objects are converted to nonconstant objects.

int main() { const int a = 10; const int* p = &a; int* q = const_cast<int*>(p); *q = 20; //fine cout << "a=" << a << " " << "&a = " << &a << endl; cout << "*p=" << *p << " " << "p = " << p << endl; cout << "*q=" << *q << " " << "q = " << q << endl; return 0; } //a = 10&a = 012FFC10 //* p = 20 p = 012FFC10 //* q = 20 q = 012FFC10 copy codeCopy the code
int main() { int c = 11; const int a = c; const int* p = &a; int* q = const_cast<int*>(p); *q = 20; //fine cout << "a=" << a << " " << "&a = " << &a << endl; cout << "*p=" << *p << " " << "p = " << p << endl; cout << "*q=" << *q << " " << "q = " << q << endl; return 0; } //a = 20&a = 007BFD64 //* p = 20 p = 007BFD64 //* q = 20 q = 007BFD64 copy codeCopy the code
int main() { const int c = 11; const int a = c; const int* p = &a; int* q = const_cast<int*>(p); *q = 20; //fine cout << "a=" << a << " " << "&a = " << &a << endl; cout << "*p=" << *p << " " << "p = " << p << endl; cout << "*q=" << *q << " " << "q = " << q << endl; return 0; } //a = 11&a = 00EFFB44 //* p = 20 p = 00EFFB44 //* q = 20 q = 00EFFB44 copy codeCopy the code

012FFC10 = 012FFC10; 012FFC10 = 012FFC10; Why is the value of A still printed out as 10?

This is actually a good thing, and we’re glad that variable A didn’t end up at 20! The variable a is originally declared as a constant variable, and no matter what subsequent programs do with it, it will remain constant. Imagine what would happen if this variable a ended up being 20? For the short program, if finally turned into a 20, we will see a pointer is q changed, but once a project is very large, somewhere in the emergence of a pointer q, it can modify the constants a, this is a very terrible thing, can be said to be the vulnerability of a program, After all, declaring variable A as a constant means you don’t want to change it, which would be horrible if you could change it later.

We call “*q=20” statements undefined behavior. Undefined behavior means that the statement’s behavior is not specified in the standard C++ specification, and it is up to the compiler to decide what to do with it. Statements with undefined behavior should be avoided at all costs!

Reinterpret_cast reinterpret_conversion

In C++, a reinterpret_cast has three main uses: changing the type of a pointer or reference; converting a pointer or reference to an integer of sufficient length; and converting an integer to a pointer or reference. reinterpret_cast

(expression)

Type-id must be a pointer, reference, arithmetic type, function pointer, or member pointer.

It can convert a pointer to an integer, or an integer to a pointer (first converting a pointer to an integer, then converting the integer to a pointer of the original type, and then returning the original pointer value).

The types we map to are only for confusing and other purposes, and this is the most dangerous mapping of all. (this phrase is from C++ programming thought). Therefore, you should use reinterpret_cast with caution.

int *a = new int; double *d = reinterpret_cast<double *>(a); Copy the codeCopy the code

In the code above, an integer pointer is cast to a double-precision floating-point pointer via reinterpret_cast. A reinterpret_cast converts a pointer or reference into an integer of sufficient length, which depends on the operating system. A 32-bit operating system requires an integer of 4 bytes or more, while a 64-bit operating system requires an integer of 8 bytes or more.

typedef void (* FUNC)(); int DoSomething (int i) { cout<< "DoSomething" <<endl; return 0; } void Test () {// reinterpret_cast makes it possible for the compiler to interpret a DoSomething function in a FUNC way. FUNC f = reinterpret_cast<FUNC>(DoSomething); // C++ does not guarantee that all function Pointers will be used the same. f(); } Duplicate codeCopy the code

Dynamic_cast Dynamic conversion (runtime check)

It is mainly used for conversion of Pointers or references between base classes (parent classes) and derived classes (subclasses) in a class hierarchy (can only be used for conversion between classes, supports cross conversion between classes, cannot operate on ordinary data).

  1. Dynamic_cast has the same effect as static_cast during class conversion, when ascending between class hierarchies. Dynamic_cast is more secure than Static_cast because it has type checking for downlink conversions. [1] Upconversion, that is, the subclass pointer to the parent class pointer (usually not a problem); A downward cast, in which a parent class pointer is converted to a child class pointer. [2] The success of downward conversion is also related to the type to be converted. That is, the actual type of the object to be converted must be the same as the converted object type; otherwise, the conversion will fail. [3] in C++, compile-time conversions may cause errors at runtime, especially when they involve Pointers or references to class objects. The Dynamic_cast operator can be used to test type conversions that might cause problems at run time.
  2. When polymorphism occurs, interconversion is allowed.
  3. Classes that have no inheritance relationship can also be converted to each other.
  4. If the dynamic_cast statement converts to a pointer type and fails, the result is 0. If the conversion target is a reference type and fails, the dynamic_cast operator throws an STD ::bad_cast exception
  5. If dynamic_cast is used for conversion, it must have a virtual function in the base class, otherwise the compilation fails. (If a virtual function exists in the class, it wants a pointer or reference to the base class to point to a derived object, then the conversion makes sense.) This is because runtime type checking requires runtime type information, which is stored in the virtual function table of the class, which is only available for classes that define virtual functions.
class base { public: void print1() { cout << "in class base" << endl; }}; class derived : public base { public: void print2() { cout << "in class derived" << endl; }}; int main() { derived* p, * q; // p = new base; // Compilr Error: cannot convert "base * "to "derived *" // Compile Error: Cannot cast from 'base*' to 'derived*' via dynamic_cast: Expression type is not polymorphic // p = dynamic_cast<derived *>(new base); q = static_cast<derived*>(new base); // ok, but not recommended q->print1(); // in class base q->print2(); // in class derived return 0; } Duplicate codeCopy the code

As you can see from the above code, using a pointer to a derived class cannot point directly to an object of a base class, resulting in a compilation error. Dynamic_cast also generates a compilation error telling us that the base class is not polymorphic, meaning that there are no virtual functions in the base class. You can see that static_cast compiles and the output looks correct

Dynamic_cast does not provide type-safe casting, but C++ provides dynamic_cast, which checks for type-safe casting at runtime. Dynamic_cast is also used conditionally, requiring that the converted expression must contain a polymorphic class type (that is, a class that contains at least one virtual function).

The point to summarize

  • Static_cast: Almost as powerful and meaningful as c-style casts. It has functional limitations. For example, you can’t use static_cast to convert a struct to an int or a double to a pointer like you can with a C-style cast. In addition, static_cast cannot remove a const attribute from an expression, because another new type converter, CONST_cast, does that. The conversion possibilities of types can be determined statically, even in an inheritance system, even if multiple inheritance and virtual inheritance are included, as long as the static resolution can be carried out, the conversion can be successful
  • Const_cast: The const or volatile attribute used for type conversion of an expression. By using const_cast, you emphasize to people and the compiler that all you want to do with type conversion is change the constness or volatieness property of something. This meaning is constrained by the compiler. If you try to use const_cast to do anything other than change the constness or volatileness property, your conversion will be rejected.
  • Reinterpret_cast: A type conversion using this operator, the result of which is almost always an execution-time definition. As a result, code using reinterpret_cast is difficult to port. The most common use for reinterpret_casts is for converting between function pointer types.
  • Dynamic_cast: This is used to safely cast down class inheritance. That is, you can use dynamic_cast to convert a pointer or reference to a base class into a pointer or reference to its derived or sibling class, and you can tell if the conversion was successful. A failed conversion will either return a null pointer (when a pointer is typed) or throw an exception (when a reference is typed).

RTTI (the Run – time Type identification) :

Through runtime type information programs can use Pointers or references to base classes to check the actual derived type of the object to which those Pointers or references refer. (Runtime type recognition)

  1. Typeid operator that returns the actual type to which the pointer and reference refer:

You can determine the type of a variable, you can determine whether two variables have the same type, and you can print the type of a variable (name()).

For example, typeid(a).name() tells you what type of variable a is

  1. The dynamic_cast operator safely converts a pointer or reference of a base class type to a pointer or reference of a derived type:

RTTI technique is used to transform parent-child class Pointers. Prevents native parent Pointers from being converted to child Pointers. This is prevented by throwing a BAD_cast exception and changing the expression’s value to NULL.