How to implement the polymorphic mechanism of C + +, the mechanism of running polymorphism is to add the virtual keyword in front of the function of the base class, overriding the function in the derived class, and the runtime will invoke the corresponding function based on the actual type of the object.
Realization and principle of C + + polymorphism
C + + polymorphism is summed up in a nutshell: By adding the virtual keyword to a function in the base class, overriding the function in a derived class, the runtime will invoke the corresponding function based on the actual type of the object. If the object type is a derived class, the function of the derived class is called, and if the object type is a base class, the function of the base class is called
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, and 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 a multi-interface implementation, is the core of object-oriented, divided into the polymorphism of the class and the polymorphism of the function.
4: Polymorphism is implemented by virtual function, which combines dynamic binding.
5: pure virtual function is virtual function plus = 0;
6: Abstract class refers to a class that includes at least one pure virtual function.
Pure virtual function: virtual void fun () = 0; abstract Class! This function must be implemented in a subclass, that is, there is a name first, no content, and the content is implemented in the derived class.
Let's look at an example first.
#include <iostream> #include <stdlib.h>using namespace std; Class Father{public: void Face () { cout << "Father's face" << Endl; } void Say () { cout << "Father Say hello" << endl; }}; Class Son:public Father{public: void Say () { cout << "Son Say hello" << endl; }; int main () { son son; Father *pfather=&son; Implicit type conversion Pfather->say (); return 0;}
The result of the output is:
Father Say hello
We first defined a son class in the main () function, and then defined a pointer variable pfather to the Father class, and then called Pfather->say () with that variable. It is estimated that many people tend to confuse this with C + + polymorphism, Think son is actually the son class object, should be called son class say, output "son say hello", but the result is not.
From a compilation point of view:
When compiling the C + + compiler, to determine the address of the function (non-virtual function) called by each object, which is called early binding, when we assign the address of son to Pfather, the C + + compiler makes a type conversion, at which point C + + The compiler thinks that the variable pfather is the address of the Father object, and when it executes Pfather->say () in the main function, the Say function of the Father object is of course called.
From the memory point of view
The memory model of the Son class object such as
When we construct the object of the son class, we first call the constructor of the father class to construct the object of the Father class, and then call the son class's constructor to complete the construction of its own part, thus stitching up a complete son class object. When we convert the Son class object to the Father type, the object is considered to be the upper part of the entire memory model of the original object, that is, the "father of the memory" of the object, so when we use the type-converted object Pointer to invoke its method, of course, it is called in the memory of its method, Therefore, the output "Father Say Hello", it is also logical.
As many people think, in the code above, we know that Pfather actually points to the son class object, and we want the result of the output to be the say method of the son class, so it is necessary to use the virtual function in the thought of achieving this result.
The result of the previous output is because the compiler at the time of compilation, has determined the address of the function called by the object, to solve this problem is to use late binding, when the compiler uses late binding, will be at run time to determine the type of the object and the correct call function, but to let the compiler use late binding, To use the virtual keyword when declaring a function in a base class, such a function is called a virtual function, and once a function is declared as virtual in the base class, the function is virtual in all derived classes, and it does not need to be explicitly declared as virtual.
Change the code a little bit and look at the results of the run
#include <iostream> #include <stdlib.h>using namespace std; Class Father{public: void Face () { cout << "Father's face" << Endl; } virtual void Say () { cout << "Father Say hello" << endl; }}; Class Son:public Father{public: void Say () { cout << "Son Say hello" << endl; }; int main () { son son; Father *pfather=&son; Implicit type conversion Pfather->say (); return 0;}
Operation Result:
Son Say hello
We find that the result is "Son say hello", which is called the correct function based on the type of object, so what happens behind us when we declare say () as virtual.
At compile time, the compiler discovers that there are virtual functions in the Father class, at which point the compiler creates a virtual table (that is, vtable) for each class that contains the virtual function, which is a one-dimensional array in which the address of each virtual function is stored.
So how do you locate a virtual table? The compiler also provides a virtual table pointer (that is, vptr) for each object, which points to the virtual table of the class to which the object belongs, initializes the vptr according to the type of the object when the program is run, so that vptr correctly points to the virtual table of the owning class, so that when the virtual function is called, it can find the correct function. For the second code program, because Pfather actually points to the type of object that is son, vptr points to the vtable of the son class, and when Pfather->son () is called, the Say () function of the Son 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 very important to determine the correct initialization of the virtual table pointer, in other words, we can not call virtual function before the virtual table pointer is not properly initialized, then when or where is the virtual table pointer initialized?
The answer is to create the virtual table in the constructor and initialize the virtual table pointer, when constructing the subclass object, the constructor of the parent class is called, at which point the compiler only "sees" the parent class, does not know if there is any successor, 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.
Summary (the base class has virtual functions):
1: Each class has a virtual table
2: Virtual tables can inherit, if the subclass does not override the virtual function, then there will still be the address of the function in the virtual table of the subclass, except that the address points to the virtual function implementation of the base class, and if the base class has 3 virtual functions, then there are three items (virtual function addresses) in the virtual table of the base class, and the derived class will be empty, If the corresponding virtual function is overridden, the address in the virtual table will change, pointing to its own virtual function implementation, and if the derived class has its own virtual function, the item will be added in the virtual table.
3: The order of the virtual address in the virtual table of the derived class is the same as the virtual function address in the virtual table of the base class.
This is the C + + polymorphism, when the C + + compiler at compile time, found that the Father class say () function is a virtual function, this time C + + will use late binding technology, that is, the compiler does not determine the specific call function, but at run time, depending on the type of object to confirm which function is called, This ability is called C + + polymorphism, and when we do not add the virtual keyword before the Say () function, the C + + compiler determines which function is called, which is called early binding.
The polymorphism of C + + is realized by late binding technology.
C + + polymorphism is summed up in a nutshell: Before the function of the base class with the virtual keyword, override the function in a derived class, the runtime will invoke the corresponding function according to the actual type of the object, if the object type is a derived class, call the function of the derived class, if the object type is a base class, call the base class function.
A virtual function is defined in a base class to not determine the specific behavior of its derived class, for example:
Define a base class: Class Animal//animal, its function is breathe ()
Then define a class fish//fish. Its function is also breathe ()
Define a class Sheep//sheep, and its function is also breathe ()
The fish,sheep is defined as a derived class of animal, but fish is different from the breathe of sheep, one is to breathe through water in water, one to breathe directly, so the base class cannot determine how to define breathe, so only one virtual is defined in the base class. Breathe, it is an empty virtual function, the specific function is defined in the subclass, the program is generally run, find the class, if it has a base class, then find its base class, and finally run the function in the base class, then it found in the base class is the virtual identity of the function, It will go back to the sub-class to find the same name function, the derived class is also called the subclass, the base class is also called the parent class, this is the creation of virtual function, and the embodiment of the polymorphism of the class.
Polymorphism here refers to the polymorphism of a class.
The polymorphism of a function is a function that is defined as a function of several different parameters. When you call this function, different functions with the same name are called.
In general (no virtual functions are involved), when we invoke a function with a pointer/reference, the function being called depends on the type of the pointer/reference.
When designing to polymorphism, virtual functions and dynamic bindings are used, at which point the call is not determined at compile time but at runtime. Do not consider the pointer/reference type alone but look at the type of the pointer/reference object to determine the invocation of the function, based on the address of the function in the virtual table pointed to by the virtual pointer in the object, determining which function to call
Now let's look at an example of C + + polymorphism, and look at the output:
#include <iostream> #include <stdlib.h>using namespace std; Class CA {public: void F () { cout << "CA f ()" << Endl; } virtual void ff () { cout << "CA ff ()" << Endl; f (); } }; Class Cb:public CA {public: virtual void F () { cout << "CB f ()" << Endl; } void ff () { cout << "CB ff ()" << Endl; f (); Ca::ff (); } }; Class Cc:public CB {public: virtual void F () { cout << "C f ()" << Endl; }}; int main () { CB B; CA *ap = &b; CC C; CB &br = c; CB *BP = &c; Ap->f (); cout << Endl; B.f (); cout << Endl; BR.F (); cout << Endl; Bp->f (); cout << Endl; Ap->ff (); cout << Endl; Bp->ff (); cout << Endl; return 0; }
Output Result:
ca F () CB F () c F () C F () CB FF () CB F () CA ff () CA f () CB FF () C f () CA ff () CA f ()