When I first fell in love with object-oriented six years ago, I remembered nearly ten definitions in one breath. Six years later, when I crawled from hundreds of thousands of lines of programs to prepare for snacks, I couldn't explain what "object-oriented" was, just as I couldn't tell what mathematics was. In software engineering, the fashionable terms "Object-Oriented Analysis" and "Object-Oriented Design" are usually used in the "requirement analysis" and "System Design" stages. There are several schools of "Object Oriented", such as Buddha, God, and God, who define the world in their own ways and leave a bunch of scriptures to explain the world.
Some scholars suggest looking for "objects" like this: analyzing the syntax of a sentence, finding out nouns and verbs. Nouns are objects, and verbs are object methods (I .e. functions ).
In order to confront Mao Zedong's "qinyuanchun · snow", the Kuomintang's literati specially asked the Qing Dynasty elders to write some neat poems to show their views. Old Jiang looked angry and scolded: "Niang SIPI, all of them have the smell of rotten corpses in the coffin ." After reading thousands of pages of software engineering materials, I finally found myself "mentally retarded", unable to understand the "Object-Oriented" theory, and realized that "programming is the final principle ."
There are many object-oriented programming languages, such as Smalltalk, Ada, Eiffel, Object Pascal, Visual Basic, and C ++. The C ++ language is the most flattering because it is compatible with the C language and has the performance of the C language. In recent years, a pure object-oriented language called Java has become very popular, and many people have been clamoring for the use of Java C ++. I think Java is like a C ++ nephew. Although it is not directly inherited, it is also a bit similar. When the nephew was playing on his uncle, he put a bubble in his urine. The two should not argue about it.
There are many books on C ++ programming. This Chapter does not talk about C ++ syntax, but only about some small programming principles. If I had understood these principles several years ago, I could have greatly improved the quality of hundreds of thousands of lines of programs.
1. Important Concepts of C ++ Object-Oriented Programming
There was such a role in the early Revolutionary film. He said, "I am a party representative, I represent the party, and I am the party ." Later, he brought disaster to the comrades.
Will C ++ programmers understand object-oriented programming?
Programmers who don't use C ++ certainly don't understand object-oriented programming?
Neither of them is necessary. Just as a bad guy may not become a good guy after joining the party, and a good guy may not become a bad guy if not joining the party.
I am not afraid of breaking the public anger to say: "C ++ has no master, and C language has a master ." After eight years of programming with C and C ++, I am deeply sorry that I am not a master of C language, and I am sorry that no one has asked me how to design object-oriented programs. Like many c ++ programmers, I thought I had understood object-oriented programming when enjoying the benefits of C ++ syntax. It's like squeezing out toothpaste and Selling toothpaste.
People can speak Mandarin even if they do not understand pinyin. If they do, they can speak Mandarin better. C ++ programming can be used if you do not understand object-oriented programming. If you understand object-oriented programming, C ++ programs will be better compiled. This section describes three basic concepts: class and object, inheritance and combination, and virtual function and polymorphism ". Understanding these concepts will help improve the quality of the program, especially improve "reusability" and "scalability ".
1.1 categories and objects
An object is an instance of a class ). If the object is compared to a house, the class is the design drawing of the house. So the focus of object-oriented programming is class design, rather than object design. Classes can encapsulate data and functions, in which functions represent the behavior (or service) of classes ). Class provides public, protected, and private keywords to declare which data and functions are public, protected, or private.
This can achieve the purpose of information hiding, that is, to make the class only public content that must be known to the outside world, while hiding all other content. We cannot abuse the encapsulation function of the class. We should not treat it as a hot pot and throw everything in it.
Is the class designed to be data-centric or behavior-centric?
Advocates the internal data structure of the "data-centered" group of personnel category. They are used to writing private-type data in front and public-type functions in the back, see Table 8.1 (.
What kind of services and interfaces should the "behavior-centric" Group provide? They are used to writing public-type functions in front and private-type data in the back, see Table 8.1 (B.
Many C ++ teaching books advocate "data-centric" in design ". I insist on and recommend that you "act-centric" when designing a class, that is, first consider what functions the class should provide. The core of Microsoft's COM specification is interface design. The COM interface is equivalent to the class's public function [Rogerson 1999]. In terms of program design, we should not doubt Microsoft's style.
Designing isolated classes is easier. It is difficult to correctly design the base classes and Their Derived classes. Some programmers cannot understand the concepts of "inheritance", "composition", and "polymorphism.
1.2 inheritance and combination
If a is a base class and B is a derived class of A, B inherits data and functions of. The example program is as follows:
Class
{
Public:
Void func1 (void );
Void func2 (void );
};
Class B: public
{
Public:
Void func3 (void );
Void func4 (void );
};
// Example
Main ()
{
B; // an object of B
B. func1 (); // B inherits the function func1 from.
B. func2 (); // B inherits function func2 from
B. func3 ();
B. func4 ();
}
This simple example program illustrates the fact that the "inheritance" feature of C ++ can improve the reusability of the program. Because "inheritance" is too useful and easy to use, it is necessary to prevent the misuse of "inheritance ". We need to set some rules for "inherit:
1. if Class A and Class B are irrelevant, B cannot inherit the functions of Class A to make B more functional.
Don't think that "don't eat white, don't eat", let a good and strong young people eat ginseng for no reason.
2. If Class B needs to use the function, consider the following two situations:
(1) If logical B is a kind of a, B is allowed to inherit the functions of. For example, a man is a human, and a boy is a man. Class man can be derived from class human, and class boy can be derived from class man. The example program is as follows:
Class human
{
...
};
Class man: Public Human
{
...
};
Class boy: public man
{
...
};
(2) If logically A is a part of B, B is not allowed to inherit the function of a, but to combine a with other things. For example, eye, nose, mouth, and ear are part of the head, therefore, class head should be composed of class eye, nose, mouth, and ear, not derived. The example program is as follows:
Class eye
{
Public:
Void look (void );
};
Class nose
{
Public:
Void smell (void );
};
Class mouth
{
Public:
Void eat (void );
};
Class ear
{
Public:
Void listen (void );
};
// Correct design and lengthy procedures
Class head
{
Public:
Void look (void) {m_eye.look ();}
Void smell (void) {m_nose.smell ();}
Void eat (void) {m_mouth.eat ();}
Void listen (void) {m_ear.listen ();}
PRIVATE:
Eye m_eye;
Nose m_nose;
Mouth m_mouth;
Ear m_ear;
};
If the head can be derived from eye, nose, mouth, and ear, the head will automatically have the functions of look, smell, eat, and listen:
// Incorrect Design
Class head: Public Eye, public nose, public mouth, public ear
{
};
The above program is very short and runs correctly, but this design is wrong. Many programmers cannot withstand the temptation of inheritance and make design mistakes.
Do you know why a rooster is hitting a hen with just egresses?
Because the hen has duck eggs.
As mentioned in section 3.3 in this book, "correctly running" programs are not necessarily high-quality programs. This is an example.
1.3 virtual functions and Polymorphism
In addition to inheritance, another excellent feature of C ++ is the support for polymorphism, which allows the use of the object of the derived class as the object of the base class. If a is a base class, B and C are the derived classes of A, the test parameter of the polymorphism function is the pointer of. The test function can reference objects A, B, and C. The example program is as follows:
Class
{
Public:
Void func1 (void );
};
Void test (A *)
{
A-> func1 ();
}
Class B: public
{
...
};
Class C: public
{
...
};
// Example
Main ()
{
A;
B;
C;
Test (& );
Test (& B );
Test (& C );
};
The above programs do not see the value of "polymorphism". With the addition of virtual functions and abstract base classes, the power of "polymorphism" is displayed.
C ++ uses the keyword "virtual" to declare a function as a virtual function. The virtual function of the derived class will be the function of the virtual function corresponding to the (override) base class. The example program is as follows:
Class
{
Public:
Virtual void func1 (void) {cout <"This Is A: func1 \ n "}
};
Void test (A *)
{
A-> func1 ();
}
Class B: public
{
Public:
Virtual void func1 (void) {cout <"This is B: func1 \ n "}
};
Class C: public
{
Public:
Virtual void func1 (void) {cout <"This is C: func1 \ n "}
};
// Example
Main ()
{
A;
B;
C;
Test (& A); // output this is a: func1
Test (& B); // output This is B: func1
Test (& C); // output this is C: func1
};
If the base class A is defined as follows:
Class
{
Public:
Virtual void func1 (void) = 0;
};
Therefore, func1 is called a pure virtual function, and classes containing pure virtual functions are called abstract base classes. Abstract base classes only define the form of pure virtual functions. The specific functions are implemented by the derived classes.
The combination of abstract base classes and polymorphism has the following outstanding advantages:
(1) The application does not need to write function calls for each derived class, but only needs to process the abstract base class. This
It can be called "retained without changing", which can greatly improve the reusability of the Program (this is the reuse of interface design, rather than the reuse of code implementation ).
(2) The function of the derived class can be referenced by the base class pointer, Which is backward compatible and can improve the scalability and maintainability of the program. It is not surprising that previously written programs can be called by programs written in the future, but the future written programs can be called by previously written programs.
2. Good programming style
Martial arts experts with deep internal skills are often unremarkable. Similarly, programmers will not use strange tricks to write programs. A good programming style is a prerequisite for high-quality programs.
2.1 naming conventions
Many people use Pinyin to name functions or variables when programming. This does not mean that you are very patriotic, but will confuse people who use this program (many Southerners do not understand pinyin, ). The English in the program is generally not too complex, and the words should be accurate. The Hungarian naming convention [Maguire 1993] was proposed by Microsoft. Although it was cumbersome, it became natural to get used to it. No one forces you to adopt the naming method, but one thing should be done: Your program name must be consistent.
The naming conventions used in programming are as follows:
(1) macro definitions are expressed with uppercase letters and underscores, for example, max_length;
(2) The function is composed of words starting with an upper-case letter, such as setname and getname;
(3) the pointer variable is prefixed with P, for example, * pnode;
(4) Add the bool variable with the prefix B, such as bflag;
(5) The Int variable is prefixed with I, such as iwidth;
(6) Add the prefix F to the float variable, such as fwidth;
(7) The double variable is prefixed with D, for example, dwidth;
(8) string variables are prefixed with STR, such as strname;
(9) Add the prefix e to the enumerated variables, such as edrawmode;
(10) Add the prefix M _ to the member variables of the class, such as m_strname and m_iwidth;
For int, float, and double variables, if the meaning of the variable name is very obvious, the prefix is not added to avoid being cumbersome. Such as the three-dimensional coordinates (x, y, z) of the int type I, J, K, and float variables used for loops.
2.2 Use assertions
Programs are generally divided into debug and release versions. The debug version is used for internal debugging, And the release version is released to users. Assert is a macro that only works in the debug version. It is used to check the situation where "no" occurs. The following is a memory replication program. During the running process, if the assert parameter is false, the program will be suspended (A dialog is usually prompted, description of where the assert is triggered ).
// Copy non-overlapping memory blocks
Void memcpy (void * pvto, void * pvfrom, size_t size)
{
Void * pbto = (byte *) pvto;
Void * pbfrom = (byte *) pvfrom;
Assert (pvto! = NULL & pvfrom! = NULL );
While (size--> 0)
* Pbto ++ = * pbfrom ++;
Return (pvto );
}
Assert is not a hasty macro. To avoid the differences between the debug and release versions of the program, assert should not produce any side effects. So assert is not a function, but a macro. Programmers can regard assert as a harmless testing method that can be safely used in any system status.
There are few more frustrating things than the assertions that trace the program, but do not know the role of the assertions. You have made a lot of time, not to exclude errors, but to find out what the error is. Sometimes, programmers occasionally design wrong assertions. Therefore, if you do not know what the assertions check, it is difficult to determine whether the errors appear in the program or in the assertions. Fortunately, this problem is well solved by adding clear notes. This is obvious, but few programmers do this. This is like a person in the forest, seeing a "dangerous" big sign on the tree. But what is the danger? Will the tree fall? Is there a waste well? Is there a beast? Unless you tell people what danger is, this warning board cannot play a positive and effective role. Incomprehensible assertions are often ignored or even deleted by programmers. [Maguire
1993]
The following principles Use assertions:
(1) Capture exceptions that should not occur with assertions. Do not confuse the differences between illegal and wrong situations. The latter must exist and be handled.
(2) Use assertions to confirm the function parameters.
(3) When writing a function, you should repeat it and ask yourself: "What assumptions do I plan to make ?" Once
Suppose that we need to use assertions to check the assumptions.
(4) In general textbooks, programmers are encouraged to design error-proof programs, but remember that such programming style will conceal errors. When programming against errors, if "impossible to happen" does happen, Use assertions to trigger an alarm.
2.3 new, delete, and pointer
In C ++, the operator new is used to request memory, and the operator Delete is used to release memory. In C language, the function malloc is used to request memory, and the function free is used to release memory. Since C ++ is compatible with C language, new, delete, malloc, and free may all be used together. New can do more work than malloc. It can apply for the object's memory, but malloc cannot. The pointer in C ++ and C languages is extremely powerful, and errors may cause disasters. For a pointer P, if the new memory is used, delete must be used instead of free. If the memory is applied with malloc, you must use free
Instead, delete cannot be used for release. After you use delete or free to release the memory referred to by P, you should explicitly set P to null immediately to avoid an error when you use P next time. The example program is as follows:
Void test (void)
{
Float * P;
P = new float [100];
If (P = NULL) return;
... // Do something
Delete P;
P = NULL; // good programming style
// You can continue to use P
P = new float [500];
If (P = NULL) return;
... // Do something else
Delete P;
P = NULL;
}
We also need to prevent "wild pointer", which is a pointer to the "junk" memory. There are two main causes:
(1) the pointer is not initialized.
(2) The Pointer Points to the released memory, which is the most difficult to prevent. The example program is as follows:
Class
{
Public:
Void func (void ){...}
};
Void test (void)
{
A * P;
{
A;
P = & A; // note the life cycle of
}
P-> func (); // P is a "wild pointer" and the program has an error.
}
2.4 use const
When defining a constant, const is more flexible than # define. A constant defined by const contains a data type, which can be used in logical operations. For example:
Const int length = 100; // length is of the int type
Const float max = 100; // Max is of the float type
# Define length 100 // No type of Length
# Define max 100 // Max no type
In addition to defining constants, const also has two "protection" functions:
I. The parameter values of the mandatory protection function are not changed.
In the following program, function F does not change the value of the input parameter name, but function G and H may change the value of name.
Void F (string S); // pass by value
Void g (string & S); // pass by referance
Void H (string * s); // pass by pointer
Main ()
{
String name = "dog ";
F (name); // The value of name will not change
G (name); // The value of name may change.
H (name); // The value of name may change
}
For a function, if the '&' or '*' type parameter is used only for input but not for output, you should add const before the parameter, to ensure that the function code does not change the value of this parameter (if the value of this parameter is changed, the compiler will receive an error warning ). Therefore, the functions G and H in the above program should be defined:
Void g (const string & S );
Void H (const string * s );
2. The member function of the force protection class does not change the value of any data member.
In the following program, the member function count of the class Stack is only used for counting. To ensure that count does not change the value of any data member in the class, the function count should be defined as the const type.
Class Stack
{
Public:
Void push (int elem );
Void POP (void );
Int count (void) const; // a function of the const type
PRIVATE:
Int num;
Int data [100];
};
Int Stack: Count (void) const
{
++ Num; // compilation error. The num value changes.
Pop (); // compilation error. Pop changes the value of the member variable.
Return num;
}
2.5 Other suggestions
(1) do not write an overly complex statement. Compact C ++/C code does not see machine code that can be efficient, but it will reduce the comprehensibility of the program, the probability of program errors increases.
(2) do not compile functions that combine multiple functions. Do not mix normal values and error marks in the return values of functions.
(3) do not program bool values true and false with values 1 and 0. In most programming languages, false is defined as 0, and any non-0 value is true. Visual c ++ defines true as 1, while Visual Basic defines true as-1. The example program is as follows:
Bool flag;
...
If (FLAG) {// do something} // correct usage
If (flag = true) {// do something} // dangerous usage
If (flag = 1) {// do something} // dangerous usage
If (! Flag) {// do something} // correct usage
If (flag = false) {// do something} // unreasonable usage
If (flag = 0) {// do something} // unreasonable usage
(4) Be careful not to write "=" as "=". The compiler will not automatically detect such errors.
(5) do not write 123 as 0123. The latter is a numerical value of octal.
(6) record the programming errors that you often make and paste them into tables next to your computer.
3 Summary
C ++/C programming is as profound and profound as the martial arts of Shaolin Temple. After eight years of practice, I learned only two or three of them. So no matter what time, do not feel that your programming level is the highest in the world. To see other people's good technologies and styles, you must learn with an open mind. This chapter has little content, just like giving you only one bayberry to eat when you are thirsty. You must not be addicted to it. I recommend a good book called C ++ FAQs [Cline 1995] by Marshall P. Cline. You will be full of praise after reading it. C ++/C programs can be compiled. Don't be so proud. This is just a basic skill requirement for programmers. If you compare System Analysis and system design to "strategic decision-making", programming is only "tactical" at best ". If the commander is an idiot, the soldiers will be defeated again if they are brave. Therefore, programmers should not only focus on the program, but also learn more. We should learn from our children in Beijing and Hu Tongli. They will be able to give advice and comment on world events at a young age.