C + + polymorphism is summed up in the following sentence: In the base class of the function plus the virtual keyword, in a derived class to override the function, the runtime will be based on the actual type of the object to call the corresponding function. If the object type is a derived class, the function of the derived class is called, and the function of the base class is called if the object type is a base class
1. A function declared with the virtual keyword is called a virtual function, and a virtual function is definitely a member function of a class.
2. A class with a virtual function has a one-dimensional virtual function table called a virtual table. The object of the class has a virtual pointer to the beginning of the virtual table. A virtual table corresponds to a class, and a virtual table pointer corresponds to an object.
3. Polymorphism is an interface with multiple implementations and is the core of object-oriented. It is divided into the polymorphism of the class and the polymorphism of the function.
4. Polymorphism is implemented with virtual functions, combined with dynamic binding.
5. Pure virtual function is a virtual function plus = 0.
6. An abstract class refers to a class that includes at least one pure virtual function.
pure virtual function:virtual void breathe () = 0, or abstract class. This function must be implemented in subclasses! That is, the first name, no content, in the derived class implementation content!
Let's take a look at an example:
The code is as follows:
#include <iostream.h>
class animal
{public
:
void Sleep ()
{
cout<<] Animal 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; Implicit type conversion
pan->breathe ();
}
Note that virtual functions are not defined in the program in example 1-1. Consider what the result of example 1-1 program execution is.
The answer is output: animal breathe
In the main () function we first define the object FH of a fish class, then define a pointer variable pan that points to the animal class, assign the FH address to the pointer variable pan, and then use the variable to invoke Pan->breathe (). Many students tend to confuse this with C + + polymorphism, thinking that FH is actually an object of fish, that it should be the breathe () of the Fish class, the "Fish bubble", and then the result is not. Here are two ways to tell the reason.
1, the angle of compilation
C + + compiler at compile time, to determine the address of a function called by each object (requiring this function to be a non-virtual function), which is called early binding (early binding), when we assign the address of a fish class to the pan, the C + + compiler does a type conversion, at which point C + + The compiler thinks that the variable pan holds the address of the animal object. When Pan->breathe () is executed in the main () function, the call is of course the breathe function of the animal object.
2, the angle of the memory model
We give the fish object memory model, as shown in the following figure:
When we construct the object of fish, we first call the constructor of the animal class to construct the object of the animal class, and then call the Fish class constructor to complete the construction of its own part, thus stitching together a complete fish object. When we convert an object of a fish class to a animal type, the object is considered to be the upper half of the entire memory model of the original object, which is the "Memory of the Animal object" in Figure 1-1. Then when we use the type-converted object Pointer to invoke its method, of course, it is also called in the memory of the method in which it resides. Therefore, the output animal breathe, it is logical.
As many of you think, in the example 1-1 program, we know that the pan actually points to the fish object, and we want the output to be the method of the fishes ' respiration, that is, the breathe method that calls it. This time, it is the turn of the virtual function.
The result of the preceding output is that the compiler has already determined the address of the function called by the object when compiling, and the late binding (late binding) technique will be used to solve the problem. When the compiler uses late binding, it will then determine the type of object and the correct invocation function at runtime. To get the compiler to use a late binding, it is necessary to declare the function in the base class using the virtual keyword (Note that this is a must, many students simply do not use a virtual function to write many of the wrong examples), such a function 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.
The following modifies the code in example 1-1 to declare the Breathe () function in the animal class as virtual:
The code is as follows:
#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; Implicit type conversion
pan->breathe ();
}
You can run the program again, and you'll 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 happens behind the scenes.
At compile time, the compiler discovers that there are virtual functions in the animal class, where the compiler creates a virtual table (that is, vtable) for each class that contains a virtual function, which is a one-dimensional array that holds the address of each virtual function in the array. For the program in example 1-2, the animal and fish classes all contain a virtual function breathe (), so the compiler creates a virtual table for all two classes (even if there is no virtual function in the subclass, but in its parent class, so does the subclass) as shown in the following figure:
So how to locate the virtual table. The compiler also provides a virtual table pointer (that is, vptr) for each class object, which points to the virtual table of the class to which the object belongs. When the program is run, the vptr is initialized according to the type of the object, allowing the vptr to correctly point to the virtual table of the owning class, so that when the virtual function is invoked, the correct function can be found. For the program in example 1-2, because the pan actually points to the type of object is fish, so the vtable of the fish class that vptr points to, when Pan->breathe () is invoked, the breathe () function of the fish class is found according to the function address in the virtual table.
It is because each object calls the virtual function is indexed by the virtual table pointer, it also determines the virtual table pointer correct initialization is very important. In other words, we cannot invoke a virtual function until the virtual table pointer is properly initialized. So when, or where, the virtual table pointer is initialized.
The answer is to create the virtual table and initialize the virtual table pointer in the constructor. Remember the order in which constructors are called? When you construct a subclass object, you first invoke the parent class's constructor, at which point the compiler only "sees" the parent class, does not know if there is a successor behind it, initializes the virtual table pointer of the parent class object, which 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 a fish class is constructed, its internal virtual table pointer is also initialized to a virtual table pointing to a fish class. After the type conversion, call Pan->breathe (), because the pan actually points to the object of the fish class, and the virtual table pointer inside the object points to the virtual table of the fish class, so the final call is the Breathe () function of the fish class.
Note: for virtual function invocations, there is a virtual table pointer inside each object that is initialized to the virtual table of this class. Therefore, in the program, no matter how your object type conversion, but the object inside the virtual table pointer is fixed, so it can implement dynamic object function call, this is the principle of C + + polymorphism implementation.
Summary (base class has virtual functions):
1. Each class has a virtual table.
2. The virtual table can inherit, if the subclass does not override the virtual function, then the subclass virtual table will still have the address of the function, but this address is to point to the virtual function of the base class implementation. If the base class has 3 virtual functions, then the base class of the virtual table has three items (virtual function address), derived classes will also have virtual table, at least three, if the corresponding virtual function is rewritten, then the address in the virtual table will change, pointing to its own virtual function implementation. If the derived class has its own virtual function, the item is added to the virtual table.
3. The virtual function addresses in the derived class's virtual table are arranged in the same order as the virtual functions in the base class's virtual table.
This is the polymorphism of C + +. When the C + + compiler found that the breathe () function of the animal class was a virtual function at compile time, C + + would use the late binding (late binding) technique. That is, the compiler does not determine the specific call function, but at runtime, based on the type of object (in the program, we pass the address of the Fish object) to confirm the invocation of which function, this ability is called C + + polymorphism. When we do not add the virtual keyword before the breathe () function, the C + + compiler determines at compile time which function is called, which is called early binding (early binding).
The polymorphism of C + + is realized by the late binding technology.
C + + polymorphism is summed up in the following sentence: In the base class of the function plus the virtual keyword, in a derived class to override the function, the runtime will be based on the actual type of the object to call the corresponding function. If the object type is a derived class, the function of the derived class is called, and the function of the base class is called if the object type is a base class.
A virtual function is defined in a base class in order to not determine the specific behavior of its derived classes. Cases:
Define a base class: Class animal//animals. Its function is breathe ()//breathing.
Define a class fish//fish. Its function is also breathe ()
Define a class Sheep//Sheep. Its function is also breathe ()
To simplify the code, define the Fish,sheep as a derived class of the base class animal.
However, fish is not the same as sheep's breathe, one is to breathe through water in water, and one is to breathe air directly. So the base class is not sure how to define breathe, so only a virtual breathe is defined in the base class, which is an empty virtual function. The functions in this class are defined separately in subclasses. When the program is running normally, it finds the class, if it has a base class, finds its base class, and then runs the function in the base class, it finds the function in the base class that is identified by the virtual, and it goes back to the subclass to find a function of the same name. Derived classes are also called subclasses. The base class is also called the parent class. This is the emergence of virtual functions, and the embodiment of class polymorphism (breathe).
Polymorphism here refers to the polymorphism of a class.
Function polymorphism refers to a function that is defined as a function of several different parameters, they are generally in the header file, when you call this function, for different parameters, you call different functions of the same name. Example: Rect ()//rectangle. Its arguments can be two coordinate points (point,point) or four coordinates (X1,Y1,X2,Y2), which is called the polymorphism of the function and the overload of the function.
The polymorphism of a class is implemented using virtual functions and deferred bindings. The polymorphism of a function is an overload of a function.
Normally (no virtual function is involved), when we call a function with a pointer/reference, the called function depends on the type of the pointer/reference. That is, if the pointer/reference is a pointer/reference to the base class object, the method of the base class is invoked; If the pointer/reference is a pointer/reference to a derived class object, then the method of the derived class is called, but if there is no such method in the derived class, it goes up to the base class to find the appropriate method. These calls are determined at compile time.
When designing to polymorphism, virtual functions and dynamic bindings are used, and calls at this time are not determined at compile time but at runtime. Instead of thinking about the type of pointer/reference alone, you can judge the invocation of a function by the type of the pointer/reference object, and determine which function to call based on the address of the function in the virtual table to which the virtual pointer is pointing.
Reproduced from: http://www.jb51.net/article/41809.htm