Here are some of the key points that apply to all C + + program apes. I say they are the most important, because these points are mentioned in the C + + book or you usually can not find the site. For example, pointers to members, which are not mentioned in much of the material, are often a mistake, even for some advanced C + + program apes. The point here is not to explain how to write better code, but many of the other things that show up in the language rules. Obviously, they are good data for the C + + program ape. I believe this article will make you fruitful.
First of all, I put together a number of questions that are often asked by C + + program apes at different levels. I was amazed to find that there are so many experienced programs that apes have not yet realized. The H symbol should also be in the standard header file today.
Point 1: <iostream.h> or <iostream>
Very many C + + programs Ape is still in use<iostream.h>Instead of using the updated standard<iostream>Library. What's the difference between the two? First, 5 years ago we began to oppose the continuation of the. h symbol in the standard header file. It's not a good way to continue using outdated rules. From a functional point of view,<iostream>Includes a series of templated I/O classes, in contrast to<iostream.h>only supports character streams. In addition, the C + + standard specification interface for input and output streams has been improved in some subtle detail, so<iostream>And<iostream.h>is different on both the interface and the running. At last<iostream>are declared in the form of STL, but<iostream.h>All of the components are declared as global.
Because of these substantial differences, you cannot confuse the use of these two libraries in a program. As a habit, generally used in new code<iostream>, but suppose you are dealing with code that was written in the past, in order to inherit<iostream.h>Consistency of the old hold code.
point 2: Places to be aware of when passing references by reference
When passing parameters by reference, it is better to declare the reference asConstType. The advantage of this is that you tell the program that you can't change the number of parameters. In the example below, the function f () is the passed reference:
|
void F (constint & i); int Main () { F (2); / * OK * / }
|
This program passes a parameter of 2 to F (). At execution time, C + + creates a temporary variable of type int with a value of 2 and passes its reference to F (). This temporary variable and its reference are created and present until the function is called from F (). When returned, it is immediately deleted. Note that assuming that we do not precede the reference with a const qualifier, the function f () may change the value of its parameters, and may cause unexpected behavior in the program. So, don't forget the const.
This point also applies to user-defined objects. You can also add a reference hypothesis to a temporary object as a const type:
|
struct a{}; void F (const a& A); int Main () { F (A ()); //OK, passing a const reference for temporary a } |
Point 3: "comma-separated" representations
The "comma separated" expression is inherited from C, and is used in for- and while- loops. Of course, this grammatical rule is thought to be not intuitive. First, let's look at what is a "comma-separated" representation.
An expression is composed of one or more other expressions, separated by commas, such as:
|
if (++x,--y, Cin.good ())//three expressions |
This if condition includes three expressions separated by commas. C + + evaluates each expression, but the result of a complete comma-separated expression is the value of the rightmost expression. Therefore, the value of theif condition is trueonly if cin.good () returns true . Here are a few more examples: |
int j=10; int i=0; while (++i,--j) { Until J=0, the loop ends, and in the loop, I constantly self-adds } |
Point 4, use the constructor of the global object to call the function before the program starts
Some applications need to call other functions before the main program starts. Such as: The process function of the transition, the registration function must be called before the actual program execution. The simplest approach is to call these functions through a constructor of a global object. Because global objects are constructed before the main program starts, these functions will return results before main () . Such as: |
class Logger { Public: Logger () { Activate_log (); //Translator NOTE: Call the function you need to execute first in the constructor } }; Logger log; //A global instance int Main () { Record * prec=read_log (); //Translator Note: Read log file Data //. Program code } |
The Global object log is constructed before main () is executed, andlog calls the function Activate_log (). Thus, when main () starts executing, it is able to read the data from the log file. There is no doubt that memory management is the most complex and easy place to have bugs in C + + programming. Direct access to raw memory, dynamic allocation of storage, and maximizing the efficiency of C + + directives all make it hard to avoid bugs about memory. Point 5: Avoid pointers to functions that use complex constructs
Pointers to functions are one of the least readable grammars in C + +. Can you tell me the meaning of the following statement?
|
void (*p[10]) (void (*) ()); |
P is an array of 10 pointers to a function that returns a void type and points to an element that has no return and no operations. This troublesome grammar is really hard to recognize, isn't it? You can actually simply declare a function that is equivalent to the above statement through a typedef . First, use a typedef to declare a pointer to a function that has no return and no operations: |
typedef void (*PFV) (); |
Next, the declaration "has a pointer to a function that has no return and uses PFV": |
typedef void (*PF_TAKING_PFV) (PFV); |
Now, declare an array of 10 of these pointers: |
PF_TAKING_PFV P[10]; |
with void (*p[10]) (void (*) ()) to achieve the same effect. But this is not more readable! |
Point 6: Pointers to Members
There are two main members of a class: function members and data members. Similarly, pointers to members are also available in two ways: a pointer to a function member and a pointer to a data member. The latter is not often used, since the class usually does not contain public data members, and is used only when the structure (struct) and class (classes) are used to inheritcode written in C.
Pointers to members are one of the most incomprehensible constructs in C + + syntax, but this is also one of the most powerful features of C + +. It allows you to invoke a function member of a class without having to know the name of the function. This is a very agile calling tool. Similarly, you can also check and change this data without having to know its member names by using pointers to data members.
Pointers to data members
Although the syntax of pointers to members can make you a little bit confusing at first, you will soon find that it is virtually identical to a normal pointer, just a few more of the numbers in front of the *: Symbols and class names, example: defining a pointer to int:
|
int * PI; |
Defines a data member that points to a class of type int: |
int A::* PMI; //pmi is a member of the int type that points to class A |
You can initialize it like this: |
class A { Public: int num; int x; }; int A::*PMI = & A::num; |
The above code declares a NUM member that points to an int of class a and initializes it to the address of the Num member. By adding * in front of the PMI You will be able to use and change the value of the NUM member of Class A: |
A A1, A2; int N=a1.*pmi; //Assign the A1.num to n a1.*pmi=5; //Assign a value of 5 to the A1.num a2.*pmi=6; //Assign a value of 6 to the 6a2.num
|
Assuming you have defined a pointer to Class A, you must replace the above operation with the ->* operator: |
A * pa=new A; int n=pa->*pmi; pa->*pmi=5; |
Pointers to function members
It consists of the data type returned by the function member, followed by the class name:: Symbol, pointer name, and function's list of references. For example: A pointer to a function member of Class A that returns an int type:
|
class A { Public: int func (); };int (A::*PMF) (); |
The above definition means that PMF is a pointer to the function member func () of Class A. In fact, this pointer is no different from a normal pointer to a function, just that it includes the name of the class and : symbol. You can call this function wherever you use *PMF . |
Func (): pmf=&a::func; A; (A.*PMF) (); //Call A.func () |
Suppose you first define a pointer to an object, then the above operation is replaced with ->* : |
A *pa=&a; (PA->*PMF) (); //Call Pa->func () |
A pointer to a function member takes polymorphism into account. So, when you invoke a virtual function member through a pointer, the call is recycled dynamically. There is also a need to note that you cannot take the constructor of a class and the address of the destructor. Point 7, avoid memory fragmentation
This is often the case when your application leaks memory as a result of a memory leak due to a bug in the program every time you execute it, and you are periodically repeating your program, and it can be imagined that it will crash the system. But how to do talent prevention? First, use as little dynamic memory as possible. In most cases, you may use static or self-active storage or an STL container. Second, try allocating large chunks of memory instead of just allocating a small amount of memory at a time. For example: allocating the memory required for an array instance at a time, rather than allocating only one array element at a time. Point 8, delete or delete[]
There is a myth in the program ape that using delete to replace delete[] is possible when you delete an array type! Give me a sample: |
int *p=newint[10]; Delete p; //error, should be: delete[] P |
The program above is completely wrong. In fact, an application that uses delete instead of delete[] on one platform may not cause the system to crash, but that is sheer luck. You cannot guarantee that your application will be compiled on a compiler and that there is another platform, so please use delete[]. Point 9, optimize the arrangement of members
The size of a class can be changed in the following ways: |
struct A { BOOL A; int b; bool C; }; //sizeof (A) = =
|
On my Computer sizeof (A) equals a . This result may surprise you, because the total number of members of a is 6 bytes: 1+4+1 bytes. Where did the other 6 bytes come from? The compiler inserts 3 padding bytes behind each bool member to ensure that each member is arranged in 4-byte order for demarcation. You can lower the size of a by the following way:
|
struct B { BOOL A; bool C; int b; }; //sizeof (B) = = 8
|
This time, the compiler inserted only 2 bytes after member C. Since b takes up 4 bytes, it is very natural to arrange it as a word, and the size of a and C 1+1=2, plus 2 bytes to arrange B exactly as two characters. |
Point 10, Why is it critical to inherit a class that does not have a virtual destructor? A class that does not have a virtual destructor means that it cannot be a base class. such as std::string, Std::complex, and std::vector. Why is it critical to inherit a class that does not have a virtual destructor? When you have a public inheritance that creates a related class that inherits from a base class, pointers and references in the new class object actually point to the originating object. Since the destructor is not a virtual function, C + + does not call the destructor chain when you delete one of these classes. For a sample description: |
class A { public : ~a () //not virtual function { //... } }; class B: public a //wrong; A does not have a virtual destructor { public : ~b () { //... } }; int Main () { A * p = new b; //appears to be right delete p; //error, B's destructor is not called } |
Point 11, declare nested classes in friend class
When you declare a nested class in a friend class, the friend declaration is placed after the nested class declaration, not the previous one.
|
class A { Private: int i; Public: class B //nested class declaration in front { Public: B (A & a) {a.i=0;}; }; Friend class B //friend class declaration };
|
Suppose you put a friend declaration in front of the declaration nested class, and the compiler discards the other declarations after the friend class. |