[Object-Oriented Programming]
When I write an article for the first time, there must be hundreds of errors. I just want to learn some ideas about object-oriented programming.
It can be of little use to people who share common interests, but it cannot be helpful.
[Title Description in the text]
1. Variable: This Title includes two parts.
Built-in instances (such as int, float, and char)
User-Defined instance types (such as class, union, and struct)
At the same time, this article also generally calls variables and functions as Program Members.
2. parent class/subclass: the inherited class is the parent class, And the inherited class is the Child class.
3. Object: This article refers to an instance of a class)
* *********************************** Basic part ** ************************
[Memory Object Model overview]
This article mainly discusses the performance of polymorphism at the language level, so I am not going to do it too deeply here.
The discussion is just for the purpose of this Article, to make some specific instructions, conceptual interpretation of the Memory Object Model.
C ++ class member functions. We can regard them as functions in C language. It is only performed by the compiler.
Some related processing to prevent name conflicts. In addition to static member functions in the class, these functions
A parameter (this pointer) is added to a common C function because it can process member variables in an object.
So we didn't see anything related to member functions in the Class Object Memory layout.
Of course, if the virtual function appears in the class declaration or the class inheritance level, you will see it in the memory layout.
There is an existence of something called "virtual function finger table. When we do not use a single inheritance, the situation becomes
This is even more complex. As mentioned above, this article mainly explains how to use the language at the language usage level,
Therefore, I will not discuss more about the memory layout here. For more information, see
Object-Oriented Programming books.
[Program Member lifecycle overview]
Storage space: defines the storage format of Program Members in programs (or translation units). As we often see,
There are many program global variables, program local variables, and so on. At the same time, this concept determines the life of variables.
Cycle. This concept mainly points out the memory part of the variable program, such as the program data segment,
Program stack and so on.
Life cycle: A Program Member can be used during that period. Simply put, a Program Member has been running for a period of time.
It can be referenced. We will refer to this period as the life cycle of this Member.
Visibility: interfaces (classes and functions) that can Reference Program Members
Link mode: Indicates whether a definition member can be used by another Translation Unit of the program.
* *********************************** Theoretical part ** ************************
[Three important conclusions]
To illustrate the introduction class:
Class cbase
{
Public:
Basefunc (){}
};
Class cderived: Public cbase
{
Public:
Derifunc (){}
};
☆Conclusion 1 ☆. if we use a [parent class pointer] pointer to point to a [subclass object], then through pointer we
Only functions defined in the parent class (class definition) can be called.
We write as follows:
Cbase * pbase;
Although we can use the pointer pbase to point to the cderived object
Pbase is a cbase type pointer, so we can only call (or reference)
Basefunc (), cannot be derifunc ().
☆Conclusion 2 ☆. if we use a [subclass pointer] to point to a [parent class object], we must use rtti before referencing a function.
Determine the specific type of the pointer pointing to the object. That is to say, make an explicit shape conversion.
This is a tough practice for programmers.
Cderived * pderi;
Cderived * pderi;
Cbase abase ("Jason ");
Pderi = & abase;
☆Conclusion 3 ☆. if both the parent class and subclass define [member functions with the same name], call
The resolution for referencing a member function must be based on the pointer type (note that it is not the actual type of the pointer pointing to the object)
To determine which function we reference. In fact, this conclusion is the function blocking function. This conclusion is very important,
This is because no matter whether it is a virtual function or not, this conclusion is highly lethal.
Explain this conclusion.
************************************ Interpretation Section ** ************************
☆Conclusion 1 ☆:
Why? Let's take a look at the next example to understand why Language designers adopt such a strategy?
# Include <iostream. h>
# Include <stdio. h>
Class classa
{
Public:
Int m_data1;
Void func1 (){}
Void func2 (){}
Virtual void vfunc1 (){}
Virtual void vfunc2 (){}
};
Class classb: Public classa
{
Public:
Int m_data2;
Void func2 (){}
Void func3 (){}
Virtual void vfunc1 (){}
};
When we write such a function;
What are the problems with the function implementation?
Void change (classa & Ca)
{
CA. func1 ();
CA. func2 ();
// Ca. func3 ();
CA. vfunc1 ();
CA. vfunc2 ();
}
When we call a function like this:
Classa CA;
Classb CB;
/*
Call Description: When we call this method, we should all be very clear about the discovery.
The func3 () function cannot be called, because this function is fundamental in classa.
It does not exist. It's easy, but complicated problems are simple,
Let's continue with the following example:
*/
Change (CA );
/*
You may say that you can call the func3 () function.
There is a function named func3 (), but we still cannot use the above function
Why does it call him? Please refer to my explanation below
*/
Change (CB );
/*
Because we use a parent class to reference the type of a subclass.
From the Implementation Details of functions, our goal is to achieve
Polymorphism, because we can know the function parameters when using the function.
Reference refers to the real type of the object, which may be classa or classb,
Of course, we can't call the func3 () function rashly. We
In this way, the implementation function will be blocked in the compiler.
☆Conclusion 2 ☆
This conclusion is a programmer's programming capability problem, because the language provides flexibility,
How to use it is a programmer's business. If you do not understand the language well
The code we write is often prone to problems. We can only blame ourselves for this.
Do not speak this language badly.
**************** ***********
Many languages are simple and concise. Here is a not very vivid example,
After reading this example, I don't know what you think about the so-called concise language.
What are the changes. Haha ~~~~
I often talk to people about such a company's lack of freedom, which seriously affects their creativity.
Have you ever thought about these things? In my understanding, if this company changes to a relatively free company,
It is reasonable to say that his creativity should be able to be released by a certain Program (that is, to play it out ).
This is the benefit of degrees of freedom from small to large.
At the same time, because we still think that we are strict with our own people, even if he is at a great degree of freedom
Space can also be a good grasp of their own direction.
Well, the rest time is almost over. Now back to the topic, one that gives programmers great freedom
Language, which is called a language with high flexibility. In such a language environment
We can make good use of this flexibility and sometimes cause errors, but we should not blame the language itself,
Only one thing we need to do is strive to improve our own level.
The language with Low Degrees of Freedom is lost.
Some are unlikely. However, when we want to gain a low degree of freedom in an environment with a high degree of freedom
As long as you strictly require yourself.
The above nonsense is based on programmers, programmers, and programming machines.
No matter how software is produced (at least within a few years), like in the traditional production industry.
It has entered the "People management" (Knowledge Management) era.
**************************************** ******************
☆Conclusion 3 ☆
Speaking of this conclusion, it is actually the mask problem in C ++ that is in the same name as override and overload.
With the help of the above analysis, we can understand this problem in one breath.
I hereby describe this example and explain it in reference to <strong tive C ++>.
However, some of my instructions are added here, which makes it easy to understand.
Let's look at an example that may drive you crazy.
Class base {
Public:
Void F (const base & base ){}
Virtual void F (int x ){}
};
Class derived: public base {
Public:
Virtual void F (double * PD );
};
Derived * Pd = new derived;
Pd-> F (10); // error!
Function blocking occurs here. If you are not clear about it, please take a look at Conclusion 3.
This is not reasonable, but arm provides an explanation for this behavior. Suppose you really want to call the version in derived when calling F, but you accidentally use the wrong parameter type. Let's further assume that derived is at the lower layer of the hierarchy. You don't know that derived indirectly inherits a base class baseclass, and baseclass declares a virtual function f With the int parameter. In this case, you will inadvertently call baseclass: F, a function that you do not even know it exists! When a large class hierarchy is used, such errors often occur. To prevent this problem, stroustrup decides to hide the base class members by name.
By the way, if you want derived users to access base: F, it is easy to use a using declaration:
Class derived: public base {
Public:
Using Base: F; // introduce base: F
// Derived Space Range
Virtual void F (double * PD );
};
Derived * Pd = new derived;
Pd-> F (10); // correct, call base: F
For compilers that do not yet support using declarations, another option is to use inline functions:
Class derived: public base {
Public:
Virtual void F (int x) {base: F (x );}
Virtual void F (double * PD );
};
Derived * Pd = new derived;
Pd-> F (10); // correct, call derived: F (INT ),
// Indirectly called base: F (INT)