Four types of conversion _c languages in C + +

Source: Internet
Author: User
Tags inheritance

1 Primer

This note is based on an issue stackoverflow above, with an illustration of four types of conversion operations in C/s + +. They were all understood before, and they were deeply understood as they were summing up and knocking out some test sample code for verification.

It is well known that there are four new types of conversion operators introduced into C + +: static_cast, dynamic_cast, reinterpret_cast, and const_cast. In some of the C + + code that you've seen, they're not generally used. Many programmers are still happy to use the C-like type conversion because it is powerful and simple to write. It is said that the role of the C-like type conversion operator has actually included the static_cast, Const_cast and reinterpret_cast three operators, do you believe it? Look at it together.

Note: The C-like type conversion operation mentioned above is like two forms, which we must all be familiar with.

(new-type) expression
new-type (expression)

2 static_cast vs dynamic_cast

The reason why we put static_cast and dynamic_cast brothers together is that they are easier to remember when compared to each other. First of all, from the name above they have a semantic relative relationship, a "static" a "move." In addition, the features of this comparison are reflected to a certain extent on the function, such as Dynamic_cast's run-time checkingt,static_cast to increase the type detection at compile time. In simple terms:

STATIC_CAST:1) Complete the underlying data type, 2 conversion of types in the same inheritance system
dynamic_cast: Using polymorphic scenes, adding a layer of checks to the type of the real call object

2.1 From C-like to static_cast

Static_cast for the underlying type such as int, float, char, and the underlying type corresponding to the pointer processing is much the same as c-like conversion, but static_cast will be more secure.

char C = ten;      1 byte
int *p = (int *) &c;  4 bytes (32bit platform)

*p = 5;        Memory on dirty
int *q = Static_cast<int *> (&c);//use static_cast to check the error at compile time.


For custom type processing, it also has a layer of protection over c-like, which means that it does not support conversions between types that do not belong to the same inheritance system. But C-like can do it, look at the following example:

#include <iostream>

Class A
{public
:
 A () {}
 ~a () {}
 
private:
 int i, J;
};

Class C
{public
:
 C () {}
 ~c () {}

 void Printc ()
 {
  std::cout << ' Call PRINTC () In class C "<<std::endl;
 }
" Private:
 Char C1, C2;

int main ()
{ 
 a *ptra = new A;
 C *ptrc = static_cast<c *> (ptrA);
 Compilation cannot pass, prompt:
 //In function ' int main () ':
 //Error:invalid static_cast from type ' * ' to type ' c* '
 
 C *ptr c = (c *) (PtrA);
 PTRC->PRINTC ();
 compiles normally through.
 //Although this time the normal call to PRINTC, but in fact the result of this practice is "undefined"
 //tried, if the addition of some data members of the operation, this time will make the results of the operation can not predict
 //So, The logic-related behavior at runtime is not clear. return
 
 0;
} 

2.2 Static_cast Conversions to custom types

This small example compares the differences between the static_cast and the c-like in terms of the classes of different inheritance systems, and now narrows the scope down to the type conversions in the same inheritance system. (Note: The type is generally referred to as a pointer to a class or a reference to a class.)

Static_cast the conversion between classes of the same inheritance system, it can be either upcast or downcast. Generally speaking, in the upcast is not a problem, after all, the subclass must contain a parent class related operations set, so through the conversion of the pointer or reference to manipulate the corresponding object, its behavior is to ensure that no problem. This is the same as using static_cast with c-like or a direct implicit conversion effect (of course, the results are consistent with the programmer's own expectations and the design at the time).

It should be noted that using static_cast for downcast should be avoided because it can escape the compiler's discernment, but at run time there will be an undefined problem:

#include <iostream> class A {public:a (): I (1), J (1) {} ~a () {} void PrintA () {std::cout << "call Prin"
 TA () in class A "<<std::endl;
 } void Printsum () {std::cout << "sum =" <<i+j <<std::endl;
Private:int I, J;

}; Class B:public a {public:b (): A (2), B (2) {} ~b () {} void Printb () {std::cout << "call PRINTB () in class B"
 <<std::endl;
 } void Printsum () {std::cout << "sum =" <<a+b <<std::endl;
  } void Add () {a++;
 b++;
Private:double A, B;

};
 int main () {b *PTRB = new B;
 Ptrb->printsum ();  
 Print Result: Sum = 4 A *ptra = static_cast<b *> (PTRB);
 Ptra->printa ();
 Ptra->printsum ();
 
 
 Print Result: Sum = 2//When the upcast is made, the behavior of the object to which the pointer points is related to the type of the pointer.
 PtrA = new A;
 Ptra->printsum ();
 Print Result: Sum = 2 PTRB = static_cast<b *> (PtrA);
 PTRB-&GT;PRINTB (); 
 Ptrb->printsum ();
 
 Print Result: Sum = 0//When downcast is performed, the behavior is "undefined".
 b b;
 b &AMP;RB = b; Rb.priNtsum ();  
 Printed result: Sum = 4//a &ra = Static_cast<a &> (RB);
 Ra.printa ();
 Ra.printsum ();
 
 Print Result: Sum = 2//When the upcast is made, the behavior of the object to which the reference refers is related to the type of the reference.
 A A;
 a &ra = A;
 Ra.printsum ();  
 Printed result: Sum = 4//b &AMP;RB = static_cast<b &> (RA);
 RB.PRINTB ();
 Rb.printsum ();
 
 Print Result: Sum = 5.18629e-317//When downcast is performed, the behavior is "undefined".
return 0;

 }

As above, the performance of the static_cast in downcast between classes of the same inheritance system, as in the case of conversions between classes belonging to different inheritance systems, will be undefined. Therefore, you should use static_cast to perform downcast conversions whenever possible, and, more accurately, avoid downcast conversions of pointers or references to the classes of the integration system as much as possible.

In this case, that is not in the software development process will not exist downcast this situation? Actually, it's not. Generally speaking, when the downcast is usually in the virtual inheritance of the scene, this time dynamic_cast on the field.

2.3 dynamic_cast

The use of dynamic_cast is mainly in the downcast scenario, and it needs to meet two conditions:

There is a "virtual inheritance" relationship between classes converted at downcast
The type after the conversion corresponds to the actual type to which it is pointing
Dynamic_cast is the same for upcast and static_cast, but because dynamic_cast relies on rtti, it is slightly lower on performance than static_cast.

#include <iostream> #include <exception> class A {public:virtual void print () {std::cout << "We
 Lcome to worlda! "<<std::endl;

}
};  Class B:public a {public:b (): A (0), B (0) {} ~b () {} virtual void print () {std::cout << "Welcome to worldb!"
 <<std::endl;
Private:double A, B;

};
 int main () {b *PTRB = new B;
 A *ptra = Dynamic_cast<a *> (PTRB);
 Ptra->print ();
  
 In virtual inheritance, the effect of a dynamic_cast conversion on a pointer executing upcast is the same as the static_cast//to the existence of a virtual without requiring that the member of the object being directed will actually be called.
 A *ptra = new A;
 B *PTRB = dynamic_cast<b *> (PtrA);
 Ptrb->print ();
 
 Segmentation fault, the conversion was unsuccessful when performing downcast on the pointer, returning NULL.
 A A;
 a &ra = A;
 B &b = dynamic_cast<b &> (RA);  
 B.print ();
 
 Throws an St8bad_cast exception, the conversion is unsuccessful, and an exception is thrown when performing downcast on the reference.
 PtrA = new A;
 PTRB = Static_cast<b *> (PtrA);
 Ptrb->print ();
  
 When using static_cast for downcast, it is different from the dynamic_cast return NULL,//This will invoke the virtual function of the object that PTRB actually points to.
 PtrA = new A; PTRB = dynamic_cast<B *> (PtrA);
 Ptrb->print ();  If there are no virtual members in the downcast, the compile-time prompts://in function ' int main () '://Cannot dynamic_cast ' PtrA ' (of type ' class * ')
To type ' class b* ' (source type isn't polymorphic) return 0;

 }

As can be seen from this example, in the virtual inheritance scenario, where the dynamic_cast can be used can be used static_cast, but dynamic_cast has more stringent requirements to help programmers write more rigorous code. It's just that there's a bit more overhead on performance.

3 reinterpret_cast

Reinterpret_cast is the most dangerous kind of cast, it is the most dangerous, because its performance and c-like generally strong, a little attention will appear errors. It is generally used in a number of low-level conversions or bitwise operations.

 #include <iostream> class A {public:a () {} ~a () {} void print () {Std::cout
 << "Hello world!" <<std::endl;

}
}; Class B {public:b (): A (0), B (0) {} ~b () {} void Call () {std::cout << ' Happy for your call! ' <<std::endl
 ;
Private:double A, B;

};
 int main () {//a *ptra = new A;
 B *PTRB = reinterpret_cast<b *> (PtrA);
 Ptrb->call ();
 Normal compilation//a *ptra = new A;
 b *PTRB = (b *) (PtrA);
 Ptrb->call (); 
 Normal compilation//a *ptra = new A;
 B *PTRB = static_cast<b *> (PtrA);
 Ptrb->call ();
 Compile does not pass, prompt://in function ' int main () '://error:invalid static_cast from type ' * ' to type ' b* '//char C;
 Char *pc = &c;
 int *pint = Static_cast<int *> (PC);
 Compile-prompt error: Error:invalid static_cast from type ' char* ' to type ' int* '//int *pint = Reinterpret_cast<int *> (PC);
 Normal compilation.
 int *pint = (int *) (PC);
 
 Normal compilation.
return 0; }

After analyzing the static_cast,dynamic_cast and reinterpret_cast, we can draw the following diagram to compare the differences between them. The const_cast is not included because it is special, and it is introduced in a separate section.

     ----------------
     /  dynamic_cast \--> class pointers to the same inheritance system (virtual) or references [more secure downcast]
    ~~~~~~~~~~~~~~~~~~~~  
    /   static_cast  \--> base type [more secure], class pointers for the same inheritance system or references
   ~~~~~~~~~~~~~~~~~~~~~~~~
   /  reinterpret_ Cast  \--> is consistent with c-like, without any static or dynamic checking mechanism
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  /     c-like      \--> base type, the same inheritance system class pointer or reference, different inheritance system class pointers or references
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

4 const_cast

Const_cast can be used to remove or add a variable to the const attribute, initially I think this const_cast is more strange, C has been no similar thing to eliminate the const attribute, here will be redundant? In fact, I have no basis for such an idea. Then think about, in C + + has been advocated to declare constants as const, so once the constant amount of time, in conjunction with other software components or third-party libraries to meet the need to cast the const properties of the problem. Like what:

const int myconst =;
int *nonconst = Const_cast<int *> (&myconst);

void print (int *p)
{
  std::cout << *p;
}

Print (&myconst); Compilation error: Error:invalid conversion from ' const int* ' to ' int* '
print (nonconst);//Normal

However, when using const_cast, it should be noted that if there is no need to try not to modify its value:

const int myconst =;
int *nonconst = Const_cast<int *> (&myconst);

*nonconst = ten;
If the variable is stored in the Read-only memory area, an error may occur at run time.

5 Summary

In C + + for most data types, the use of C-like type conversion is fully enough. However, many people have been advocating for explicit data type conversion when possible to use C + + specified type conversion operations. I think there are probably two reasons for this:

First of all, C + + is a "new" programming language, should learn to use its own ideas to solve programming problems;
The second, although the C-like conversion operation is powerful, but if it is used arbitrarily, will produce a lot of hidden during the compilation, but in the runtime shadowy. These problems make the behavior of the software extremely unclear.
In this way, C + + leads to four other types of conversions to make it more secure to perform type conversion operations on some occasions. Using reinterpret_cast, for example, will indicate that you are sure you want to use C-like type conversions, and that when you use static_cast you want to make sure that the converted objects are basically compatible, such as not converting char * to int *, You cannot convert between pointers or references to different inheritance system classes, while using dynamic_cast is a downcast conversion to classes under virtual inheritance, and it is clear that current performance is not a major factor ...

Answer the question mentioned earlier. It can be said that C-like can do all the transformations that const_cast, static_cast, reinterpret_cast and dynamic_cast can accomplish. However, c-like conversions do not have static_cast, dynamic_cast compile-time type detection and run-time type detection provided respectively.

Bjarne Stroustrup, the father of C + +, also talks about his views here, with two main points: first, c-like cast is extremely destructive and rarely takes much effort to search the code text; The new cast allows programmers to use them more purposeful and allow the compiler to discover more errors, and thirdly, the newer cast conforms to the template declaration specification, allowing programmers to write their own cast.

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.