Memory model of C + + virtual function __jquery

Source: Internet
Author: User
Tags class definition
Preface

Everyone should know that the essence of C + + is a virtual function, right? The advantage of a virtual function is that you can define a pointer to a base class that points to an inheriting class, and when you call a function through a pointer to a base class, you can decide at run time whether the function of the base class or the function of the inherited class. Virtual functions are the basis for implementing polymorphic (Dynamic Binding)/interface functions. Can say: no virtual function, C + + will become useless!

Since it is the essence of C + +, then we need to understand her implementation of the way? It's necessary! Since C + + is from the base of the development of language, then we can try to use C language to simulate the implementation of it? It's possible! Next, I step-by-step to resolve the C + + virtual functions of the implementation of the method, as well as the use of C language to simulate it. memory layout for C + + objects

To know the memory layout of a C + + object, there are several ways, such as the offset of an output member variable, to be viewed through the debugger by Offsetof macros, such as the Common vs

objects with only data members

Class is implemented as follows:

Class Base1
{public
:
    int base1_1;
    int base1_2;
};

Object size and Offset:

sizeof (BASE1) 8
Offsetof (Base1, Base1_1) 0
Offsetof (Base1, base1_2) 4

The object layout:

As you can see, the member variables are saved in the order defined, first declared at the top, and then saved in turn!
The size of the class object is the sum of the size of all the member variables. an object without a virtual function

Class is implemented as follows:

Class Base1
{public
:
    int base1_1;
    int base1_2;

    void foo () {}
};

The results are as follows:

sizeof (BASE1) 8
Offsetof (Base1, Base1_1) 0
Offsetof (Base1, base1_2) 4

Is the same as the previous result? You don't need to have a problem, do you?
Because if a function is not a virtual function, then it is impossible for the dynamic binding to occur and will not affect the layout of the object.
When a non-virtual function is invoked, the call must be the member function that the current pointer type has. This invocation mechanism was determined at compile time. class object that has only one virtual function

Class is implemented as follows:

Class Base1
{public
:
    int base1_1;
    int base1_2;

    virtual void Base1_fun1 () {}
};

The results are as follows:

sizeof (BASE1) 12
Offsetof (Base1, Base1_1) 4
Offsetof (Base1, base1_2) 8

Hey? 4 more bytes? And the base1_1 and base1_2 offsets are 4 bytes backwards!
Description of the top of the class object is added 4 bytes of "Dongdong", what ' s it?
Now, let's look at the memory layout of the variable b1 of class Base1 by VS2013:
(Since I did not write the constructor, the data for the variable is not based, but the virtual function is constructed for us, the data is correct!)
(in debug mode, the uninitialized variable value is 0xCCCCCCCC, that is:-858983460)

Did you see that? Base1_1 a variable __vfptr (often called a virtual function table vtable pointer), its type is void**, which indicates that it is a void* pointer ( Note: not an array).

Then look at the [0] element, whose type is void* and its value is consoleapplication2.exe! Base1::base1_fun1 (void), what does that mean? If you are familiar with WinDbg, you should know that this is a idiomatic expression, she refers to the address of the BASE1::BASE1_FUN1 () function.

Well, __vfptr's definition pseudocode might be as follows:

void*   __fun[1] = {&BASE1::BASE1_FUN1};
Const void**  __vfptr = &__fun[0];

It is worth noting that the above is just a pseudo code, the syntax does not necessarily pass the object size of the class is 12 bytes, size and offset information as follows:

sizeof (BASE1) 12
Offsetof (__VFPTR) 0
Offsetof (base1_1) 4
Offsetof (base1_2) 8
Have you been paying attention to this __vfptr? Why is it defined as a pointer to an array of pointers instead of being directly defined as an array of pointers?

Why should I ask such a question? Because if it's just a pointer, you can't easily modify the contents of that array because she's not part of the class object.
For a class object, it is only a pointer to a virtual function table __vfptr , and we will continue to discuss this issue in the next section. Note the const modifier in front of the __vfptr. She modifies the virtual function table, not the __vfptr.

The objects are now laid out as follows:

The virtual function pointer __vfptr is defined before all member variables.

Note: I am not here to explain the specific point of __vfptr, but to illustrate the current layout of class objects.
Next look at a slightly more complex situation, I will clearly describe the composition of the virtual function table. class object with multiple virtual functions

Similar to the previous example, just add a virtual function. The definition is as follows:

Class Base1
{public
:
    int base1_1;
    int base1_2;

    virtual void Base1_fun1 () {}
    virtual void base1_fun2 () {}
};

The size and offset information are as follows:

Got a situation!? More than a virtual function, the class object size is still 12 bytes!

Let's look at the performance of VS Image:

Yes, __vfptr the 2nd element in the array of function pointers to which the value is the function address of the 2nd virtual function base1_fun2 () of the Base1 class.

Now, the pseudo definition of virtual function pointers and virtual function tables is probably as follows:

void* __fun[] = {&base1::base1_fun1, &base1::base1_fun2};
Const void** __VFPTR = &__fun[0];

From the above two charts, we can get the following conclusion: more sure of what we described earlier: __VFPTR is just a pointer, she points to a function pointer array (that is, a virtual function table) adds a virtual function, simply adds an entry to the virtual function table corresponding to the class. Does not affect the size and layout of the class object

As mentioned earlier: __vfptr is just a pointer, she points to an array, and: This array is not included within the class definition, so what is the relationship between them?
Let's define a variable b2 for a class, and now look at the __vfptr point:

Through the Watch 1 window we see: B1 and B2 are classes of two variables, of course, their address is different (see &B1 and &B2) although B1 and B2 are two variables of the class, but: their __vfptr point is the same virtual function table

From this we can conclude that:

Different instances of the same class share the same virtual function table, and they all point to the virtual function table by means of a so-called virtual function table pointer __vfptr (defined as void** type).

It's time to show the memory layout of the class object:

No surprises, it's clearly shown. :-) hoho~~

Then the question is coming! Where does this virtual function table hold? In fact, we do not have to unduly investigate where she is located, the focus is: She is the compiler at compile time for us to create a good, only a definition of class objects, the compiler automatically __vfptr the class object to the virtual function table

memory layout of inherited classes with single inheritance and no virtual functions of their own

So much has been studied before, and it's time to study the inheritance Class! Study the single inheritance first!

Still, simply define an inheritance class, as follows:

Class Base1
{public
:
    int base1_1;
    int base1_2;

    virtual void Base1_fun1 () {}
    virtual void base1_fun2 () {}
};

Class Derive1:public Base1
{public
:
    int derive1_1;
    int derive1_2;
};

Let's take a look at the current memory layout (defined as Derive1 D1):

That's right! The base class is on top, and the members of the inheriting class are defined below! Unfold to see:

After unfolding, the front part is completely Base1: the virtual function table pointer + member variable definition.
Also, the [0][1] two items of the BASE1 virtual function table are the functions they own: base1_fun1 () and base1_fun2 ().

Now the layout of the class should be the following:

There is no virtual function in itself (not rigorous) but there is a memory layout for a single inheriting class that is covered by a base class virtual function

The title ' itself does not exist a virtual function ' is somewhat imprecise, I mean to say: In addition to the inherited from the base class virtual function, it does not define other virtual functions.

Ok, now that you have a base class virtual function overlay, let's see how the next code will affect:

Class Base1
{public
:
    int base1_1;
    int base1_2;

    virtual void Base1_fun1 () {}
    virtual void base1_fun2 () {}
};

Class Derive1:public Base1
{public
:
    int derive1_1;
    int derive1_2;

    Overwrite base class function
    virtual void base1_fun1 () {}
};

As you can see, the Derive1 class overrides the Base1_fun1 () function of the Base1 class, which is often called a virtual function overlay. How is the layout now?

Pay special attention to the line I highlighted: Originally BASE1::BASE1_FUN1 (), but because the inheriting class overridden this method of the base class Base1, it now becomes derive1::base1_fun1 ()!

So, whether you call this method through a Derive1 pointer or a Base1 pointer, the invocation will be the method (function) that is overridden by the inherited class, and the polymorphic occurrence of the bird!!!

So the new layout diagram:

class object layout that defines a single inheritance of a virtual function without a base class

Description: Because the previous situation only causes a pointer to overwrite the base class virtual function table, I will not discuss the virtual function overlay at the same time.

Continue to paste code:

Class Base1
{public
:
    int base1_1;
    int base1_2;

    virtual void Base1_fun1 () {}
    virtual void base1_fun2 () {}
};

Class Derive1:public Base1
{public
:
    int derive1_1;
    int derive1_2;

    virtual void Derive1_fun1 () {}
};

Unlike the 5th class, a virtual function of its own definition is more than one. Unlike the 6th class, there is no overriding of the base class virtual function.

Hey, did you find the problem? On the surface it looks almost exactly the same as the 5th case? For what?
Now the inheriting class clearly defines its own virtual function, but it is missing.
So, let's look at the size of the class object and the member offsets:

There's no change!!! The front 12 bytes are Base1, do you feel strange?

Well, since there's nothing on the surface, we can only start with the assembly and look at the code that calls DERIVE1_FUN1 ():

Derive1 D1;
derive1* PD1 = &d1;
Pd1->derive1_fun1 ();

Note: Why do I use pointers as a way to invoke? Description: Because if you do not use pointer calls, virtual function calls will not occur dynamically bound Oh! If you d1.derive1_fun1 directly (), it is not possible that dynamic binding will occur, but if you use pointers: pd1->derive1_fun1 (); , then PD1 will never know if she is pointing to the object is Derive1 or inherited from the Derive1 object, although here we do not inherit from Derive1, but she had to do so, after all, inheriting class no matter how you inherit, will not affect the base class, right?

; Pd1->derive1_fun1 ();
00825466  mov         eax,dword ptr [pd1]  
00825469  mov         edx,dword ptr [eax]  
0082546B  mov         ESI , esp  
0082546D  mov         ecx,dword ptr [pd1]  
00825470  mov         eax,dword ptr [edx+8]  
00825473  Call        eax

Assembly Code Explanation:

Line 2nd: Since PD1 is a pointer to D1, EAX is the address of D1 After this sentence is executed
Line 3rd: And because Base1::__vfptr is the 1th member of the BASE1,

Related Article

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.