Before we go into the four transformation operators in C + +, let's talk about the drawbacks of legacy transformations:
① It almost allows any type to be converted to any other type, which is very poor. It would be better if each transformation would be more precise in identifying the intention.
② old-fashioned transformation is difficult to identify. The syntax structure for legacy transformations consists of a pair of parentheses plus an object name, while the parentheses and object names are likely to be used anywhere in C + +.
To address the shortcomings of the C legacy transformation, C + + imported 4 new transformation operators: static_cast, Const_cast, dynamic_cast, reinterpret_cast. Let me analyze each of these four transformation operators.
1) static_cast
Static_cast basically has the same power and meaning as the C legacy transformation, along with the same limitations. For example, you cannot use static_cast to transform a struct into an int, or a double to pointer, which is a task that the C legacy transformation action could not have done. Static_cast is not even able to remove the constants of an expression.
int A, B;
...
Double C = static_cast<double> (a)/b;
2) const_cast
const_cast is used to change the constant (constness) or variable (volatileness) in an expression. Using const_cast, it is emphasized to humans (and compilers) that through this transformation operator, the only thing we want to change is the constant or variable nature of something. If the const_cast is applied to the intended use, then the transformational action is rejected. Let's look at an example:
Class widget{...};
Class Specialwidget:public Widget {...};
void Update (specialwidget* PSW);
Specialwidget SW;//SW is a Non-const object.
Const specialwidget& CSW = SW;//CSW is a reference that represents SW and is considered a const object
Update (&CSW);//Error! Cannot speak Const specialwidget* to a function that needs specialwidget*
Update (const_cast<specialwidget*> (&CSW));//Can! The constant nature of the &CSW was removed. Therefore, CSW (i.e. SW) can be changed in this function.
Update ((specialwidget*) &CSW);//The same as the case, but using the more difficult to identify the C-legacy transformation syntax
widget* pw = new Specialwidget;
Update (PW);//Error! The type of PW is widget*, but update () requires specialwidget*.
Update (const_cast<specialwidgt*> (PW));//Error! Const_cast can only be used to influence the constants or the variation of the inheritance system.
3) dynamic_cast
①dynamic_cast is used to perform "safe downward or cross-system transition actions" in the inheritance system. That means you can use dynamic_cast to transform "pointers or references to base class objects" to "point to derived (or sibling base) class Objects pointers or references ", and know if the transition is successful. If the transformation fails, it is shown with a null pointer (when the transformed object is a pointer) or a exception (when the transformed object is reference):
widget* PW;
...
Update (dynamic_cast<specialwidget*> (PW));//good, pass to update () a pointer to the specialwidget referred to by PW----If PW really points to something like this Otherwise, the pass will be a null pointer
void Updateviaref (specialwidget& RSW);
Updateviaref (dynamic_cast<specialwidget&> (*PW));//Very good, passed to Updateviaref () is the specialwidget referred to by PW----If PW really points to something like this; throw a exception
Dynamic_cast can only be used to help you cruise under the inheritance system. It cannot be applied to a type that lacks virtual functions, nor can it change the constant nature of a type.
the second use of ②dynamic_cast is to find the starting point of memory occupied by an object. For example:
Class heaptracked
{
Public
BOOL Isonheap () const;
Private
typedef const VOID* Rawaddress;
static list<rawaddress> addresses;
};
BOOL Heaptracked::isonheap () const
{
Const void* rawaddress = Dynamic_cast<const void*> (this);//Get a pointer to the beginning of the memory occupied by *this
List<rawaddress>::iterator it = Find (Addresses.begin (), Addresses.end (), rawaddress);
return it! = Addresses.end ();
}
Any object involving multiple inheritance or virtual base classes will have multiple addresses, as long as the pointer is simply "dynamically transformed" to void* (or const void* or volatile void* or const volatile void*), a pointer is obtained, pointing to the The original pointer refers to the object "at the beginning of the memory. However, dynamic_cast only applies to those pointers that "the object has at least one virtual function".
4) reinterpret_cast
The conversion result of this operator is almost always related to the compiler platform. So the reinterpret_cast is not transplanted.
The most common use of reinterpret_cast is to convert the "function pointer" type. Suppose you have an array that stores all the function pointers, with specific types:
typedef void (*FUNCPTR) ();//funcptr is a pointer to a function.
Funcptr Funcptrarray[10];//funcptrarray is a number group with 10 funcptrs in it.
Suppose, for some reason, you want to put a pointer to the following function into Funcptrarray:
int dosomething ();
If there is no transformation, it is impossible to do this because the type of dosomething is different from the funcptrarray acceptable. The return value of the function pointer within Funcptrarray is void, but the return value of dosomething is int:
FUNPTRARRAY[0] = &dosomething;//Error! Type is not correct
Using reinterpret_cast, you can force the compiler to understand your intentions.
Funcptrarray[0] = reinterpret_cast<funcptr> (&dosomething);
The transition action of a function pointer is not portable (c + + does not guarantee that all function pointers can be re-rendered in this way), and in some cases such a transformation may result in incorrect results, so you should try to avoid transforming function pointers.
If the compiler has not yet supported these modern transformation actions, you can also replace static_cast, Const_cast, and reinterpret_cast with traditional transformation methods. You can even use macros to emulate these new grammars.
#define STATIC_CAST (type,expr) ((TYPE) (EXPR))
#define CONST_CAST (type,expr) ((TYPE) (EXPR))
#define REINTERPRET_CAST (type,expr) ((TYPE) (EXPR))
As for dynamic_cast, you can also go back to using the old type C syntax, or define a macro, but they can't tell you if the transformation was successful.