1. Type conversion in C language
In C language, if the types of the left and right sides of the assignment operator are different, or the shape participating argument types do not match, or the return value type is inconsistent with the received return value type, type conversion is required. There are two forms of type conversion in C language: implicit type conversion and explicit type conversion.
- Implicit type conversion: the compiler performs automatic conversion at the compilation stage. If it can be converted, it will fail to compile
- Explicit type conversion: it needs to be handled by the user
void Test() { int i = 1; // Implicit type conversion double d = i; printf("%d, %.2f\n", i, d); int* p = &i; // Cast type for display int address = (int)p; printf("%x, %d\n", p, address); }
Defect: the visibility of conversion is poor. All conversion forms are written in the same form, so it is difficult to track the wrong conversion
The C-style conversion format is very simple, but it has many disadvantages:
- Implicit type conversion may cause problems in some cases, such as loss of data precision
- Explicit type conversion mixes everything together, and the code is not clear enough
Therefore, C + + puts forward its own type conversion style. Note that because C + + is compatible with C language, the conversion style of C language can also be used in C + +.
2. C + + cast
In order to enhance the visibility of type conversion, standard C + + introduces four named forced type conversion operators:
static_cast,reinterpret_cast,const_cast,dynamic_cast
2.1 static_cast
static_ Cast is used for conversion of non polymorphic types (static conversion). static_cast can be used for any type conversion implicitly performed by the compiler, but it cannot be used for conversion of two unrelated types.
int main() { double d = 12.34; int a = static_cast<int>(d); cout<<a<<endl; return0; }
2.2 reinterpret_cast
reinterpret_ The cast operator usually provides a lower level reinterpretation of the bit pattern of the operand, which is used to convert one type to a different type (unrelated type)
typedef void(*FUNC)(); int DoSomething(int i) { cout << "DoSomething" << endl; return 0; } void Test() { // // reinterpret_ The cast compiler can view DoSomething functions in the way of FUNC definition // Therefore, the following code for converting function pointers is not portable, so it is not recommended to use this method // C + + does not guarantee that all function pointers are used the same, so sometimes using them will produce uncertain results // FUNC f = reinterpret_cast<FUNC>(DoSomething); f(); }
2.3 const_cast
const_ The most common use of cast is to delete the const attribute of variables to facilitate assignment
void Test () { const int a = 2; const int* pa = &a; int* p = const_cast<int*>(pa); *p = 3; cout<<a <<endl; cout<<*p <<endl; }
Answer: a=2, * p=3, because a is a variable in the constant area, which can only be read and cannot be modified. However, because it is relatively small, the compiler will optimize and directly store this value in the register. Even if the address of a has been obtained and the value of a has been changed, the compiler will directly print the value in the register. (therefore, in order to avoid excessive optimization of the compiler, the keyword volatile can be added to tell the compiler not to get the value of a from the register, but to get the value of a from the memory.)
2.4 dynamic_cast
dynamic_cast is used to convert a pointer / reference of a parent object to a pointer or reference of a child object (dynamic conversion)
- Upward Transformation: subclass object pointer / reference - > parent class pointer / reference (naturally supported by derived class and base class, also known as slicing)
- Downward Transformation: parent object pointer / reference - > child class pointer / reference (it is safe to use dynamic_cast transformation) (because there may be a risk of crossing the boundary, it is unsafe)
be careful:
- dynamic_cast can only be used for classes containing virtual functions (the parent class must contain at least one virtual function). If the polymorphic conditions are not met, reinterpret_cast is used for conversion.
- dynamic_cast will first check whether the conversion is successful. If it is successful, the conversion will be successful. If not, 0 will be returned
class A { public: virtual void func() {} protected: int _a = 0; }; class B :public A { protected: int _b = 1; }; int main() { A aa; B bb; A* pa = &aa; B* pb = &bb; //pa = pb;// Turn up, natural support, slice pb = (B*)pa;//Turn down, with risk pb->_b = 0; // Possible risks return 0; }
int main() { A aa; B bb; A* pa = &aa; B* pb = &bb; pa = pb;//Turn up, natural support, slice //If pa refers to a derived class, the conversion is safe and can be converted normally to return the normal address //2. If pa points to the base class, the conversion is not safe. The conversion cannot occur and NULL is returned pb = dynamic_cast<B*>(pa); if (pb) { cout << "Conversion succeeded" << endl; } else { cout << "switch views" << endl; } return 0; }
3. explicit and RTTI (runtime type identification)
explicit keywordprevents implicit conversion by a conversion constructor
class A { public : explicit A (int a) { cout<<"A(int a)" <<endl; } A(const A& a) { cout<<"A(const A& a)" <<endl; } private : int _a ; }; int main () { A a1 (1); // Implicit conversion - > a TMP (1); A a2(tmp); // A a2 = 1; //It should be used like this A a2 = static_cast<A>(1); }
RTTI: short for Run-time Type identification, i.e. runtime type identification.
C + + supports RTTI in the following ways:
- The typeid operator returns a string of type typeid (object) name())
- dynamic_cast operator
- decltype