Document directory
- General inheritance (no virtual function overwrite)
- General inheritance (with virtual function overwrite)
- Multi-inheritance (no virtual function overwrite)
- Multiple inheritance (with virtual function overwrite)
- Security
In C ++, a virtual function is used to implement polymorphism. Specifically, the parent class Pointer Points to the subclass instantiation, and then the parent class pointer calls the member function of the actual subclass.
The virtual function is implemented through the virtual function table, for example:
Below, I will explain the virtual function tables for "No overwrite" and "Overwrite" respectively. It is meaningless to not override the virtual functions of the parent class. The reason why I want to talk about the situation without coverage is mainly to give a comparison. In comparison, we can better understand the specific internal implementation.
General inheritance (no virtual function overwrite)
Next, let's take a look at what the virtual function table looks like during inheritance. Assume there is an inheritance relationship as follows:
Note that in this inheritance relationship, the subclass does not overload any function of the parent class. In the instance of the derived class, the virtual function table is as follows:
The following table lists the virtual functions of instance: Derive d:
We can see the following points:
1) virtual functions are stored in the table in the declared order.
2) the virtual function of the parent class is prior to the virtual function of the subclass.
I believe that you can write a program for verification by referring to the previous program.
General inheritance (with virtual function overwrite)
Overwriting the virtual functions of the parent class is obvious. Otherwise, the virtual functions become meaningless. Next, let's take a look at what it will look like if there is a virtual function in the subclass that reloads the virtual function of the parent class? Suppose we have the following inheritance relationship.
In order to let everyone see the inherited effect, in the design of this class, I only covered a function of the parent class: f (). Then, the virtual function table of the instance of the derived class will look like the following:
We can see the following points from the table,
1) The f () function to be overwritten is placed at the original parent class virtual function in the virtual table.
2) The unoverwritten functions remain.
In this way, we can see the following program,
Base * B = new derive ();
B-> F ();
The F () Position of the virtual function table in memory referred to by B has been replaced by the derive: F () function address, so when the actual call occurs, it is derive :: F () is called. This achieves polymorphism.
Multi-inheritance (no virtual function overwrite)
Next, let's take a look at the multi-inheritance situation. Suppose there is an inheritance relationship of the following class. Note: The subclass does not overwrite the function of the parent class.
The following figure shows the virtual function table in the subclass instance:
We can see that:
1) Each parent class has its own virtual table.
2) The member function of the subclass is placed in the table of the first parent class. (The first parent class is determined in the Declaration Order)
In this way, the actual function can be called to resolve the pointer of different parent classes pointing to the same subclass instance.
Multiple inheritance (with virtual function overwrite)
Next let's take a look at the case of virtual function coverage.
, We override the F () function of the parent class in the subclass.
The following figure shows the virtual function table in the subclass instance:
We can see that the F () position in the three parent class virtual function tables is replaced with the function pointer of the subclass. In this way, we can direct any static parent class to the subclass and call the F () of the subclass. For example:
Derive D;
Base1 * b1 = & D;
Base2 * b2 = & D;
Base3 * B3 = & D;
B1-> F (); // derive: F ()
B2-> F (); // derive: F ()
B3-> F (); // derive: F ()
B1-> G (); // base1: G ()
B2-> G (); // base2: G ()
B3-> G (); // base3: G ()
Security
Every time I write a C ++ article, I always have to criticize C ++. This article is no exception. As described above, I believe we have a more detailed understanding of the virtual function table. The water can carry boat, but also the boat. Next, let's take a look at what we can do with a virtual function table.
1. Use a pointer of the parent type to access the virtual function of the subclass.
We know that it is meaningless for the subclass to overload the virtual function of the parent class. Because polymorphism is also based on function overloading. Although we can see in the figure above that the virtual table of base1 has a virtual function of derive, we cannot use the following statement to call its own virtual function of the subclass:
Base1 * b1 = new derive ();
B1-> F1 (); // compilation Error
Any attempt to use the parent class pointer to callThe member functions of the parent class are not overwritten.Such a program cannot be compiled. However, during runtime, we can access the virtual function table through pointers to violate the C ++ semantics. (I believe you can do this by reading the code in the appendix below)
2. Access non-publicVirtual Functions
In addition, if the parent class's virtual functions are private or protected, but these non-public virtual functions will also exist in the virtual function table, we can also access these non-public virtual functions by accessing the virtual function table, which is easy to achieve.
For example:
Class base {
PRIVATE:
Virtual void F () {cout <"base: F" <Endl ;}
};
Class derive: public base {
};
Typedef void (* Fun) (void );
Void main (){
Derive D;
Fun pfun = (fun) * (int *) (& D) + 0 );
Pfun ();
}