C + + virtual function table parsing

Source: Internet
Author: User

Transfer from Chen Hao's blog

Objective

C++The function of virtual function in the main is to realize the polymorphism mechanism. In the case of polymorphism, in short, a pointer to the parent type points to an instance of its child class, and then invokes the member function of the actual subclass through a pointer to the parent class. This technique allows the parent class to have a "multiple form" pointer, which is a generic technique. The so-called generic technology, plainly, is trying to use immutable code to implement a mutable algorithm . For example: template technology, RTTI technology, virtual function technology, either try to do at compile time resolution, or try to achieve runtime resolution.

On the use of virtual functions, I do not do 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 above for everyone a clear analysis.

Of course, the same article appeared on the Internet some, but I always feel that these articles are not very easy to read, large sections of the code, no pictures, no detailed instructions, no comparison, no extrapolate. Not conducive to learning and reading, so this is why I want to write this article. I hope you will give me more advice.

Let's go to the world of virtual functions.

virtual function table

For C++ Those who know, the virtual function ( Virtual Function ) is implemented by a virtual function table ( Virtual Table ). For short V-Table . In this table, the master is the Address table of the virtual function of a class, which solves the problem of inheritance, overwriting, and ensures that it can actually react to the actual function. Thus, in an instance of a class with virtual functions, the table is assigned to the memory of this instance, so when we manipulate a subclass with a pointer to the parent class, the virtual function table is important, and it is like a map that indicates the function that should actually be called.

Here we focus on this virtual function table. C++compiler should be to ensure that pointers to virtual function tables exist in the first place in 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 this virtual function table from the address of the object instance , and then we can iterate over the function pointer and call the corresponding function.

Listen to me so much, I can feel it. You may be more disoriented than before. It doesn't matter, the following is the actual example, I believe that smart you see it.

class Base {     public:            virtualvoidcout"Base::f" << endl; }            virtualvoidcout"Base::g" << endl; }            virtualvoidcout"Base::h" << endl; }};

According to the above, we can use Base The example to get the virtual function table. Here is the actual routine:

            typedefvoid(*Fun)(void);            Base b;            Fun pFun = NULL;            cout"虚函数表地址:" << (int*)(&b) << endl;            cout"虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;            // Invoke the first virtual function             pFun = (Fun)*((int*)*(int*)(&b));            pFun();

The actual run-through results are as follows: ( Windows XP+VS2003 , Linux 2.6.22 + GCC 4.1.3 )

虚函数表地址:0012FED4虚函数表 — 第一个函数地址:0044F148Base::f

With this example, we can see that we can get the address of the virtual function table by forcing it, &b int * and then we can obtain the address of the first virtual function again, that is Base::f() , this is verified in the program above (the int* force is turned into a function pointer). With this example, we can know 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()

You should understand this time. What the? Still a little dizzy. Also, such code looks too messy. No problem, let me draw a diagram to explain. As shown below:

Note: In the above diagram, I added a node at the end of the virtual function table, which is the end node of the virtual function table, just like the string's terminator /0 , which marks the end of the virtual function table. The value of this end flag is different under different compilers. Under Winxp+vs2003, this value is null. And in Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3, this value is if 1, indicating there is also the next virtual function table, if the value is 0, represents the last virtual function table.

Below, I will explain the appearance of the virtual function table when there is no overwrite and overwrite. It is meaningless not to overwrite the virtual function of the parent class . I want to tell the story of the absence of coverage, the main purpose is to give a contrast. In comparison, we can know more clearly the specific implementation of its internal.

General Inheritance (no virtual function overrides)

Next, let's look at what the virtual function table looks like when inheriting. Suppose you have an inheritance relationship that looks like this:

Note that in this inheritance relationship, subclasses do not overload functions of any parent class. So, in an instance of a derived class, its virtual function table looks like this:

For instance: 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 precedes the virtual function of the child class.

General inheritance (with virtual function overrides)

Overriding the virtual function of the parent class is a very obvious thing, otherwise the virtual function becomes meaningless. Let's take a look at what it looks like if a virtual function in a subclass overloads the virtual function of the parent class. Let's say we have an inheritance relationship like the one below.

In order to let you see the effect after the inheritance, in the design of this class, I only covered a function of the parent class: f() . Then, for instances of derived classes, the virtual function table will look like this:

We can see the following points from the table,

1) The overridden f() function is placed in the location 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 the following program,

  *=new Derive();  b->f();

The b location of the table of virtual functions in memory is replaced by the address of the f() Derive::f() function, and is called when the actual call occurs Derive::f() . This enables polymorphism.

Multiple inheritance (no virtual function overrides)

Next, let's look at the case in multiple inheritance, assuming that there is an inheritance relationship for one of the following classes. Note: The subclass does not have a function that overrides the parent class.

For a virtual function table in a subclass instance, the following looks like this:

We can see:

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 so-called first parent class is judged in order of declaration)

This is done in order to resolve pointers to different parent class types to the same child class instance, and to invoke the actual function .

Multiple inheritance (with virtual function overrides)

Let's take a look at the case where virtual function overrides occur.

, we override the parent class's function in the subclass f() .

The following is a diagram of a virtual function table in a subclass instance:

As we can see, the position in the three parent virtual function table f() is replaced with the function pointer of the subclass. In this way, we can refer to the subclass of the parent class of any static type and call the subclass f() . Such as:

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 C++ you write an article, you always have to criticize C++ . This article is no exception. Through the above, I believe we have a more detailed understanding of the virtual function table. Water can carry boat, can also overturn it. Let's take a look at what we can do with a virtual function table.

Access a subclass's own virtual function through a pointer to the parent type

We know that subclasses do not have to reload the virtual functions of the parent class as a meaningless thing. Because polymorphism is also based on function overloading. Although there are virtual functions in the virtual table that we can see in the above figure Base1 Derive , we simply cannot use the following statement to invoke the own virtual function of the subclass:

          *=new Derive();          b1->f1();  //编译出错

any attempt to use a parent pointer to call a member function in a subclass that does not overwrite a parent class is considered illegal by the compiler (That is, a base-class pointer can only access functions that its own and quilt-class overrides), so such a program cannot be compiled at all. But at run time, we can access the virtual function table in the way of pointers to violate C++ the semantic behavior. (Try to do this by reading the code in the appendix below, believing you can do it)

Accessing virtual functions of Non-public

In addition, if the virtual function of the parent class is private or is protected , but these non- public virtual functions will also exist in the virtual function table, so we can also use access to the virtual function table to access these non-public virtual functions, which is very easy to do.

Such as:

class Base {    private:            virtualvoidcout"Base::f" << endl; }};classpublic Base{};typedefvoid(*Fun)(void);void main() {    Derive d;    Fun  pFun = (Fun)*((int*)*(int*)(&d)+0);    pFun();}
Appendix

The following is a routine about virtual function table access for multiple inheritance:

#include <iostream>usingnamespace Std;class Base1{public:virtual void F(){cout << "Base1:: F "<< Endl; } virtual void G(){cout << "Base1:: G "<< Endl; } virtual void H(){cout << "Base1:: H "<< Endl; }};class Base2{public:virtual void F(){cout << "Base2:: F "<< Endl; } virtual void G(){cout << "Base2:: G "<< Endl; } virtual void H(){cout << "Base2:: H "<< Endl; }};class BASE3{public:virtual void F(){cout << "BASE3:: F "<< Endl; } virtual void G(){cout << "BASE3:: G "<< Endl; } virtual void H(){cout << "BASE3:: H "<< Endl; }};class Derive: PublicBase1, publicBase2, publicBASE3{public:virtual void F(){cout << "Derive:: F "<< Endl; } virtual void G1(){cout << "Derive:: G1 "<< Endl; }};typedef void(*Fun)(void); int main(){ FunPfun =NULL;DeriveD int** Pvtab =(int* *)&d; //Base1 ' svtable//pfun =(Fun)*(int*)*(int*)(int*)&d+0) +0); Pfun =(Fun)PVTAB[0][0]; Pfun(); Pfun =(Fun)*(int*)*(int*)(int*)&d+0) +1); Pfun =(Fun)PVTAB[0][1]; Pfun(); Pfun =(Fun)*(int*)*(int*)(int*)&d+0) +2); Pfun =(Fun)PVTAB[0][2]; Pfun(); //Derive ' svtable//pfun =(Fun)*(int*)*(int*)(int*)&d+0) +3); Pfun =(Fun)PVTAB[0][3]; Pfun(); // theTail of the vtable Pfun =(Fun)PVTAB[0][4];            cout<<pfun<<endl; //Base2 ' svtable//pfun =(Fun)*(int*)*(int*)(int*)&d+1) +0); Pfun =(Fun)PVTAB[1][0]; Pfun(); Pfun =(Fun)*(int*)*(int*)(int*)&d+1) +1); Pfun =(Fun)PVTAB[1][1]; Pfun(); Pfun =(Fun)PVTAB[1][2]; Pfun(); // theTail of the vtable Pfun =(Fun)PVTAB[1][3];            cout<<pfun<<endl; //Base3 ' svtable//pfun =(Fun)*(int*)*(int*)(int*)&d+1) +0); Pfun =(Fun)PVTAB[2][0]; Pfun(); Pfun =(Fun)*(int*)*(int*)(int*)&d+1) +1); Pfun =(Fun)PVTAB[2][1]; Pfun(); Pfun =(Fun)PVTAB[2][2]; Pfun(); // theTail of the vtable Pfun =(Fun)PVTAB[2][3];            cout<<pfun<<endl; return 0;}

C + + virtual function table parsing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.