The virtual function is related to the polymorphism, and the polygon is connected to inheritance. Therefore, this article is in the inheritance level. Didn't inherit, nothing to talk about. Below is the understanding of the younger you're with a virtual function of C . First, what is a virtual function (if you don't know what the virtual function is, but I want to know, then you should start from here) simply, those who are modified by the Virtual keyword, are virtual functions. The function of virtual functions, explains with professional terminology is to achieve polymorphism (polymorphism), and polymorphism is to separate the interface and implementation; interpretation with the language is to implement a common method, but different from individual differences Strategy. Let's take a simple code Class a {public: void print () {cout << "this is a" <
Print (); p2-> print ();} Run a look at the results, 哟呵, look back, the result is two this is A. The problem is coming, P2 is clearly pointing to the Class B object but is the print () function called Class A, which is not the result we expect, then solve this problem, you need to use the virtual function Class A {public: Virtual Void Print () {cout << "this is a" <
Fun (); no doubt, call A :: Fun (), but A :: fun () is called? Is it directly jumped to the code of the function like a normal function? NO, in fact, first is to remove the value of VPTR, this value is the address of the VTBL, then according to this value to vtbl, because the function called the function A :: fun () is the first virtual function, so Tet the VTBL The value in the first slot, this value is the address of a :: fun (), and finally calls this function. Now we can see that as long as VPTR is different, the poby VTBL is different, and the different VTBL is equipped with a virtual function address of the corresponding class, so this virtual function can complete its task. And for Class A and Class B, where are their VPTR pointers stored? In fact, this pointer is placed in their respective instance objects. Since Class A and Class B have no data members, there is only one VPTR pointer in their instance objects. Through the above analysis, we now come to a piece of code to describe the simple model of this class with virtual functions. #include
Using namespace std; // Add above "virtual function sample code" to INT main () {void (*) (a *); a * p = new b; long lvptraddr; memcpy (& lvptraddr, p, 4) Memcpy (& Fun, Reinterpret_cast
(LVPTRADDR), 4); FUN (P); delete p; system ("pause");} Compile with VC or DEV-C , see if it is output 3, if not, then the sun will definitely be from Western side. Now step by step to analyze the void (* fun) (a *); this parameter defines a function pointer name called FUN, and there is a parameter of a A * type, this function pointer is used to save functions taken from VTBL. Address A * P = New B; I don't know much, forget it, don't explain this long lvptraddr; this long-type variable is used to save VPTR's value Memcpy (& lvptraddr, p, 4); Only the VPTR pointer in their instance objects, so we can restart the 4bytes memory in the 4bytes memory refer to in the LVPTRADDR, so the 4bytes content copied is the value of VPTR, that is, the address of VTBL now has VTBL. The address is, then we now take out the contents of the first slot in the first slot (& Fun, ReinterPret_cast (LVPTRADDR), 4); remove the contents of the first slot in the VTBL, and store it in the function pointer fun. It should be noted that the LVPTRADDR is the address of VTBL, but lvptradd is not a pointer, so we have to turn it into a pointer type FUN (P); here, the function in the function address just taken out is called, that is, call B: : fun () This function, maybe you find why there will be parameter P, when the class member function is called, there will be a THIS pointer, this P is the THIS pointer, just in the general call, the compiler is automatically handled. Moreover, it is necessary to handle it. Delete P; and System ("pause"); I don't know much, forget it, don't explain this, if you call B :: fun2 ()? Then take the value of the VTBL's second slot, Memcpy (& fun, reinterpret_cast)
(LVPTRADDR 4), 4); Why is it add 4? Since a pointer is 4Bytes, add 4. Or Memcpy (& Fun, Reinterpret_cast)
(LVPTRADDR) 1, 4); this is more in line with the usage of the array, because LVPTRADDR is turned into a long * type, so 1 is the length of the SIZEOF (long), starting with a piece of code #include
Using namespace std; class a {// virtual function sample code 2 public: Virtual void fun () {cout << "a :: fun" <
* fun) (); fun = & a :: fun2; (p -> * fun) (); delete p; system ("pause");} Can you estimate output results? If you estimate the result is A :: Fun and A :: Fun2, huh, please, congratulations, you have a circle. In fact, the real result is B :: Fun and B :: Fun2, if you don't want to see it. Give a prompt, & a :: fun and & a :: fun2 is the address that really gets the virtual function? First we go back to the second part, pass the paragraph actual code, get a "universal" method for obtaining virtual function addresses #include
Using namespace std; // Add above "virtual function sample code 2" Add above Void callvirtualfun (void * pthis, int index = 0) {void (* funptr) (void *); long lvptraddr; memcpy (& lvptraddr, pthis, 4); Memcpy (& Funptr, ReinterPret_cast (lvptraddr) index, 4); Funptr (PTHIS); // Call} int main () {a * p = new b; callvirtualfun (p); // call virtual function P- > fun () CallVirtualFun (p, 1); // Call the virtual function P-> FUN2 () System ("pause");} Now we have a "universal" CallVirtualFun method. What is the connection between this general method and the third part starting? Contact great. Since A :: Fun () and A :: Fun2 () are virtual functions, & a :: fun and & a :: fun2 get the address of the function, but a piece of code for a virtual function address, we The image is imaged as the CallVirtualFun. When compiling, the compiler is compiled, which is similar to the CallVirtualFun. When you call the virtual function, it is actually called the code similar to the CallVirtualFun code. After this code, after the virtual function address, finally call the virtual function, This really guarantees the polymorphism. At the same time, everyone said that the virtual function is low, the reason is that before calling the virtual function, the code to obtain the virtual function address is called. Last description: The code of this article can be compiled with VC6 and DEV-C 4.9.8, and there is no problem. Other compilers, the younger brother dare not guarantee. Among them, the ratio method can only be seen as a model because the low-level implementation of different compilers is different. For example, the THIS pointer, the DEV-C GCC is passed by pressing, as parameter passes, while the compiler of the VC is saved in ECX by the removal address. Therefore, these types of methods cannot be treated as a specific implementation. PS: The level of younger brother is really limited, whether it is technology, or language, if there is any problem in the text, welcome a prawn and rookie friends to pointed out. Bright ~~ the end