The use of C + + type conversion characters

Source: Internet
Author: User

On the issue of coercion type conversion, many books have been discussed, the most detailed writing is the father of C + + "C + + Design and evolution." The best solution is not to use the C-style coercion type conversion, but instead use the standard C + + type conversion character: Static_cast, dynamic_cast. There are four type conversions in standard C + +: static_cast, dynamic_cast, reinterpret_cast, and const_cast. Each of them is described below.

I.static_cast

Usage: static_cast <type-id > (expression)

The operator converts expression to the Type-id type, but does not have run-time type checking to guarantee the security of the conversion. It is mainly used in the following ways:

the transformation used for pointers or references between base and subclass classes in a class hierarchy.

It is safe to make an upstream conversion (a pointer or reference to a class is converted to a base class representation).

When a downstream conversion (a base class pointer or reference is converted to a subclass representation) is not secure because there is no dynamic type checking.

used for conversions between basic data types. convert int to char, convert int to enum. The security of this conversion is also to be ensured by the developer.

converts a null pointer to a null pointer of the target type.

Convert any type of expression into an void type.

Note: static_cast cannot convert the const, Volitale, or __unaligned properties of expression.

Ii.dynamic_cast

primarily used to perform " a safe downward transition ( Safe Down Casting ) " , that is, to determine whether an object is a specific type in an inheritance system.

Usage: dynamic_cast <type-id > (expression)

This operator converts expression to an object of type Type-id. Type-id must be a pointer to a class, a reference to a class, or void *; if Type-id is a class pointer type, expression must also be a pointer, and if Type-id is a reference, expression must also be a reference.

dynamic_cast It is primarily used for upstream and downstream conversions between class hierarchies, and can also be used for cross-conversion between classes.

The effect of dynamic_cast and static_cast is the same when upstream conversions are made between class hierarchies, and dynamic_cast has the function of type checking, which is more secure than static_cast when making a downstream conversion.

Class b{

Public

int m_inum;

virtual void foo ();

};

Class D:public b{

Public

Char *m_szname[100];

};

void func (B *pb) {

D *PD1 = Static_cast<d *> (pb);

D *PD2 = dynamic_cast<d*> (PB);

}

In the preceding code snippet, if PB points to an object of type D, PD1 and PD2 are the same, and any operation that performs type D on both pointers is safe, but if PB points to an object of type B, then PD1 will be a pointer to that object. It would be unsafe to do a type D operation (such as access to M_szname), and PD2 would be a null pointer. Also note: B to have virtual function, or compile error, static_cast There is no such limit. This is because runtime type checking requires run-time type information, and this information is stored in the virtual function table of the class (the concept of virtual function table, detailed <inside C + + object model>), only the class that defines the virtual function has a virtual function table, A class that does not have a virtual function defined is not a virtual function table.

In addition, thedynamic_cast supports cross-cast. as shown in the following code.

Class a{

Public

int m_inum;

virtual void F () {}

};

Class B:public a{

};

Class D:public a{

};

void Foo () {

b *PB = new B;

Pb->m_inum = 100;

D *PD1 = Static_cast<d *> (pb); Copile Error

D *pd2 = Dynamic_cast<d *> (pb); PD2 is NULL

Delete PB;

}

In function foo, a conversion using static_cast is not allowed and will fail at compile time, whereas a conversion using dynamic_cast is allowed with the result of a null pointer.

//////////////////////////////////////////////////////////////////////////////////////////////////////

Conversion upward, more secure, no longer an example.

Convert to void*

If Type-id is a void*, the run-time check determines the actual type of the expression. The result is a complete object to which expression points. For example:

Class A {...};

Class B {...};

void F ()

{

A * pa = new A;

b* PB = new B;

void* PV = dynamic_cast< void* > (PA);

PV points to an object of type a

...

PV = dynamic_cast<void*> (PB);

PV points to an object of type B

}

Down conversion

If Type-id is not void*, the runtime checks whether an object pointing to expression can be converted to an object that points to the Type-id type.

If the expression type is a base class for Type-id, the runtime checks whether expression is actually a Complete object that points to the Type-id type. If it is, the result returns a full object that points to the Type-id type, otherwise NULLis returned. For example:

Class B {...};

Class D:public B {...};

void F ()

{

b* PB = new D; Unclear but OK

b* PB2 = new B;

Determines whether the object pointed to by a base-class pointer is a specified subtype

d* PD = dynamic_cast< d* > (PB); OK:PB actually points to D and returns d*

d* pd2 = dynamic_cast< d* > (PB2); Pb2 actually points to B instead of D, the conversion fails, and PD2 is NULL.

}

In the case of multiple inheritance, it can lead to two semantics.

Take a look at the following class inheritance hierarchy:

A pointer to type D is normal to B or C, but what happens if you convert from D to a? This result results in a two semantic error of the conversion; In order to result in this problem, you can point to two explicit transformations, such as:

void F ()

{

d* PD = new D;

A * pa = dynamic_cast<a*> (PD); Error: Ambiguity

b* PB = dynamic_cast<b*> (PD); First switch to B

A * PA2 = dynamic_cast<a*> (PB); OK: clear.

}

The use of virtual base classes leads to more complex blurring; look at the following class-level diagram:

In this inheritance hierarchy, a is a virtual base class. Assuming an instance of Class E and a pointer to a sub-object, once to b the dynamic_cast will fail due to ambiguity, you must first convert to the appropriate level and then upward to the level of determination, until the correct B object is reached in this way.

Look at the following class-level diagram:

Assuming an object of type E and a pointer to a D child object, navigating from the D sub-object to the top-left a child object, you must perform three transformations. The conversion of dynamic_cast from D to E, then a conversion from E to B (which can be either dynamic_cast or implicit), and ultimately a conversion from B to a, for example:

void f (d* PD)

{

e* PE = dynamic_cast<e*> (PD);//The D here is actually an E-type Object

b* PB = PE; Upcast, implicit conversion

A * pa = PB; Upcast, implicit conversion

}

Cross Conversion

The dynamic_cast operation can perform a cross-conversion, using the same class hierarchy above, from the B-sub-object to the D-sub-object conversion is possible, as long as the complete object is E.

Because of the cross-conversion, pointers from the D pointer to the A sub-object in the upper-left corner are feasible, first the cross-conversion from D to B, and then the conversion implicitly from B to a. For example:

void f (d* PD)

{

b* PB = dynamic_cast<b*> (PD); Cross cast

A * pa = PB; Upcast, implicit conversion

}

A null pointer value is converted to a null pointer by dynamic_cast.

When using dynamic_cast <Type-id> (expression), If expression cannot be safely converted to Type-id, run-time checks cause a transformation failure, such as:

Class A {...};

Class B {...};

void F ()

{

A * pa = new A;

b* PB = dynamic_cast<b*> (PA);   fails, not safe; B not derived from A

...

}

The type of pointer that failed the conversion is a NULL pointer. A failed reference type cast throws a Bad_cast_exception exception, and if expression does not point to or reference a valid object, the __non_rtti_object exception is thrown.

Let's look at a cross-conversion example below:
struct b1{Virtual ~b1 () {}};

structb2{Virtual ~b2 () {}};

STRUCTD1:B1, b2{};

Intmain ()

{

D1 D;

b1* PB1 = &d;

b2* PB2 = dynamic_cast<b2*> (PB1);//l1

b2* pb22 = static_cast<b2*> (PB1); L2 failure

return 0;

}

As you can see in the above definition, B1 and B2 are unrelated classes, and from L1 you can see that dynamic_cast allows this conversion: as long as the B1 has a polymorphic method. L2 fails the compilation, static_cast does not allow two completely unrelated classes to convert to each other.

This characteristic of dynamic_cast is very useful when extracting an interface of an object, which is similar to the QueryInterface function of COM.

Dynamic_cast's Discussion:

Before exploring the design intent of dynamic_cast, It is worth noting that many dynamic_cast implementations are quite slow.

For example, there is at least one common implementation that is partially based on string comparisons of class names. If you execute dynamic_cast on an object in a four-layer, single-inheritance system, each dynamic_cast under such an implementation will have to pay the equivalent of four calls to strcmp to compare the cost of the class name. For a deeper or more inherited inheritance system, the cost will be more expensive.

The need for dynamic_cast usually occurs in this case: you want to perform the operation of a derived class on an object that you are sure is a derived class, but you can only manipulate the object by a pointer or reference to a base class.

There are two general ways to avoid this problem:

The first is to eliminate the need to manipulate the object through the base class interface by using a container that stores pointers directly to the derived class object. Of course, this method does not allow you to store pointers to the derived classes of all possible base classes in the same container. In order to work with different window types, you may need multiple types of security (Type-safe) containers.

A candidate method allows you to manipulate all possible Window derived classes through a base class interface, which is to provide a virtual function in the base class that lets you do what you want to do. For example, although only specialwindows can blink, declaring this function in a base class, and providing a default implementation that does nothing at all, might make sense:

So:

• Avoid the use of forced transformations, especially in performance-sensitive code, and if a design requires a forced transformation, try to develop a candidate with no forced transformation. dynamic_casts

• If you have to force a transition, try to hide it in a function. Customers can call that function instead of adding a forced transformation to their own code.

• Try to replace the forced transformation of the old style with a C + + style of forced transformation. They are more likely to be noticed, and the things they do are clearer.

Iii.reinpreter_cast

Usage:reinpreter_cast<type-id> (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 (a pointer is converted to an integer, the integer is converted to the original type of pointer, and the original pointer value can be obtained).

The operator uses more.

Iv.const_cast

Usage:const_cast<type_id> (expression)

The operator is used to modify the const or volatile properties of a type. In addition to const or volatile adornments, the type_id and expression types are the same.

The constant pointer is converted to a very pointer, and still points to the original object, the constant reference is converted to a very literal reference and still points to the original object, and the constant object is converted to a very mass object.

Voiatile and const class test. As an example:

Class b{

Public

int m_inum;

}

void Foo () {

Const B B1;

B1.m_inum = 100; Comile Error

B B2 = const_cast<b> (B1);

B2. M_inum = 200; Fine

}

The above code compiles with an error, because B1 is a constant object and cannot be changed, and using const_cast to convert it to a constant object, it can arbitrarily change its data members. Note: B1 and B2 are two different objects.

The use of C + + type conversion characters

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.