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.
script>
Terms 1: Try to use const and inline without #define
It is 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
The compiler will never see the symbol name of Aspect_Ratio because it will be removed by the pre-processing program before the source code enters the compiler, 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 aspect_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 pattern in the header file, you have to write twice:
Const char * const authorname = "scott meyers";
For the meaning of Const, in particular, the issues 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 constant to the class, you must first make it a member of the class; in order to ensure that there is only one copy, it will define it as a static member:
Class GamePlayer {
Private:
Static const Int num_turns = 5; // constant ecaration
int Scores [Num_Turns]; // Use of constant
...
}
There is another point, as you can see, the above statement is Num_Turns declaration, not the definition, so you must also define a static member of the class in the category implementation code file: 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 mailmentation 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 using enumerated types when you need int types, so GamePlayer can also be defined like this:
Class GamePlayer {
Private:
Enum {num_turns = 5} // "The Enum Hack" - 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 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 that people are distressed, 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 do this, there will be a strange thing like this:
INT A = 5, b = 0;
Max ( a, b); // a value increased by 2 times
MAX ( a, b 10); // a value only increases 1 time
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 a normal function to achieve macro efficiency, plus the expected behavior and type security, which is the inline function (see Terms 33):
Inline int Max (int A, int b) {RETURN A> B? A: B;}
However, this is not large as the above macro, because this version of MAX can only handle the int type. 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.
script>
Terms 2: Try to use
Yes, Scanf and Printf are very light, very efficient, you have long known how to use them, this I admit. But although they are useful, in fact, Scanf and Printf and their series can also do some improvements. In particular, they are not type safe and there is no scalability. Because type security and scalability are the cornerstone of C , you have to obey this. In addition, the Scanf / Printf series function separates the variables to be read and the information on the information on the read / write format, just like ancient Fortran. It is time to say to the fifth year!
Don't be surprised, these weaknesses of Scanf / Printf are operators >> and <<
INT I;
Rational R; // r is a constant number
...
CIN >> I >> R;
Cout << i << r;
The above code must be compiled, >> and << must be a heavy-duty function that can handle the Rational type object (may be converted by implicit type). If such a function is not implemented, it will be wrong (handling Int does not do this because it is a standard usage). In addition, the compiler can select different forms of operators according to different variable types, so it is not necessary to deserve that the first object to be read is Int, and the second is Rational.
In addition, the grammar form is the same as the syntax form used when reading and writing objects, so it is not necessary to remember some of the SCANF, for example, if the pointer is not obtained, addicts, and if the pointer has been, it is necessary to add it. Address. These can be handed over to the C compiler. There is nothing else to do anything else, but you are different. Finally, it is important to note that the custom type like INT and the custom type of Rational Rational is the same. And you will try it with SACNF and Printf!
The code you have written to indicate the number of categories that may be like this:
Class russ {
PUBLIC:
Rational (int name = 0, int devenoman = 1);
...
Private:
INT N, D; / / molecule, branch
Friend Ostream & Operator << (Ostream & S, Const Rational &);
Ostream & Operator << (Ostream & S, Const Rational & R)
{
s << r.N << '/' << r.d;
Return S;
}
The above code involves some subtle (but very important) usage of Operator <<, which is discussed in detail in this book. For example: The above Operator << is not a member function (Terms 19 explains why), and it is not a reference to operator <<, but is not a reference to the object of Const (see Terms 22). The statement and implementation of Operator >> are similar.
Although I am not willing to admit it, it is still very meaningful to return to those who have proved and correct old roads. First, some iostream's operations are achieved less than the corresponding C stream efficiency, so different options will give you the program (although not necessarily, see the Terms M16) brings a lot. But please keep in mind that this is not for all Iostream, just some special implementation; see Terms M23. Second, in the standardization process, the iostream library has made a lot of modifications in the underlying (see Terms 49), so for those applications that require maximum portability, different manufacturers will follow the standards. Third, the functionality of the iostream library is constructed and the function in
The value of the type of security and scalability provided by the Iostream library and functions are far more than your original imagination, so don't just discard it just because you are used to
By the way, the title of this Territor has not been printed; I do is
script>
Terms 3: Try to use New and Delete without Malloc and Free
The cause of Malloc and Free (and its variants) will have a problem that they are too simple: they don't know constructor and destructor.
Assume that two methods are assigned a space containing 10 String objects, one with malloc, another with New:
String * stringArray1 = static_cast
String * stringArray2 = new string [10];
As a result, StringArray1 does point to sufficient space that can accommodate 10 String objects, but these objects are not created in memory. Moreover, if you don't jump from this obscure symbol (see the description of clauses M4 and M8), you have no way to initialize the objects in the array. In other words, StringArray1 is actually not used. Instead, StringArray2 points to an array containing 10 fully constructive String objects, each of which can be safely used in any read string.
Suppose you think of a strange trick to initialize the objects in the StringArray1 array, then you will do this in the following programs:
Free (StringArray1);
DELETE [] StringArray2; // See the Terms 5: Why do you have a "[]"
Calling Free will release the memory pointing by StringArray1, but the String object in memory does not call the destructor. If the String object is in general, you have allocated memory, and these memory will be lost. Conversely, each object in the array will call the destructor before memory release when calling DELETE.
Since New and Delete can be interactively interact with constructor and destructive functions such as constructor, they are obvious.
It is also a bad idea to mix new and delete with Malloc and Free. Call free with a pointer for NEW, or call Delete to call with Malloc, which is unpredictable. Everyone knows "unpredictable" means that it may work well in the development phase, work well during the test phase, but may also be in the face of your most important customer's face.
The incompatibility between New / Delete and Malloc / Free often leads to some serious complexity issues. For example, it usually has a strDup function in
Char * strdup (const char * ps); // Return to copy of PS
In some places, C and C use the same STRDUP version, so the function is allocated with Malloc. In this case, some uninformed C programmers will ignore the pointer returned to the strDUp for free operation after calling StrDUP. In order to prevent this, some places will rewrite StrDup for C , and new NEW is called inside the function, which requires its caller to remember the last use of Delete. You can imagine, this will cause how serious transplantability, because StrDUP in the code is in different places in different places.
C programmers and C programmers are also very interested in reused code. Everyone knows that there is a large number of C libumes composed of codes written by Malloc and Free. When using these libraries, it is best that you don't have to be responsible for going to FREE to drop your own Malloc's memory, and / or you don't have to go to the MalloC library you will fall by Free, this is great. In fact, use Malloc and Free in the C program, just guarantees that the pointer to Malloc is used to use free, or the pointer you get with New is finally used to operate with Delete. Don't use new and free or malloc and delete, it will only find trouble.
Since Malloc and Free don't know about the constructor and the destructive function, mix Malloc / Free and New / Delete as uncontrolled as a noisy congestion party, then, when you are best to use it New and delete.