The following key points are for all c ++ Program Applicable to all members. The reason why I say they are the most important is that you often cannot find them in C ++ books or websites. For example, the pointer to a Member is not to be mentioned in many documents, but also frequent errors, even for some advanced C ++ programmers. The main point here is not just to explain how to write better Code More is to show the things in the language rules. Obviously, they are permanent good materials for C ++ programmers. I believe this article Article It will make you gain a lot. First, I will combine the questions that C ++ programmers at different levels often ask. I was surprised to find that many experienced programmers haven't realized whether the. h symbol should still appear in the standard header file. Key Point 1: <iostream. h> or <iostream>? Many C ++ programmers are still using<Iostream. h>Instead of using the updated standard<Iostream>Library. What are the differences between the two? First, five years ago, we began to oppose the use of the. h symbol in standard header files. It is not a good way to continue using outdated rules. In terms of functionality,<Iostream>Contains a series of templated I/O classes.<Iostream. h>It only supports batch streams. In addition, the C ++ standard interface of the input/output stream has been improved in some subtle details. Therefore,<Iostream>And<Iostream. h>The interface and execution are different. Finally,<Iostream>Each group of Chengdu is declared in STL format. However<Iostream. h>All components are declared as global. Because of these differences, you cannot confuse these two libraries in a program. As a habit, it is generally used in new code<Iostream>But if you are dealing with code written in the past, you can continue to use<Iostream. h>Maintain code consistency. Key 2: notes when passing parameters through references It is best to declare the referenceConstType. The advantage of this is that the program cannot modify this parameter. In the following example, function f () is the reference passed:
|
VoidF (Const Int& I ); IntMain () { F (2 );/* OK */ }
|
This program passes a parameter 2F (). At runtime, C ++ creates a 2-ValueIntType of temporary variables, and pass its referenceF (). This temporary variable and Its Reference are created and exist since F () is called until the function returns. Is deleted immediately. Note: if we do not addConstThe qualifier, then the FunctionF ()It may change the value of its parameters, which may lead to unexpected behavior of the program. So, don't forgetConst. This key point also applies to user-defined objects. You can add references to temporary objects.ConstType:
|
StructA {}; VoidF (ConstA & ); IntMain () { F (());// OK. A const reference of temporary A is passed. }
|
Key Aspect 3: comma separated expressionThe comma-separated expression is inherited from C and used inFor-AndWhile-Loop. Of course, this syntax rule is considered not intuitive. First, let's take a look at what is a comma separated expression. An expression is composed of one or more other expressions separated by commas, for example:
|
If (++ X, -- y, Cin. Good ())// Three expressions |
This if condition contains three expressions separated by commas. C ++ calculates each expression, but the result of the complete comma separated expression is the value of the rightmost expression. Therefore, only whenCin. Good ()ReturnTrue,IfThe value of the condition isTrue. The following is another example: |
IntJ = 10; IntI = 0; While (++ I, -- J) { // Until J = 0, the loop ends. During the loop, I continuously auto-Increment } |
Key 4: Use the global object constructor to call the function before the program starts.Some applications need to call other functions before the main program starts. For example, Transition Functions and registration functions must be called before the actual program runs. The simplest way is to call these functions through a global object constructor. Because global objects are constructed before the main program starts, these functions willMain ()Previously returned results. For example: |
class logger {< br> public: logger () {< br> activate_log (); // note: call the function you need to run in the constructor }< BR >}; logger log; // a global instance int main () {< br> record * prec = read_log (); // Translator's note: Read log file data //.. program code } |
Global ObjectLogInMain ()Constructed before running,LogFunction calledActivate_log (). Thus, whenMain ()When the execution starts, it can start fromLogFile to read data. Undoubtedly, memory management is the most complex and prone to bugs in C ++ programming. Directly accessing the original memory, dynamically allocating storage, and maximizing the efficiency of the C ++ command make you do your best to avoid Memory bugs.
Key 5: Avoid using pointers to functions in Complex Structures The pointer to a function is one of the least readable syntax in C ++. Can you tell me what the following statements mean? |
Void(* P [10]) (Void(*)()); |
P is a "pointing to a return composed of 10 pointers.VoidType and points to another array of functions without return and operation ". This troublesome syntax is really hard to recognize, isn't it? You can simply passTypedefTo declare the function equivalent to the preceding statement. First, useTypedefDeclare "pointer to a function without return or operation ": |
Typedef void(* PFV )(); |
Then, declare "another pointer to a function that does not return and uses PFV ": |
Typedef void(* Pf_taking_pfv) (PFV ); |
Now, declare an array composed of 10 pointers above: |
Pf_taking_pfv P [10]; |
AndVoid(* P [10]) (Void(*) () Achieves the same effect. But is it more readable! |
Key 6: pointer to a member
A class has two basic types of members: function members and data members. Similarly, there are two types of pointers to members: pointers to function members and pointers to data members. It is not commonly used because the class generally does not contain public data members. It is used only to coordinate the structure when inheriting the code written in C (Struct) And Class (Class. Pointers to members are one of the most incomprehensible structures in C ++ syntax, but they are also the most powerful feature of C ++. It allows you to call a function member of a class without having to know the name of the function. This very agile calling tool. Similarly, you can use a pointer to a data member to check and change the data without having to know its member name. Pointer to a data member Although at the beginning, the syntax for pointing to the member pointer may confuse you a little bit, but you will soon find that it is actually similar to a common pointer, but it is more:: Symbol and class name. For example, define a pointer to the int type: |
Int* PI; |
Define a data member pointing to an int type class: |
IntA: * PMI;// PMI is a member of the int type pointing to Class. |
You can initialize it like this: |
ClassA { Public: IntNum; IntX; }; IntA::* PMI = &::Num; |
The above Code declares a pointing classAOneIntType num member and initialize it to thisNumThe Member address.PMIAdd*You can use and change the value of the num member of Class: |
A A1, A2; IntN = A1. * PMI;// Assign a1.num to n A1. * PMI = 5;// Assign 5 to a1.num A2. * PMI = 6;// Assign 6 to 6a2. Num.
|
If you define a pointer to Class A, you must use-> *Operator substitution: |
A * pA = new; IntN = pa-> * PMI; Pa-> * PMI = 5; |
Pointer to a function MemberIt consists of the Data Types returned by function members. The class name follows the symbol, pointer name, and function parameter list. For example, a pointer to a function member of Class A (this function returns the int type:
|
ClassA { Public: IntFunc (); };Int(::* PMF )(); |
The above definition isPMFIs a function member pointing to Class.Func ()Actually, this pointer is no different from a normal pointer to a function, but it contains the class name and::Symbol. You can use* PMFTo call this function. |
Func (): PMF = & A: func; A; (A. * PMF )();// Call A. func () |
If you first define a pointer to an object, the above operation will use-> *Replace: |
A * pA = &; (Pa-> * PMF )();// Call pa-> func () |
The pointers to function members should consider polymorphism. Therefore, when you call a virtual function member through a pointer, this call will be dynamically recycled. You cannot take the address of the constructor and destructor of a class. Key Aspect 7. Avoid memory fragmentation Jing This often happens when your application leaks out of memory due to its own defects every time it runs, and you repeat your program periodically, the results can be imagined, and it will also make the system Crash. But how can we prevent it? First, try to use less dynamic memory. In most cases, you may use static or automatic storage or STL containers. Second, allocate as much memory as possible instead of once. Only a small amount of memory is allocated. For example, allocate the memory required by an array instance at a time, instead of allocating the memory of only one array element at a time. Key Aspect 8: delete or delete [] The programmer has an absurd saying: UseDeleteTo replaceDelete []Yes When deleting the array type! For example: |
Int* P = newInt[10]; DeleteP;// Error, which should be: Delete [] P |
The above program is completely incorrect. In fact, it is used on a platformDeleteReplaceDelete []The application may not cause a system crash, but it is just luck. You cannot guarantee that your application will be compiled on another compiler and run on another platform, so please useDelete []. Key 9. Optimizing member Arrangement The size of a class can be changed as follows:
|
StructA { BoolA; IntB; BoolC; };// Sizeof (A) = 12
|
On my computerSizeof ()Equal12. This result may surprise you, becauseAThe total number of members is 6 bytes: 1 + 4 + 1 bytes. Where did the other 6 bytes come from? The CompilerBoolThree filling bytes are inserted after the Members to ensure that each member is arranged in 4 bytes to facilitate the division. You can reduce the size of a:
|
StructB { BoolA; BoolC; IntB; };// Sizeof (B) = 8
|
This time, the compiler inserts only two bytes after member C. Because B occupies 4 bytes, it is naturally arranged as a word, and the size of a and c is 1 + 1 = 2, adding two bytes will arrange B in the form of two words. |
key 10: Why is it dangerous to inherit a class without virtual destructor? A class without virtual destructor means that it cannot be used as a base class. Such as STD: String, STD: complex, and STD: vector . Why is it dangerous to inherit a class without virtual destructor? When you create a class that inherits from the base class by using public inheritance, the pointer and reference in the New Class Object actually point to the original image. Because the Destructor are not virtual functions, when you delete a class like this, C ++ will not call the Destructor chain. For example, |
class A {< br> Public :< br> ~ A () // not a virtual function {< br> //... }< BR >}; class B: Public A // error; A does not have a virtual destructor {< br> Public : ~ B () {< br> //... }< BR >}; int main () {< br> A * P = New B; // It looks right Delete P; // error, the destructor of B is not called } |
Key Aspect 11: declare Nested classes with a friend classWhen you declare a nested class with a friend Meta class, put the friend meta declaration behind the nested class declaration without leading it.
|
ClassA { Private: IntI; Public: ClassB// Nesting class declaration before { Public: B (A & A) {a. I = 0 ;}; }; Friend classB;// Youyuan Declaration };
|
If you place the comments declaration in front of the declared nested class, the compiler will discard the rest declaration after the peer class. |