Preface
The function of virtual function in C + + is mainly to realize the mechanism of polymorphism. About polymorphism, in short, is to use the pointer of the parent type to an instance of its subclass, and then call the member function of the actual subclass through the pointer to the parent class. This technique allows the pointer of the parent class to have "multiple forms," which is a generic technique. The so-called generic technology, plainly is to try to use immutable code to implement the variable algorithm. For example: template technology, RTTI technology, virtual function technology, or try to do at compile-time resolution, or try to do run-time resolution.
On the use of virtual functions, I do not do too much elaboration here. You can take a look at the relevant C + + books. In this article, I just want to from the virtual function of the implementation mechanism for everyone a clear analysis.
Of course, the same article on the internet also appeared some, but I always feel that these articles are not very easy to read, large sections of code, no pictures, no detailed instructions, no comparison, no extrapolate. Not conducive to learning and reading, so this is the reason I want to write this article. I also hope that members will give me more advice.
Let's go to the world of virtual functions together.
virtual function Table
People who know C + + should know that virtual functions (virtual function) are implemented by a virtual function table (virtual table). Referred to as v-table. In this table, the master is the Address table of a virtual function of a class, which solves the problem of inheritance and coverage, and ensures that the actual function of the real response is true. Thus, in an instance of a class with a virtual function, the table is allocated to the memory of the instance. So, when we manipulate a subclass with a pointer to a parent class, the virtual function table is important, and it is like a map that indicates the function that is actually supposed to be called.
Here we look at this virtual function table. The compiler for C + + should be to ensure that the pointer to the virtual function table exists at the very front of the object instance (this is to ensure the highest performance of the virtual function table-if there are multiple layers of inheritance or multiple inheritance). This means that we get the virtual function table through the address of the object instance, and then we can iterate through the function pointer and call the corresponding function.
Listen to me so much, I can feel that you may be more disoriented now than before. No problem, the following is a practical example, I believe that the smart you see it.
Let's say we have a class like this:
Class Base {
Public
virtual void F () {cout << "base::f" << Endl;}
virtual void g () {cout << "base::g" << Endl;}
virtual void H () {cout << "base::h" << Endl;}
};
According to the above, we can get the virtual function table through the example of base. The following is the actual routine:
typedef void (*fun) (void);
Base b;
Fun pfun = NULL;
cout << "virtual function table Address:" << (int*) (&b) << Endl;
cout << "virtual function table-First function address:" << (int*) * (int*) (&b) << Endl;
Invoke the
Pfun = (Fun) * (int*) * (int*) (&b));
Pfun ();
The actual operating results are as follows: (Windows xp+vs2003, Linux 2.6.22 + GCC 4.1.3)
virtual function table Address: 0012FED4
virtual function table-First function address: 0044f148
Base::f
With this example, we can see that we can get the address of the virtual function table by forcing the &b into int *, and then we can take the address of the first virtual function again, that is base::f (), which is validated in the above program (Put int* Force to a function pointer). With this example, we can see that if you want to invoke Base::g () and Base::h (), the code is as follows:
(Fun) * ((int*) * (int*) (&b) +0); Base::f ()
(Fun) * ((int*) * (int*) (&b) +1); Base::g ()
(Fun) * ((int*) * (int*) (&b) +2); Base::h ()
This time you should understand it. What the. Still a little dizzy. Also, such a code looks too messy. No problem, let me draw a picture to explain. As shown below:
Note: In the above diagram, I add a node to the end of the virtual function table, which is the ending node of the virtual function table, just like the Terminator "/0" of the string, which flags the end of the virtual function table. The value of this ending flag is different under different compilers. Under Winxp+vs2003, this value is null. and under Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3, this value is 1, which means that there is also the next virtual function table, and if the value is 0, the last virtual function table is represented.
Below, I will explain the appearance of the virtual function table in "No overlay" and "overwrite" respectively. It is meaningless not to overwrite the virtual function of the parent class. The main purpose of my story about not covering is to give a comparison. In comparison, we can know more clearly the specific implementation within it.
General Inheritance (no virtual function overrides)
Next, let's look at what the virtual function table is like when inheriting. Suppose you have an inheritance relationship as shown below:
Note that in this inheritance relationship, subclasses do not have functions that overload any of the parent classes. Then, in an instance of a derived class, its virtual function table looks like this:
For example: derive D; The virtual function table is as follows:
We can see the following points:
1 virtual functions are placed in the table in the order in which they are declared.
2 The virtual function of the parent class is in front of the virtual function of the subclass.
I believe that smart you can certainly refer to the previous program, to write a program to verify.
General inheritance (with virtual function overrides)
It is obvious that the virtual function of the parent class is overridden, otherwise the virtual function becomes meaningless. Next, let's take a look at what it would look like if a virtual function in a subclass overloaded the virtual function of the parent class. Suppose we have one of these inheritance relationships.
In order for you to see the effect of being inherited, in the design of this class, I covered only one function of the parent class: F (). Then, for an instance of a derived class, its virtual function table would look something like the following:
We can see the following points from the table,
1 the covering F () function is placed in the position of the original parent virtual function in the virtual table.
2 functions that are not covered are still.
In this way, we can see that for programs like the following,
Base *b = new Derive ();
B->f ();
The position of the F () of the virtual function table in the memory of B is already replaced by the Derive::f () function address, so the derive::f () is invoked when the actual call occurs. This enables polymorphism.