GURU Of The WEEK Terms 17: Transformation

zhaozj2021-02-08  316

Gotw # 17 CASTS

Author: Herb Sutter

Translation: k] [N g of @ rkTM

[Declaration]: This article takes the Guru of The Week column on www.gotw.ca website, and its copyright belongs to the original person. Translator Kingofark translated this article without the consent of the original person. This translation is only for self-study and reference, please read this article, do not reprint, spread this translation; people download this translation content, please delete its backup immediately after reading. Translator Kingofark is not responsible for people who violate the above two principles. This declaration.

Revision 1.0

GURU Of The WEEK Terms 17: Transformation

Difficulty: 6/10

(How much is your transformation of C ? Appropriate use of it can greatly improve the reliability of code.)

[problem]

Standard C new-style transformation has more powerful features and security compared to old-style C transformations. How much do you know about it? The following classes and global variables are used in this clause:

Class a {/*...*/};

Class B: Virtual a {/*...*/};

Struct C: a {/*...*/};

Struct D: b, c {/*...*/};

A A1; B1; C C1; D D1;

Const a a2;

Const a & ra1 = a1;

Const A & Ra2 = A2;

Char C;

1. Which new style of the following style cannot be corresponding to the transformation in C?

Const_cast

Dynamic_cast

Reinterpret_cast

STATIC_CAST

2. For the transformation statement in each of the following, the corresponding new style transition statement is written. From which statement is not correct if it is not written in a new style?

Void f () {

A * pa; b * pb; c * pc;

PA = (a *) & ra1;

PA = (a *) & a2;

PB = (b *) & c1;

PC = (C *) & D1;

}

3. Judgment the writing style and correctness of each C transformation statement.

Void g () {

Unsigned char * puc = static_cast (& c);

Signed char * psc = static_cast (& c);

Void * pv = static_cast (& b1);

B * PB1 = static_cast (pv);

B * PB2 = static_cast (& b1);

A * PA1 = const_cast (& ra1);

A * PA2 = const_cast (& ra2);

B * PB3 = Dynamic_Cast (& C1);

A * PA3 = Dynamic_Cast (& b1);

B * PB4 = static_cast (& d1);

D * pd = static_cast (pb4);

PA1 = Dynamic_Cast (PB2);

PA1 = Dynamic_Cast (PB4); C * PC1 = DYNAMIC_CAST (PB4);

C & RC1 = DYNAMIC_CAST (* PB2);

}

[answer]

1. Which new style of the following style cannot be corresponding to the transformation in C?

Only Dynamic_CAST cannot correspond to the transformation of C. Other new style transformations can correspond to the old style transition in C.

2. For the transformation statement in each of the following, the corresponding new style transition statement is written. From which statement is not correct if it is not written in a new style?

Void f () {

A * pa; b * pb; c * pc;

PA = (a *) & ra1;

You should use const_cast: const_cast (& ra1);

PA = (a *) & a2;

This sentence cannot be expressed in a new style. The closest solution is to use const_cast, but A2 is a const object, the result of the statement execution is undefined.

PB = (b *) & c1;

You should use ReinterPret_cast: PB = Reinterpret_cast (& C1);

PC = (C *) & D1;

}

This transformation is wrong in C. In C , there is no need to transform: PC = & D1;

3. Judgment the writing style and correctness of each C transformation statement.

First of all, we must pay attention to: We don't know if the classes given in this Territor have virtual functions; if those classes involving transformation do not have virtual functions, then all the use of Dynamic_Cast is wrong. In the following discussion, we assume that all classes have virtual functions, so that all Dynamic_cast usage is legal.

Void g () {

Unsigned char * puc = static_cast (& c);

Signed char * psc = static_cast (& c);

Error: We must use ReinterPret_cast to both statements. This start may make you feel surprised; this is the reason for char, souded char, and unsigned char, which are different from each other, distinguish. Although there is an implicit conversion between them, they are also associated with each other, thus pointing to their pointers are also interconnected.

Void * pv = static_cast (& b1);

B * PB1 = static_cast (pv);

These two sentences are good, but the transformation in the first sentence is unnecessary, because there is an implicit transformation action from an object pointer to Void *.

B * PB2 = static_cast (& b1);

This sentence is good, but its transformation is also unnecessary because its quotes are already a B *.

A * PA1 = const_cast (& ra1);

This sentence is legal, but use transformation to remove Const-Ness (constant) is an embodiment of potential poor style. In most cases, this is involved in certain class members when you want to remove the pointer or reference const-NESS (constant) because of reasonable temperament, and usually use the Mutable keyword to complete. Please see GotW # 6 Learn more about Const-Correctness discussions. A * PA2 = const_cast (& ra2);

Error: If the pointer is used to write to the object, it will generate undefined behavior; because A2 is a const object. To understand the reasons, you can try it to understand that "A2 is created as a compile" "A2 is CONST OBJECT", and it will store it in read-only storage area for optimization, what happens. Obviously, it is dangerous to remove such an object through the transformation.

Note: I don't have an example showing how to use const_cast to transform a Non-Const pointer into a const pointer. Because this is more, it will assign a Non-Const pointer to a const pointer, which is legal. We only need to use Const_cast to do the opposite operation.

B * PB3 = Dynamic_Cast (& C1);

Error (when you try to use PB3): This sentence will set PB3 to null because C1 is not a (IS-NOT-A) B (because C is not derived from B in public, and actually presses rooted Not derived from B). The only legally available transformation here is ReinterPret_cast, but it is almost always very embarrassed using it.

A * PA3 = Dynamic_Cast (& b1);

Error: This sentence is illegal because B1 is not a (IS-NOT-A) a (because B is not derived from A, but in a private method).

B * PB4 = static_cast (& d1);

This sentence is good, but there is no need to do transformation, because DeriveD-to-base (by derived class to base class) can be implicitly completed.

D * pd = static_cast (pb4);

This sentence is good. If you just think that it is dynamic_cast, this may be surprised. The reason is that when the goal is known, the downcast can be static. At this time, you should pay attention to: You are waiting to tell the compiler, you know "It is the type of pointer" "This fact. If you are wrong, then this transformation will not know what you have already appeared (Dynamic_cast can return a null pointer when the transition fails to tell you the problem), so you can only get a variety of different operations at this time. The error and / or the program crashes.

PA1 = Dynamic_Cast (PB2);

PA1 = Dynamic_Cast (PB4);

These two sentences look very similar. Two sentences have tried to convert B * to a * using Dynamic_cast. However, the first is wrong and the second is correct.

The reason is: As mentioned earlier, you cannot use Dynamic_CAST to convert a pointer pointing to the B object (here the PB2 pointing object B1) into a pointer to the A object, because b is inherited from A in a private manner, not in public mode . However, the transformation in the second sentence is successful because the PB4 points to the object D1, and D (via c) will act as an indirect PUBLIC BASE Class, so that Dynamic_CAST can be along b * -> d * - > C * -> A * The path is transformed in the inheritance hierarchy. C * pc1 = Dynamic_cast (PB4);

This sentence is also good, why is the same as above: Dynamic_cast can cross the inheritance level (Cross-Cast), so this sentence is legal and can be executed successfully.

C & RC1 = DYNAMIC_CAST (* PB2);

Finally, this sentence is wrong ... Because * PB2 is not really a C, Dynamic_cast will throw a Bad_cast exception to report failed. why? Because Dynamic_cast can return null when the pointer transformation fails, but because there is no Null Reference, it is not possible to return Null Reference when a reference transformation fails. In addition to throw an exception, there is no other way to report the error - the standard BAD_CAST exception class is therefore.

(Finish)


New Post(0)