Comparison of static_cast, dynamic_cast, reinterpret_cast, and const_cast, staticcastconst

Source: Internet
Author: User

Comparison of static_cast, dynamic_cast, reinterpret_cast, and const_cast, staticcastconst
Implicit conversion (implicit conversion)

short a=2000;int b;b=a;

Short is a two-byte short, int Is a four-byte short-type conversion to int-type width conversion (increasing bit bits). The Compiler does not have a warning, as shown in. Wide conversion (for example, char to int, int to long, int to float, float to double, int to double) constitutes implicit conversion, and the compiler allows direct conversion.

However

double a=2000;short b;b=a;

At this time, the short variable is converted from the 8-byte double type to the 2-byte type. The narrow conversion will enable the compiler to have warning, as shown below, reminding programmers that data may be lost. However, for some implicit conversions, the compiler may not provide warnings, such as int to short, but data overflow still occurs.

Explicit C style conversion (C style explicit conversion)

It is very easy to remove the above waring. Programmers familiar with the C language know that there are two simple writing methods (C style conversion and function style conversion ):

double a=2000.3;short b;b = (short) a;    // c-like cast notationb = short (a);    // functional notation 

As shown in, warning is gone.

This explicit conversion method is simple and intuitive, but not secure. An example of a parent class and a subclass is as follows:

// class type-casting#include <iostream>using namespace std;class CDummy {float i,j;CDummy():i(100),j(10){}};class CAddition:public CDummy{    int *x,y;  public:    CAddition (int a, int b) { x=&a; y=b; }    int result() { return *x+y;}};int main () {  CDummy d;  CAddition * padd;  padd = (CAddition*) &d;  cout << padd->result();  return 0;}

The compiler does not report any error, but the running result is incorrect, as shown in:

Note the following:Padd = (CAddition *) & d;

In this case, the pointer & d of the parent class is forcibly converted to the pointer of the subclass by the C-style conversion method, and the result of the subclass method is called later. You need to access ** x, however, the object to which the Pointer Points is essentially a parent class, so x is equivalent to I in the parent class, y is equivalent to j in the parent class, and * x is equivalent to * I, but I is a float variable (initialized to 100), not an address, so an error occurs. If the programmer is reckless in writing the memory pointed to by this address, it may damage the system program and cause the operating system to crash!

Here is an important concept. CAddition * is a subclass pointer. Its variable padd can call the subclass method, but it points to the parent class object, that is to say, padd points to the memory space where it stores the member variables of the parent class. In depth, there is no "type" in the memory. For example, 0x3F may be a random type, an integer, or an address. The variable type we define is actually a way to define what data should be "viewed.

Therefore, the padd class pointer essentially defines the value method. For example, padd-> x is the value (4 bytes in total) of units 0 to 3 in the memory space ), concatenate it into 32 bits and use it as a pointer. padd-> y extracts Unit 4 from the memory space to Unit 7 (4 bytes in total ), it is spelled into 32 bits and treated as an int variable. But in fact, padd points to the parent class object, that is, the first four bytes are float variables, and the last four bytes are also float variables.

From this point, we can see that this kind of conversion by programmers makes the compiler "understand" wrong and regards Niu as a horse. As you can see from the above, the C-style conversion is actually insecure, and the compiler cannot see the unsafe conversion.

Up-casting and down-casting)

When you see this, the reader may ask, which conversions are not secure? According to the previous example, we can see that the security of data comes from two aspects: one is the narrow type conversion, which will lead to the loss of data digits; the other is in the class inheritance chain, forcibly convert the address (pointer) of the parent class object to the address (pointer) of the Child class. This is the so-called downlink conversion. "Bottom" indicates that the inheritance chain goes down (to the subclass direction ).

Similarly, the "up" of the upstream conversion means to go up along the inheritance chain (to the parent class ).

We conclude that the uplink conversion is generally safe, and the downlink conversion is probably insecure.

Why? Because the subclass contains the parent class, the uplink conversion (only the method of the parent class can be called to reference the member variables of the parent class) is generally safe. However, the parent class does not have any information about the subclass. the downlink conversion calls the subclass method and references the member variables of the subclass. None of these parent classes exist, therefore, it is easy to refer to the deer as a horse or point to a memory space that does not exist.

It is worth noting that unsafe conversions may not necessarily lead to program errors. For example, some narrow conversions are frequently used in many occasions, provided that the programmer is careful enough to prevent data overflow; the key to downlink conversion is what its "nature" is. For example, if a parent class Pointer Points to a subclass and then converts the parent class pointer to a subclass pointer, this type of downlink conversion will not be problematic.

For Class pointers, C ++ has designed more detailed conversion methods, including:

static_cast <new_type> (expression)dynamic_cast <new_type> (expression)reinterpret_cast <new_type> (expression)const_cast <new_type> (expression)

This improves the conversion security.

Static_cast <new_type> (expression) static conversion

Static conversion is the most similar to C-style conversion. Many times, programmers need to determine whether the conversion is safe. For example:

double d=3.14159265;int i = static_cast<int>(d);

However, static_cast has security considerations, such as conversions between irrelevant class pointers. See the following example:

// class type-casting#include <iostream>using namespace std;class CDummy {    float i,j;};class CAddition {    int x,y;  public:    CAddition (int a, int b) { x=a; y=b; }    int result() { return x+y;}};int main () {  CDummy d;  CAddition * padd;  padd = (CAddition*) &d;  cout << padd->result();  return 0;}

This example is similar to the previous example, but CAddition has nothing to do with the CDummy class, but the C-style conversion in main () is still allowed by padd = (CAddition *) & d, such a conversion is not secure.

If static_cast is used in main (), like this:

int main () {   CDummy d;   CAddition * padd;   padd = static_cast<CAddition*> (&d);   cout << padd->result();   return 0;}

The compiler can see that the non-related class pointer conversion is not safe and reports an error as shown in:

Note that it is not given in the form of warning, but cannot be compiled directly by error. As you can see from the prompt, the compiler says that if this type of forced conversion is required, you need to use reinterpret_cast (which will be said later) or C-style conversion.

To sum up, static_cast is closest to C-style conversion, But it improves the security of class pointer conversion between irrelevant classes.

Dynamic_cast <new_type> (expression) dynamic conversion

Dynamic conversion ensures that the class pointer conversion is suitable and complete. It has two important constraints: new_type is required to be a pointer or reference, the second is that the base class is polymorphism (the base class contains at least one virtual function ).

Let's take a look at the following example:

#include <iostream>using namespace std;class CBase { };class CDerived: public CBase { };int main(){CBase b; CBase* pb;CDerived d; CDerived* pd;pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-basepd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived }

If there is a problem with the last line of code, the error message provided by the compiler is shown in:

Change the class definition:

class CBase { virtual void dummy() {} };class CDerived: public CBase {};

Compile again, as shown in the result:

Compilation is successful. Here we add two sentences at the end of the main function:

cout << pb << endl;cout << pd << endl;

Output pointer values of pb and pd:

We can see a strange phenomenon. The pointer that converts the parent class to a subclass through dynamic_cast is actually a null pointer! This is exactly the security enhancement function of dynamic_cast. dynamic_cast can identify unsafe downstream conversions, but does not throw an exception. Instead, it sets the Conversion Result to null (null pointer ).

Another example:

#include <iostream>#include <exception>using namespace std;class CBase { virtual void dummy() {} };class CDerived: public CBase { int a; };int main () {  try {    CBase * pba = new CDerived;    CBase * pbb = new CBase;    CDerived * pd;    pd = dynamic_cast<CDerived*>(pba);    if (pd==0) cout << "Null pointer on first type-cast" << endl;    pd = dynamic_cast<CDerived*>(pbb);    if (pd==0) cout << "Null pointer on second type-cast" << endl;  } catch (exception& e) {cout << "Exception: " << e.what();}  return 0;}

The output result is: Null pointer on second type-cast.

Both dynamic_cast are downstream conversions. The first conversion is secure, because the object is essentially a subclass. The Conversion Result directs the subclass pointer to the subclass, which is justified by nature. The second conversion is insecure, because the object is essentially a parent class, it is possible to point to a space that does not exist!

In addition, when the pointer to be converted is void * or the target pointer to be converted is void *, dynamic_cast always considers it safe. For example:

#include <iostream>using namespace std;class A {virtual void f(){}};class B {virtual void f(){}};int main() {    A* pa = new A;    B* pb = new B;    void* pv = dynamic_cast<void*>(pa);    cout << pv << endl;    // pv now points to an object of type A    pv = dynamic_cast<void*>(pb);    cout << pv << endl;    // pv now points to an object of type B}

The running result is as follows:

It can be seen that dynamic_cast thinks that the NULL pointer conversion is safe. However, classes A and B must be polymorphism and contain virtual functions. If not, an error will be reported during compilation.

Reinterpret_cast <new_type> (expression) re-interpretation and conversion

This conversion is the most "insecure". The conversion between two class pointers without any relationship can be implemented using this conversion. For example:

class A {};class B {};A * a = new A;B * b = reinterpret_cast<B*>(a);//correct!

What's more, reinterpret_cast can convert an integer to an address (pointer). This type of conversion is performed at the underlying system level, with strong platform dependence and poor portability.

It also requires new_type to be a pointer or reference. The following example cannot be compiled:

double a=2000.3;short b;b = reinterpret_cast<short> (a); //compile error! 
Const_cast <new_type> (expression) constant converts to a non-Constant

This conversion is easy to understand and can be converted to a constant.

// const_cast#include <iostream>using namespace std;void print (char * str){  cout << str << endl;}int main () {  const char * c = "sample text";  char *cc = const_cast<char *> (c) ;  Print(cc);  return 0;}

SlaveChar * cc = const_cast <char *> (c)We can see the role of this conversion, but remember that this conversion does not convert the original constant itself, that isCOr a constant, but it returns the resultCcNon-Constant.

Summary

(1) CStyle ConversionIt is a "omnipotent conversion", but programmers need to grasp the conversionSecurityThe compiler is powerless;

(2) static_castClosestCStyle ConversionBut when the irrelevant class pointer is converted, the compiler reports an error, improving the security;

(3) dynamic_castRequirementsConversion TypeRequiredPointer or referenceAndDownstream ConversionTime requirementThe base class is polymorphism.If you find that the downstream conversion is not safe,Dynamic_castReturnsNullPointer,Dynamic_castAlways thinkVoid *The conversion between them is safe;

(4) reinterpret_castYou canUnrelated class pointerConverts an integer value to a pointer. This type of conversion is underlying and has strong platform dependence,Poor portability;

(5) const_castYou can setConstantConvertExtraordinaryBut will not destroy the original constantConstAttribute, only returnsRemoveConstVariable.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.