C ++ from scratch (12) -- What Is Object-Oriented Programming Philosophy

Source: Internet
Author: User

C ++ starts from scratch (12)

-- What Is Object-Oriented Programming

The most important concept of C ++-class has been described above, and most of the class-related knowledge has been introduced. So far, we can start to do some advanced programming applications-designing programs, instead of simply turning algorithms into code. To illustrate how to design a program, it is necessary to first understand what programming ideas are.

Programming Ideology

Programming, that is, writing a program. As we have already said, a program is the description of a method, so programming is the description of a method. I knew how to get to the People's Park, and then I wrote a description of the method for getting to the People's Park-from the city center, I walked 400 m east and then turned right and walked 200 m. Then the other person knows how to proceed, but his program is: Walk two intersections along Renmin East Road in the city center, turn right at the third intersection, and go straight to the right hand side. Obviously, the two programs are different, but the last route is the same, that is, the methods are the same, but the descriptions are different.
The so-called programming idea is how to program, that is, how to compile the program. The three steps mentioned in "C ++ from scratch (8)" are actually a programming idea. This is why different people write different programs for the same algorithm (referring to program logic, rather than simple variables or function names). Different people have different programming ideas.
If you compile or read more programs, you will find that programming ideas are very important. Good programming ideas produce well-organized programs with high maintainability. Poor programming ideas produce obscure programs with low maintainability. Note: here we will compare the program's ease of use. In reality, out of efficiency, we will use programming ideas that do not conform to the habits of the human brain, which leads to the difficulty of code maintenance, however, for efficiency, the optimized code is often used at the bottleneck of the Program (this code is generally written in assembly language, and the algorithm is optimized in mathematics to a large extent, discard most of its meaning in the human world ).
This series has always adhered to and recommended such a programming idea-everything is written according to semantics. Semantics is the meaning of language. Previously, it is the meaning of code in the human world. For example, if a table is mapped to a structure with table size, color, and other member variables, why are there no members such as quality, material, price, and production date? It is necessary to explain the meaning of the "Human World.


We live in a four-dimensional objective physical world. monsters in the game live in a game-defined world. Snow White lives in a fairy tale world. What is the world? The world is a set of rules. For example, in the objective world, a force can act on an object with mass, and then change the speed of the object according to the laws of kinematics; the charge-specific absorption of the same-sex exclusion; energy conservation, etc, these are descriptions of certain rules in the Rule Set of the objective world. Note that they are only descriptions of rules, not rules, as if the program is a description of methods, but not methods. That is to say, methods and rules are both abstract logical concepts expressed by programs and arguments. Program is what we want to write, and argument is a theory, such as probability theory, kinematics, fluid mechanics, etc. The game world mentioned above is because the game is also a series of rules. I have elaborated on this in another article, game theory, if you have not understood the concept of the world, the elaboration on what is a game in game theory may be helpful. Similarly, the fairy tale world is composed of a series of rules. For example, Snow White can eat, sleep, and be poisoned by Apple viruses. The magic mirror can answer questions.
So what if I understand the concept of the world? What is the purpose? As mentioned above, this series of programs are recommended to be compiled according to semantics, that is, after learning the algorithm, the program is written according to the three steps described in C ++ from scratch (8. Algorithms are based on certain rules. For example, if the algorithm for summation of 1 to 100 is (1 + 100) * 100/2, it implies that some rules already indicate what is addition, subtraction, multiplication, division, what is summation. That is to say, an algorithm must be in one world. It may be meaningless in another world. Because algorithms are methods, they are composed of commands and operated resources, and commands and resources are defined by the world.
As mentioned above, writing code based on algorithms is actually a world first developed as a platform for algorithm presentation. For example, if a businessman cross the river, the rule set below shows that one boat can only take two people to cross the river, and three businessmen and three servants are on the river; when the number of servants on any side of the river exceeds that of businessmen, the merchant will be killed. This is a serious and inaccurate description of the world on which the cross-river problem is based, but it is no good to be too abstract. Just note: the businessmen and servants above are not businessmen and servants in the real world, they cannot eat, go to bed, or talk, or even walk. The only thing they can do is to cross the river by boat to change their position. When there are more examples of servants at a location (I .e. a river bank) than merchant instances (and at least one merchant instance), the merchant is killed. The above description is now referred to as the merchant's servant theory. It is a description of the world on which the cross-river problem is based.
The other person does not look at the problem as above. The river has two banks. Each bank has two numbers: merchant and servant. There is one way to change the two numbers corresponding to the river bank according to a rule (that is, the river can only be crossed by two people ), when the number of servants of any river bank is more than that of businessmen (and the number of merchants is not zero), the merchant is killed. This person does not define either the merchant or the servant, but only defines one concept-riverbank, which has two attributes-merchant and servant. This is another argument. It is also called the riverbank theory.
What does it mean? The above are two different arguments about the world where businessmen cross the river. Note that the above arguments are different, but they all describe the same world, just like dynamics and quantum mechanics. They all describe the rules of action between objects in the objective world, but they are quite different. Algorithms are always based on the world, but the more accurate statement is that algorithms are always based on the description of the world. The so-called design program is the world description based on the algorithm, that is, the argument, the argument is actually a description of the problem.
Now, considering the merchant's servant theory and the riverbank theory mentioned above, they both describe the same world, but the former puts forward two concepts of nouns: merchant and servant, each has the "location" status and the "boat ride" function, as well as the verb concept of "Merchant killed". The latter proposes a concept of nouns-riverbank, it has two attributes: "Merchant's number" and "servant's number", and "Merchant's murder" and "boat ride. Here, the latter is better than the former, because the latter defines fewer terms (I .e., the concept of nouns is more likely to increase the complexity of the architecture than the concept of verb, because it represents the types of things in the world, the more types, the more complex the world, the more difficult to implement), although not necessarily easier to understand, but the structure is simpler.
It is easy to find that all arguments can only be composed of the concepts of nouns and verbs. The former is a number, real number, and plural in mathematics, the latter are addition, subtraction, multiplication, division, and derivation. They are all called definitions. In game theory, I call the former class, And the instance of the class is the resource operated in the method, and the latter is called a command. In the method, the former is the resource type, and the latter is the operation type. The less concepts are proposed, the simpler the structure, and the better. However, it should be noted that, for computer programming, computers are not abstract concepts but efficiency factors, therefore, the code compilation efficiency based on the aforementioned good argument algorithms is not necessarily high.
Therefore, the so-called program design is the arguments based on the design algorithm, and a good program design is a well-designed argument. However, as mentioned above, the efficiency is not necessarily high. In this regard, it is generally designed only at the bottleneck of the code, and the overall architecture of the program is still in accordance with the previous design. As the program grows, a clear and concise program architecture becomes more important. To keep the program architecture concise, you should design a good argument; To keep the architecture clear, code should be written according to the semantics. Next, we will introduce such popular object-oriented programming ideas to help design programs.

What is an object?

To describe object-oriented, first understand what objects are. The object is the implementation of the aforementioned "concept of nouns", that is, an instance. For example, in the merchant's servant theory, there are two "Concepts of nouns": merchant and servant. If there are three businessmen and three servants, there are six objects, there are three merchant instances and three servant instances respectively. Note the differences between objects and instances. In fact, there is no difference between them. If you have to say the difference, you can think that the object can be stateless, but the instance must be stateful.
So what is status? Let's take a look at what is attribute. The table has a property called color. The table is red and the table is green. A person has a state called his face. His face is red and pale. They are all colors, but one is attribute and the other is State. What is the difference? If we map both the table and people into a class, the color of the table and the human face should be mapped into a member variable of the corresponding class, the difference between the two is that the table instance color does not change during the main operation, which is mainly used for reading; the human face may change during the main operation of the Human instance, it is mainly used for writing. What is the operation process? A class maps resources and resources can have functions, that is, member functions. When a function of an instance is executed, it is the operation process of the instance.
There is a function on the table to "put things". When this member function is called, the value of the color attribute is read to determine whether the color of the things placed on the table matches the color of the table. A person has a function of "bath", which can make the face of the corresponding instance change from pale to rosy. But the table also has the function of "changing the color", which can be called to change the color of the table. As mentioned above, the color is an attribute and should be read, but it is written during the operation of the instance. Note that what we mentioned above is the "main operation process", that is, the purpose of the table is to "put things", not to "change the color ". If the concept of a table is mainly used to change its color in the corresponding world, instead of putting something in it, then the table is just a container that records the color value, and the color of the table is the state, it is not an attribute.
What is the significance? Both attributes and states are mapped to member variables, but their meanings are significantly different from those in the code. The attribute is used to configure the instance, And the status is used to represent the instance. In the idea of object-oriented programming, objects are simply examples of attributes and functions (also called methods, this seems very weak when the world on which the program is compiled is complicated, and it is an incorrect understanding of the "attribute", coupled with the word "encapsulation, this leads to a large number of absurd code, which will be explained later.
The difference between properties and States leads to the so-called stateless object (proposed in MTS -- Microsoft Transaction Server, called stateless component, stateless component ), this is exactly the difference between objects and instances-objects are implementations, so they can be the implementation of an abstract concept; instances actually exist, and cannot be the implementation of an abstract concept. In C ++ code, this is represented by a class without member variables and a class with member variables. As follows:
Struct search {virtual int search (int *, Int, INT );};
Search a, B; int C [3] = {10, 20, 5}; A. Search (C, 3, 20 );
Here, two objects A and B are generated. They are all abstract concepts-objects of the search function. Note that the structure search does not have a member variable because it is not required. What is the length of A and B? Generally, the compiler sets the length of A and B as one byte, and then & A is not equal to & B.
Struct bsearch: Public Search {int search (int *, Int, INT );};
Search * P; bsearch D; P = & A; P = & B; P = & D; P-> Search (C, 3, 5 );
Note that the code can still be called as the above two search instances A and B, and one bsearch instance D (even if they do not actually exist, the logical size is zero ), that is why there is no difference between it and the object, but there is only a slight difference in concept.
Note that the stateless object mentioned above does not mean the instance of the class without member variables, but does not mean that there is no attribute. For example, the previous bsearch attribute m_maxsearchtimes indicates that if m_maxsearchtimes is not found after multiple searches, bsearch: Search cannot be found. Although bsearch has a member variable, it is still an abstract concept logically. Because the implementation of attributes and states is the same (both through member variables), some special means are required to implement stateless objects. This series is irrelevant and is not listed here.
Is there a difference between A and B? Why do we have two instances? Should the "search function" be mapped to a function based on the previously mentioned semantics? Why do we need to map to a class without member variables? The above usage is used in STL (standard template library-Standard Template Library), and some variants are made, called function classes. It is a programming technique. But there is indeed such semantics-the search function has three parameters: the search condition, the search location (that is, the container or set to be searched), and the method of sorting the container or set before searching. Isn't it just right to pass the function pointer here (actually not exactly, the pointer semantics is reference, and it is not very accurate here )? This is the so-called object-oriented programming idea.

Object-Oriented Programming

The preceding description shows that the design program is the description of the problem to be solved. However, arguments can be expressed only by the concepts of nouns and verbs, and objects are exactly the realization of the concepts of nouns, instead, you can use the class without member variables mentioned above to map the "verb concept" to convert it into an object. Therefore, a world can be completely composed of objects, and only objects are represented in the world based on algorithms before subsequent code compilation, this programming method is called the object-oriented programming idea.
Note: first, design the world where the algorithm should be based, and then express it with all objects. Then design the algorithm and map it to the code. However, when writing a merchant's cross-river problem, the algorithm was provided directly, and the world was not designed? In fact, because the problem was too simple, I designed the world subconsciously and described it with the riverbank theory mentioned above. It should be noted that the design of the world is totally dependent on the problem. To be precise, I did not design the world, but designed the riverbank theory to describe the problem.
Next, because the object is an instance, it is a design class in C ++ to describe the world with the object, and a combination of the class instances will express the world. However, it should be noted that the object-oriented method describes the world, but it also describes the algorithm, because the algorithm will also propose some concepts that need to be mapped, such as the cross-river scheme in the algorithm of the previous merchant's cross-river problem. But remember, when you describe an algorithm and perform operations on the class defined in the world, you must maintain the design of that class, do not map the algorithm to a member function of the class because the operations on the instance of the class in the algorithm are too complex, because this seriously masks the implementation of the algorithm, destroys the program architecture. For example, if an algorithm is used to keep the car in place and requires complex operations, is it necessary to add a function for the car to keep it in place ?! This is a frequent mistake when designing a class. For this reason, an object-oriented code is not just composed of classes, it may also map some operations in the algorithm into functions, and there are a large number of global functions. Remember: when designing a class, if it is a concept mapped to the world, do not consider an algorithm, but design it with the world as the boundary, do not add incorrect members to an algorithm because of a specific need.
Therefore, the concept of nouns is mapped to a class. The attributes and states of the concept are mapped to member variables, and the functions of the concept of nouns are mapped to member functions. What should we do with "verb concept? Ing to a class without member variables? As we have seen above, this is not common in practice because it is too awkward (STL only uses it as a technique), so it is often mapped to a function, although this is based on object-oriented thinking, it is much easier to understand and the program architecture is much more concise.
With the advent of object-oriented programming, a new design method was born. Because it is so good that it is widely spread, but wrong understanding leads to wrong ideas born everywhere, and even worse, it is put before the horse, this design method is called object-oriented programming ideas, its name is encapsulation.


First, let's take a look at the design of the following classes that can often be seen in the explanations of objects in various VC tutorials.
Class person
{PRIVATE: Char m_name [20]; unsigned long m_age; bool m_sex;
Public: const char * getname () const; void setname (const char *);
Unsigned long getage () const; void setage (unsigned long );
Bool getsex () const; void setsex (bool );
The above defines all member variables as private, and then provides three pairs of get/set functions to access the above three member variables (because they are private and cannot be directly accessed by the outside world ), these three pairs of functions are all public. Why? These textbooks encapsulate the internal memory layout of class persons, in this way, the outside world does not know how it is deployed in the memory and thus can ensure the effectiveness of the memory (only the class itself operates its instance ).
First of all, we need to confirm the absurd design above. It makes no sense to be authentic and "Unlocked. Then let's look at the so-called memory layout encapsulation. Recall why the header file must be included at the beginning of each source file to be used in C ++ from scratch (10. Assume that the above statement is in person. h, and then use the class person in B. cpp, which would have to be # include "person. H". replace it with the following:
Class person
{Public: Char m_name [20]; unsigned long m_age; bool m_sex;
Public: const char * getname () const; void setname (const char *);
Unsigned long getage () const; void setage (unsigned long );
Bool getsex () const; void setsex (bool );
Then use the class person in B. cpp as usual, as shown below:
Person A, B; A. m_age = 20; B. getsex ();
Here, the person: m_age is used directly. Even if you do not do such a bad action, # include "person. H" is still used, as follows:
Struct person {char m_name [20]; unsigned long m_age; bool m_sex ;};
Person A, B; person * PP = (person *) & A; PP-> m_age = 40;
The member person: m_age of instance a whose person is still directly modified above. How can I hide the memory layout ?! Recall the role of the Declaration. The memory layout of the class is required when the compiler generates an object. It cannot hide anything about the object implementation for any code that uses the object, otherwise, the compiler cannot compile the corresponding code.
In terms of semantics. The person ing is not the concept of a person in the real world. It should be the record buffer in the table that stores information about a person in a database, so should the buffer have the functions represented by those three pairs of get/set? The buffer zone is used to buffer data. It is used by other operations After buffering, just like a box. Therefore, the above three pairs of get/set do not have to exist, and the three member variables cannot be private. Of course, if the person ing is not a buffer, and there are semantics as described above in other worlds, there is no problem with the definition as above, however, it would be a big mistake to define classes because of the encapsulation of the memory layout.
The error above is that it does not understand encapsulation. To illustrate the encapsulation, let's take a look at the MFC (Microsoft Foundation Class Library -- Microsoft function class library), a library file that defines many classes, most of which are encapsulation design. The definition of cfile class in library files described in SDK description. It can be seen from the name that it maps to the file concept in the operating system, but it has such a member function-cfile: open, cfile: Close, cfile :: read, cfile: write. What's the problem? These four member functions map object operations rather than file functions, including opening a file, closing the file, reading data from the file, and writing data to the file. Isn't this the same as the semantics of the previously mentioned member functions? The preceding four operations share a common nature. They are all operations applied to the file resource. They can be called "functions". For example, a file has the "opened" function, it has the "read" function, but note that they are not actually a file function.
According to the original statement, the file should be mapped into a structure, such as file. Then, the four operations above should be mapped into four functions, and the functions of namespace should be reused, as follows:
Namespace ofile
Bool open (file &,... ); Bool close (file &,... );
Bool read (file &,... ); Bool write (file &,... );
The above namespace ofile indicates that all the four functions are file operations, but each of the four functions has a file & parameter. Recall that non-static member functions all have a hidden parameter this, so an amazing idea came into being.
Think of all the sets of operations on a certain resource as a resource and map it into a class. The object of this class is the operation on an object. This method is called encapsulation, the class is called a packaging class or an encapsulation class. Obviously, the packaging class maps "operations on a certain resource" and is an abstract concept, that is, the packaging class objects are all stateless objects (it should be a stateless object logically, however, if there is a link between multiple operations, there may still be states, but its semantics also changes accordingly. For example, if you have another cfile: flush member function that is used to refresh the buffer content, there will be at least one status-buffer, and you can also have a status record that has already called cfile: write, if not, you do not need to refresh it ).
Now we should be able to understand the meaning of encapsulation. Encapsulates operations on a certain resource into a class. This packaging class maps not to a "noun concept" defined in the world ", it is an abstract concept defined by the "verb concept" or "operation on a certain concept" in the world. Since a packaging class encapsulates operations on a certain resource, the packaging class object must have an attribute to indicate the object to be operated. For cfile in MFC, cfile :: m_hfile member variable (handle type), which is read in the main operation process of the packaging Class Object (cfile: Read and cfile: Write.
What are the benefits? Encapsulation provides a means to convert part of the "verb concept" in the world into objects, makes the program architecture simpler (multiple "verb concepts" are changed into a "noun concept", reducing the number of "verb concepts ), more object-oriented programming ideas.
However, the packaging objects and encapsulated objects should be differentiated. The packaging object is only a shell, and the encapsulated object must be a stateful object, because the operation is to change the state of the resource. For cfile, The cfile instance is a packaging object, which maintains a pair of encapsulated objects-file kernel objects (resources defined in Windows operating systems, represented by handle instances) -- reference in cfile: m_hfile. Therefore, the packaging objects are independent of the encapsulated objects. Cfile A; in this case, the value of A. m_hfile is 0 or-1, indicating that the referenced object is invalid. Therefore, if a. Read (... ); Will fail, because the resources applied by the operation are invalid. In this case, you should first call A. Open (... ) To bind a to a specific file kernel object, and call a. Close (... ); Will be unbound. Note cfile: After the close call, only the binding is unbound. This does not mean that a has been destroyed, because a maps not a file kernel object, but a packaging object for file Kernel Object operations.
If you think about it, you will find that Tigers can eat rabbits and rabbits can be eaten, so here it should be that the tiger has a function to "eat rabbits" or multiple rabbit packaging classes to encapsulate the "eat rabbits" operation? In fact, there is no problem. "Tigers eat rabbits" and "rabbits are eaten" are totally different operations. The former involves two types of resources, and the latter only involves one type of resources, therefore, the two can be implemented at the same time, depending on their semantics in the corresponding world. For the real world, it can be simply said that tigers have a "eat" function and can eat "meat", while animals inherit from "meat" and "autonomous initiative" in multiple ways, rabbits inherit from animals. Here, there is a class called "autonomous initiative", which means that an animal is conscious and can act on its own. In C ++, it is represented by a class with a member function, indicating that a function can be operated, however, the Radio also has functions such as adjusting the station. Is it hard to say that the radio can also be operated by itself ?! This is the significance of the world-operation.

Method-the world-driven approach

Algorithms are methods. As mentioned earlier, they are composed of operations and operated resources, that is, resource types and operation types. Method indicates how to use the operations defined in the world, but not to execute them. As described above, the world can only consist of objects. when an object is generated, a copy of the state and attributes of all objects in the world, that is, member variables, it is called a snapshot of the state of the world, and the change of the state of the world is called the operation of the world. The state of the world is the state and attribute of all objects in the world. To change the state of the world, you must perform operations defined in the world. However, you can only point out how to execute it to change the state of the world, in this way, the world can be driven even if the operations defined by the world are executed.
The more I said above, the more I felt, what is the significance? Consider why we need to propose the concept of the world. The world is a collection of rules that we want to solve by programming. The design program is to design the arguments that describe the world, and then design algorithms, compile code, and execute code on this argument, the result is displayed. "Get result "?! What is the result? That is, a part of the world's final state, such as finding the value of the circumference rate. This is actually the purpose, but it is worth noting that this is not the purpose. The code execution process is often another purpose, such as saving data to a file, opening, editing, and saving the file. This purpose does not care about the final state of the world. The changing process of the state of the world, that is, the operation of the world, is another very popular purpose-electronic games.
Whatever the purpose, we need to change the state of the world. To drive the operation of the world, we must make the operations defined in the world run. This can only be achieved through methods. Therefore, when designing algorithms, it determines the way to drive the world.
For the first purpose above, the operation is continuously executed until the end of the world because it depends on the final state of the world. The example of a merchant crossing the river in C ++ from scratch (8) is called printf to print the result and end after the result is obtained through an algorithm. For the second purpose, because the execution process is required, the operation can be executed continuously. However, this purpose usually requires the user to decide when to execute and execute more than one piece of code. For example, after the file is opened, the user does not edit the code until the user gives a command (by keyboard, mouse, or other input, the user may randomly perform different editing operations and decide whether to save the file. This kind of world is driven by users. The algorithm here is only how to open, save files, and edit data. However, since the algorithm is determined to be a user-driven method, the algorithm must be modified to implement this driver method. Let's look at the third purpose. If we want to change the state of the world, we can either. However, it is obvious that the first change process cannot be sustained, and the continuous execution is complete. The second is user-driven, which is too troublesome. Therefore, there is often a loop. In game programming, it is generally called the main loop. Each loop changes the state of some objects in the world according to certain rules. This is called a loop-driven approach. Every cycle is called an object with a changed state as autonomous initiative, as mentioned above. In addition, it is not called an example of self-initiative, as mentioned above. Similarly, the algorithm in the Game still does not involve the loop driving method mentioned above, so you must modify the algorithm to implement the Loop Driving Method.
So many of the above are just to illustrate that we can no longer compile the program as described in "C ++ from scratch (8)". The following is a method.
1. When you get a problem, you should also get the algorithm of the problem (the programmer is not a scientist), or the client will give it or get it directly because it is too simple.
2. Abstract The problem to design its description, that is, the argument mentioned above, that is, the so-called program design.
3. Describe the previously presented algorithms with the newly designed arguments and improve the arguments (because the algorithms may bring some concepts that do not exist in the world ).
4. It is up to you to decide which world-driven approach to use, and to improve algorithms and arguments (the World-driven approach may also bring in concepts that did not exist ).
5. Continue with the three steps proposed in C ++ from scratch (8.
The steps provided here are general. When the world of the program is too complex, the above step 2nd will need to be subdivided. First, design the large framework of the program, then design the interface, and finally decide the specific application of the interface. The interface will be described in "C ++ from scratch (18)". The interface design method mentioned here is not managed, but is simplified, it is not necessary. Because it has nothing to do with this series, it is not listed here.
This article puts forward several abstract concepts with few examples, and only describes some issues that should be paid attention to when designing with object-oriented ideas. The fewer concepts mentioned in the world, the better, but I didn't say how to decide what concepts are there. In this regard, we can see from the previous questions about tigers eating rabbits that, because the problem is a problem in the real world, we only need to map concepts in the real world, remove or simplify some secondary concepts (in fact, this is the embodiment of semantics on the other hand ). In the next article, we will give a simple example based on the object design for the five programming steps proposed in this article to illustrate how to write object-oriented programs.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.