Effective C ++ 2e Item26

zhaozj2021-02-11  228

Terms 26: Beware

Everyone has ideas. Some people believe in freedom economics, some people believe in life. Some people even believe that COBOL is a real programming language. C also has an idea: it thinks that potential amphibration is not a mistake.

This is an example of potentially unsatisfied:

Class B; // Pre-declare // Class A {public: A (const b "); // can be constructed from B;

Class B {public: operator a () const; // can be converted from A. Class B};

These categories have nothing wrong - they can share without a problem in the same program. However, look at the following, use the two classes to use, actually passing a B object in a function of an input parameter A, what will happen?

Void F (Const A &);

B B;

f (b); // error! - 二 meaning

When I see the call to F, the compiler knows that it must generate a type A object, even if it is holding a type B object. There are two well-known methods to achieve (see clause M5). One method is to call the constructor of class A, which constructs a new A object with B parameter. Another method is to call a self-defined conversion operator in class B, which converts B to an object of a A. Because these two ways are as possible, the compiler refuses to select one from them.

Of course, the program can be used without inciting the second sense. This is the latent harm of potential second sense. It can lurking in the program for a long time, not being discounted; once a uninformed programmer has really done an unintended operation, it will break out. This leads to such a worryable possibility: You post a library, it can be called in the case of second, but you don't know what you are doing.

Another similar form of secondary originates from the standard conversion of C languages ​​- not even involve class:

Void f (int); void f (char);

Double D = 6.02;

f (d); // error! - secondary

D is this converted into int or a char? Both conversions are feasible, so the compiler simply does not practice. Fortunately, you can solve this problem by explicit type conversion:

f (static_cast (d)); / / correct, call f (int) f (static_cast (d)); / / correct, call f (char)

Multi-inheritance (see Terms 43) is full of potential erliness. One of the most frequently occurring is that when a derived class has inherited the same member name from multiple base classes:

Class Base1 {public: int DOIT ();};

Class Derived: public base1, // derived no declaration public base2 {// a function called DOIT ...

}

Derived D;

D. DOIT (); // Error! - 二 义

When class Derive is inherited two functions with the same name, C did not think it was wrong, and the second sense is only potential. However, for the call for DOIT forces the compiler to face this reality unless explicitly through the base class required by indicating the function, the function call will be wrong:

D.Base1 :: DOIT (); // correct, call Base1 :: DOIT

D.Base2 :: DOIT (); // Correct, call Base2 :: DOIT

This will not make many people feel trouble, but when I see the above code is not used to access, some people who have been very stunning will move their minds:

Class Base1 {...}; //

Class Base2 {private: void Doot (); // This function is now private};

Class Derived: Public Base1, Public Base2 {...}; //

Derived D;

INT i = D.DOIT (); // Error! - or secondary!

The call to DOIT is still an unity, even if only the function in Base1 can be accessed. In addition, only Base1 :: DOIT returned values ​​can be used to initialize an int this fact that is not related to it - calling still has an amplitude. If you want to call successfully, you must indicate which type of DOIT you want is.

Some of C , it will find that it will feel very nice, this is this situation. Specifically, why do you eliminate the access rights when you residual? There is a very good reason, it can be concatenated: Changing access to a class member should not change the meaning of the program.

For example, the previous example, suppose it takes into account access. So the expression D. DOIT () decided to call Base1 :: DOIT, because Base2 version cannot be accessed. Now suppose Base1's DOIT version is changed from PUBLIC to protected, the version of Base2 is changed from Private to public.

Between transsthesia, the same expression D. DOIT () will cause another completely different function call, even if the calling code and the modified function itself are not modified! This is not intuitive, the compiler can't even produce a warning. It can be seen that it is reasonable to explicitly eliminate the secondary meaning as you think about what you think.

Since writing procedures and libraries, there are so many different situations that will generate potential errange, then how do a good software developer do? The most fundamentally, be careful when you want to be careful. I want to find out all the roots of all potentially unsatisfactory, especially when the programmer combines different independently developed libraries (see Terms 28), but understanding often generate potential erliness After those situations, you can minimize the possibilities of it in software design and development.

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

New Post(0)