Effective C ++ 2e Item38

zhaozj2021-02-11  176

Terms 38: Never redefine the default parameter values ​​from inheritance

Let us simplify the problem from the beginning. The default parameters can only be existing as part of a function; in addition, only two functions can inherit: virtual functions and non-virtual functions. Therefore, the unique way to redefine the default parameter value is to redefine a successful function. However, the non-virtual function that is redefined inherited is an error (see Terms 37), so we can completely reduce the scope of the discussion to "inherit a virtual function with default parameter values".

In this case, the reason for this Terfection becomes very obvious: the virtual function is dynamic binding and the default parameter value is static binding.

What do you mean? You may say that you don't understand these latest object-oriented terminology; or, you can't think of static and dynamic binding differences at the moment. So let's review it.

The statically type of object refers to the type where you declare exists in the program code text. Look at the following class hierarchy:

ENUM Shapecolor {Red, Green, Blue};

// A class class shape {public: / / all shapes indicating geometric shapes To provide a function to draw their own Virtual Void Draw (ShapeColor Color = RED) const = 0;

...

}

Class Rectangle: Public Shape {public: // Note: Different default parameter values ​​- Well! Virtual Void Draw (ShapeColor Color = Green) Const;

...

}

Class Circle: Public Shape {public: Virtual Void Draw (Shapecolor Color) Const;

...

}

Use graph to represent it below:

Shape // / / / rectangle circle

Take a look at these pointers now:

Shape * ps; // Static type = shape *

Shape * pc = new circle; // Static type = shape *

Shape * pr = new rectangle; // Static type = shape *

In this example, PS, PC, and PR are declared as a Shape pointer type, so they all use this as their own static type. Note that this is absolutely no relationship with the type of objects whose really pointing ---- their static types are always shape *.

The dynamic type of the object is determined by the type of object it is currently referred to. That is, the dynamic type of the object indicates what kind of behavior it will do. In the above example, the dynamic type of the PC is the dynamic type of Circle * and PR is Rectangle *. As for PS, there is virtually no dynamic type because it (still) does not point to any object.

Dynamic type, as the name suggestions, can change at runtime, typical methods are assigning:

PS = PC; // PS dynamic type // is now Circle *

PS = Pr; // PS dynamic type // is now Rectangle *

The virtual function is dynamically binding. It means that the virtual function is called by which object is called. The specific function called by the object is determined by the dynamic type of the object: PC-> DRAW (red); // Call Circle :: DRAW RED)

PR-> DRAW (red); // Call Rectangle :: DRAW (RED)

I know that these are old-fashioned knowledge, you certainly understand the virtual function. (If you want to know how they implement, see Terms M24) However, combining the virtual function and the default parameter value will generate a problem, because, as described above, the virtual function is dynamically bound, but the default parameter It is static binding. This means that you will eventually call a virtual function defined in derived classes, but use the default parameter value in the base class:

PR-> DRAW (); // Call Rectangle :: Draw (Red)!

In this case, the dynamic type of the PR is Rectangle *, so the virtual function of Rectangle is called --- As we expect. In Rectangle :: DRAW, the default parameter value is Green. However, since the static type of the PR is Shape *, the parameter value called by this function is from the Shape class, not the Rectangle class! So the result will be very strange and unexpected, because this call contains a combination of Draw and Rectangle classes. You certainly don't want your own software to run in this way; at least, users don't want this, believe me.

Needless to say, both PS, PC, and PR are the facts of the pointer and the cause of the problem. If they are referenced, the problem will continue. The problem is just that the DRAW is a virtual function, and one of its default parameters is redefined in the subclass.

Why is C adhere to this violation of conventional practices? The answer and operation efficiency are related. If the default parameter value is dynamically binded, the compiler must find a way to determine the appropriate default value for the virtual function, which will be more slower than the current mechanism to determine the default value in the compilation phase now. Making this option is to improve the speed and implementation of the speed, so everyone can now feel the efficiency of the program running; of course, if it is ignored the recommendations of this Territor, it will bring confusion.

转载请注明原文地址:https://www.9cbs.com/read-4447.html

New Post(0)