Analysis of the implementation mechanism of the polymorphism of C + +
1. Polymorphism and Virtual functions
#include <iostream.h> class animal{public : void sleep () {cout <<" an iMAL Sleep " <<endl; } void Breathe () {cout << "animal Breathe" <<endl; }}; class fish:public animal{ public : void Breathe () {cout <<" fish Bubble " <<endl; }}; void Main () {fish FH; Animal *pan=&fh; Pan->breathe ();}
Attention. Virtual functions are not defined in the program.
What is the result of the program execution? The answer is output: animal breathe
We first defined a fish class object FH in the main () function. Then we define a pointer variable pan to the animal class and assign the FH's address to the pointer variable pan. The variable is then used to call Pan->breathe (). Many students often confuse this with C + + polymorphism, feeling that FH is actually a fish class object. It should be called the Fish Class Breathe (), output "fish bubble", and the result is not. Here are two ways to tell why.
1, compile the angle. When compiling, the C + + compiler determines the address of the function that each object invokes. This is called early binding (early binding) when we assign the address of the Fish class's object FH to the pan. The C + + compiler makes type conversions. At this point the C + + compiler feels that the variable pan holds the address of the animal object.
When executing pan->breathe () in the main () function, the call is of course the breathe function of the animal object.
2, the angle of the memory model. We have given the fish object memory model, for example, as seen in the
When we construct objects of fish class. The first thing to do is to call the constructor of the animal class to construct the object of the animal class, and then call the fish class's constructor to complete its own part of the construct, thus stitching up a complete fish object. When we convert a fish class object to a animal type, the object is thought to be the upper half of the entire memory model of the original object. That is, the "animal" of the object in Figure 1-1.
Then, when we use a type-converted object Pointer to invoke its method, it is, of course, the method in memory where it is called. So. Output animal breathe, it is logical. The result of the
preceding output is that the compiler, at compile time, has determined the address of the function called by the object. To solve the problem, use late binding (late binding) technology. When the compiler uses late binding. The will then be executed to determine the type of object and the correct calling function. to let the compiler use late binding. Use the virtual keyword when declaring a function in a base class, which we call a virtual function. Once a function is declared as virtual in the base class, the function is virtual in all derived classes and does not need to be explicitly declared as virtual.
#include <iostream.h> class animal{public : void sleep () {cout <<" animal sleep " <<endl;} virtual void Breathe () {cout <<" animal Breathe " <<endl; }}; class fish:public animal{ public : void Breathe () {cout <<" fish Bubble " <<endl;}}; void Main () {fish FH; Animal *pan=&fh; Pan->breathe ();}
You can execute the program again and you will find that the result is "fish bubble", which is called the correct function based on the type of object.
So when we declare breathe () as virtual. What's going on behind the scenes?
When the compiler is compiled. Found a virtual function in the animal class. At this point the compiler creates a virtual table (that is, vtable) for each class that includes a virtual function, which is a one-dimensional array that holds the address of each virtual function in the array. For example 1-2, the animal and fish classes both include a virtual function breathe (), so the compiler creates a dummy table for all two classes, for example, as seen in:
So how do you locate a virtual table? The compiler also provides a virtual table pointer (that is, vptr) for each class object that points to the virtual table of the class to which the object belongs. When the program executes. Initialize the vptr according to the type of the object, so that vptr correctly points to the virtual table of the owning class, so that when the virtual function is called, the correct function is found on the line. For example 1-2 of the program, because the pan actually points to the object type is fish, so vptr points to the vtable of the fish class. When Pan->breathe () is called, the Breathe () function of the fish class is found based on the address of the function in the virtual table.
It is because the virtual function that each object calls is indexed by the virtual table pointer, it is important to determine the correct initialization of the virtual table pointer. In other words, the virtual table pointer is not initialized correctly. We are not allowed to call virtual functions. So when is the virtual table pointer. or where to initialize it?
The answer is to create the virtual table in the constructor and initialize the virtual table pointer .
Remember the order in which constructors are called. When constructing a subclass object, the constructor of the parent class is called first, at which point the compiler simply "sees" the parent class, and does not know if there are successors later, it initializes the virtual table pointer of the parent class object. The virtual table pointer points to the virtual table of the parent class.
When the constructor of a subclass is executed, the virtual table pointer of the subclass object is initialized, pointing to its own virtual table .
For example 2-2, when the FH object of the fish class is constructed, the internal virtual table pointer is initialized to a virtual table that points to the fish class. After the type conversion, call Pan->breathe (), because the pan actually points to the object of the fish class. The virtual table pointer inside the object points to the virtual table of the fish class, so the breathe () function of the fish class is finally called.
Note: For virtual function calls, there is a virtual table pointer inside each object. The virtual table pointer is initialized to the virtual table of this class . So in a program, no matter how your object type is converted, the virtual table pointer inside the object is fixed . So, the ability to implement dynamic object function calls, which is the principle of C + + polymorphism implementation.
Summary (the base class has virtual functions):
1. Each class A has a virtual table.
2, the virtual table can inherit, assuming that the subclass does not override the virtual function, then the sub-class virtual table will still have the address of the function, just the address of the base class is the virtual function implementation. Assuming that the base class has 3 virtual functions, there are three items (virtual function addresses) in the virtual table of the base class, and the derived classes have virtual tables. At least three items, assuming that the corresponding virtual function is overridden, the address in the virtual table will change , pointing to its own virtual function implementation. Assume that a derived class has its own virtual function. The item is then added to the virtual table.
3. The order of the virtual function address in the virtual table of the derived class and the order of the virtual function address in the virtual table of the base class are the same.
Implementation mechanism of c++--polymorphism