Effective C ++ 2e Item1

zhaozj2021-02-11  203

Turn from C to C

For everyone, habits C take some time, which is especially distressed for programmers that have been familiar with C. Because C is a subset of C , all C technology can continue to use, but many use is not suitable. For example, the C programmer will think of the pointer of the pointer looks quirky, they will ask: Why don't you replace the reference to the pointer? C is a simple language. It truly provides only macro, pointers, structures, arrays, and functions. No matter what problem, C is resolved by macro, pointer, structure, array, and functions. And C is not the case. Macros, pointers, structures, arrays, and functions, there are certainly, there are also private and protected members, function overload, default parameters, constructors, and destructor, custom operator, inline function, reference, friend, Template, exception, name space, etc. With C , it has a broader space with C because more choices can be considered when designing. In the face of so many options, many C programmers are in order to hold a regulations and insist on their old habits. In general, this is not a big sin. But some C habits are contrary to the spiritual nature of C , and they are elaborated in the following terms.

Terms 1: Try to use const and inline without #define this terms are best known as: "Try to use compilers without pre-processes", because #define is often considered to be part of the language itself. This is one of the problems. Look at the following statement: #define aspect_ratio 1.653 compiler will never see the aspect_ratio of this symbol name, because before the source code enters the compiler, it will be removed by the preprocessor, so AsPect_Ratio does not join the symbol list. If the code involved in this constant is compiled, it will be aware of because the error information refers to 1.653 instead of aspect_ratio. If Aspect_Ratio is not defined in your own header file, you will be strange 1.653 where to come, even spend time tracking. This issue will also appear in the symbol debugger, because the same, the symbol name you wrote will not appear in the symbol list. Solution to this problem is simple: do not need to preprocess macro, define a constant: const double assect_ratio = 1.653; this method is effective. But there are two special circumstances to pay attention. First, it will be a bit different when defining a pointer constant. Because constant definitions are typically placed in the header file (many source files will contain it), in addition to the type referred to by the pointer to be defined as consts, the pointer is often defined as const. For example, to define a Char *-based string constant in the header file, you have to write twice const: const char * const authorname = "scott meyers"; About the meaning of Const, especially the problem associated with the pointer See Terms 21.

In addition, it is also very convenient to define a class (Class), only a little difference. To limit the constant to the class, you must first make it a member of the class; in order to ensure the maximum copy, you have to define it as a static member: class gameplayer {private: static const Int num_turns = 5; // constant Declaration int Scores [// use of constant ...}; there is a little, as you can see, the above statement is Num_Turns declaration, not the definition, so you must also implement the code file in the class Static members of the definition: const Int gameplayer :: num_turns; // mandatory definition; // goes in class impl. File You don't have to worry too much. If you forget the definition, the linker will remind you.

Older compilers do not accept this grammar because it thinks that the static member of the class defines the initial value when the declaration is illegal; and only the initial integer type (eg int, bool, char, etc.) is allowed within the class. Can only be constant. In the case where the above syntax cannot be used, you can define the initial value: Class EngineeringConstants {// this goes in the class private: //Header File

Static const Double fulge_factor;

...

}

// this Goes in the class importation file const double engineeringconstants :: fudge_factor = 1.35;

In most cases, you just do so much. The only exception is that when your class needs to use the constant of this class, for example, the declaration of the GamePlayer :: Scores array (during the compilation process must know the size of the array). Therefore, in order to make up for the insufficient compiler of the compiler in which the intersection of the intersection of the entire class is prohibited, it can be used to solve the method called "borrowing ENUM". This technology uses the principle of enumeration type when you need an int type, so GamePlayer can define this: Class GamePlayer {private: enum {num_turns = 5}; // "The enum hat" Makes // Num_Turns a Symbolic Name // for 5

Int scorers [num_turns]; // fine

...

}

Unless you are using the old compiler (ie, before 1995), you don't have to borrow ENUM. Of course, I know that this method is still worth it, because this code that can be traced back to the era of a long time is uncommon.

Go back to the topic of the pretreated. Another common #define directive usage is to use it to implement macros that look like a function and does not cause function calls. A typical example is to calculate the maximum value of two objects: #define max (a, b) ((a)> (b)? (A): (b)) This statement has a lot of defects, and the light is thinking about it. It is even more painful than driving the highway at the peak time. Whenever you write a macro like this, you have to remember that you have to add parentheses to each parameter when writing the body; otherwise, if you call your macro, if you use the expression, you will cause a lot of trouble. . But even if you are doing this, there will be a strange thing like this: int A = 5, b = 0; max ( a, b); // a value increased by 2 Max ( ) A, B 10); // a value only increases once

In this case, what happens inside the MAX depends on what is it compared! Fortunately, you don't have to endure such a stupid statement. You can use the normal function to achieve macro efficiency, plus the expected behavior and type security, this is the inline function (see clause 33): Inline int max (int A, int b) {RETURN A> B? A: B;} However, this is not large, because this version of MAX can only process int types. But the template can solve this problem very lightly: Template Inline Const T & Max (Const T & A, Const T & B) {RETURN A> B? A: B;}

This template has a complete set of functions, each function takes two objects that can be converted into the same type of objects and return a reference to a large (constant) object. Because I don't know the type of T, the transfer reference can increase efficiency (see clause 22).

By the way, check the standard library when you plan to write like Max, first check the standard library (see Terms 49), see if they already exist. For example, the Max saying above, you will surprise you can find a cold: max is part of the C standard library. With const and inline, you need to decrease the pretreatment, but you can't do it completely. Abandoning #include's days is still far away, # ifdef / # ifndef also plays an important role in the process of controlling compilation. Preprocessing can't retire, but you must plan to give it a long holiday.

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

New Post(0)