0. Foreword
The article is longer, and the content is relatively boring, I hope that the memory layout of C + + objects, virtual table pointers, virtual base class pointers have in-depth understanding of friends can slowly look.
The conclusions of this paper are verified on VS2013. Different compilers may differ in the details of the memory layout.
If there are unexplained, unexplained or omissions in the article, please point out. Back to top 1. What is the C + + object model?
Quote the words "deep explore C + + object Model" in this book:
There are two concepts that can explain the C + + object model: The part of language that directly supports object-oriented programming. For the various supported underlying implementation mechanisms.
Direct support to object-oriented programming, including constructors, destructors, polymorphism, virtual functions, etc., which are discussed in many books, is also the most well-known place in C + + (characteristics). However, the underlying implementation mechanism of the object model is rarely discussed in the book. The underlying implementation mechanism of object model is not standardized, and different compilers have some freedom to design the implementation details of object model. In my opinion, object model studies the object in the storage space and time better, and the C + + object-oriented technology to support, such as virtual pointer, virtual table mechanism to support polymorphic characteristics. Back to top 2. Introduction to the content of the article
This article mainly discusses the layout of C + + objects in memory, which belongs to the research scope of the second concept. and C + + directly support the Object-oriented programming part is not much to say. The main contents of the article are as follows: virtual function table parsing. Contains a virtual function or its parent class contains a virtual function of the class, the compiler will add a virtual function table, vptr, first understand the composition of virtual function table, to help understand the C + + object model. Virtual base class table parsing. Virtual inheritance produces virtual base class table (VBPTR), the content of virtual base class table is completely different from virtual function table, we will introduce virtual function table when we explain virtual inheritance. Object Model Overview: Describes the Simple object model, the table-driven object model, and the C + + object model under inheritance. The C + + object model under inheritance. Analyze the memory layout of C + + class objects in the following scenario: Single inheritance: Subclasses are inherited from the parent class, and the class object memory layout is analyzed when the subclass overrides the parent class virtual function and the subclass defines the new virtual function. Multiple inheritance: subclasses inherit from multiple parent classes, analyze subclasses to override parent virtual functions, subclass define new virtual functions, object memory layout, and analyze the diamond inheritance under Non-virtual inheritance. Virtual inheritance: The virtual inheritance under single inheritance, the virtual inheritance under multiple base, and the virtual inheritance under repeated inheritance are analyzed. After understanding the memory layout of an object, we can analyze some of the problems: how much is the layout cost of the C + + package. The size of each class object in an inheritance hierarchy composed of empty classes.
As for other memory-related knowledge, I assume that we all have a certain understanding, such as memory alignment, pointer operation, and so on. At the beginning of this article, it may be obscure, require the reader to have a certain C + + base, the concept of a certain grasp. Back to top 3. Understanding virtual function Table 3.1. Polymorphism and virtual table
The function of virtual function in C + + is mainly to realize the polymorphic mechanism. Polymorphism, in simple terms, means that in an inheritance hierarchy, a pointer to a parent class can have many forms--when it points to a subclass object, it can call the function of the subclass, not the function of the parent class.
Class Base { virtual void print (void); }
Class Drive1:p ublic base{ virtual void print (void);
Class Drive2:p ublic base{ virtual void print (void);
Base * ptr1 = new Base;
Base * ptr2 = new Drive1;
Base * PTR3 = new Drive2;
Ptr1->print (); Call Base::p rint ()
prt2->print ()//Call Drive1::p rint ()
prt3->print ();//Call Drive2::p rint ()
This is a run-time polymorphism, that is, the parent class pointer can only know what the true type is when the program is running. This kind of runtime resolution is realized by virtual function table. 3.2. Using pointers to access virtual tables
If we enrich our base class so that it has more than one virtual function:
Class Base
{public
:
base (int i): Basei (i) {};
virtual void print (void) {cout << "called a dummy function base::p rint ()";}
virtual void SetI () {cout<< "called a dummy Function Base::seti ()";}
Virtual ~base () {}
private:
int basei;
When a class itself defines a virtual function, or if its parent has a virtual function, the compiler adds a virtual function pointer (vptr) to the class to support the polymorphic mechanism. Virtual function pointers are generally placed in the first position of the object's memory layout, in order to ensure that a virtual function table can be fetched with maximum efficiency in the case of multiple inheritance or multiple inheritance.
When VPRT is in the front of object memory, the address of the object is a virtual function pointer address. We can get the address of the virtual function pointer:
Base B (1000);
int * Vptradree = (int *) (&b);
The address of the cout << "virtual function pointer (vprt) is: \ t" <<vptradree << Endl;
We run the code out of the results:
We force the address of the class object to the int* type and obtain the address of the virtual function pointer. The virtual function pointer points to the virtual function table, and the virtual function table stores the address of a series of virtual functions, and the order of the virtual function addresses is in accordance with the order of the virtual function declarations in the class. For a virtual function pointer address value, you can get the address of the virtual function table, which is the address of the first virtual function of the virtual function table:
typedef void (*fun) (void);
Fun Vfunc = (Fun) * (int *) * (int*) (&b));
cout << "The address of the first virtual function is:" << (int *) * (int*) (&b) << Endl;
cout << "by address, call virtual function base::p rint ():";
Vfunc ();
We take out the value of the virtual table pointer: * (int*) (&B), which is an address where the address of the virtual function table casts the address of the virtual function table to the int*: (int *) * (int*) (&b) and converts it to our Fun pointer type: (FUN) * (i NT *) * (int*) (&b)
So, we get the first virtual function in the class, and we can access it through the function pointer.
Run Result:
Similarly, the address of the second virtual function, SETI (), is:
(int *) (* (int*) (&b) +1)
It can also be accessed through function pointers, which are left to the reader to experiment with themselves.
So far, we know the origin of the virtual table pointer vprt in class, know the contents of the virtual function table, and how to access the virtual function table through the pointer. The following articles will often use pointers to access object memory to validate our C + + object model, and to discuss the changes in virtual table pointers under various inheritance situations, first digest the contents of this section and then look at the following. Back to top 4. Overview of the object model
In C + +, there are two types of data members: Static and nonstatic, and three kinds of member functions (class membership functions): Static, nonstatic, and virtual:
Now we have a class base, which contains data or functions of the type 5 above:
Class Base
{public
:
base (int i): Basei (i) {};
int Geti () {return basei;}
static void Counti () {};
Virtual ~base () {}
virtual void print (void) {cout << "Base::p rint ()";}
Private:
int basei;
static int bases;
};
So, how will this class be represented in memory? 5 kinds of data are stored continuously. How to layout to support C + + polymorphism. How our C + + standards and compilers will shape various data members and member functions. 4.1. Simple Object Model
Description: In the diagram shown below, the contents of the box with the blue Edge are contiguous on the memory.
This model is very simple and rough. In this model, the object consists of a series of pointers, each pointing to a data member or member function, which means that each data member and member function occupies the same size in the class as the size of one pointer. There's a benefit--it's easy to figure out the size of an object, but it's about space and execution time. Imagine that if our Point3D class were this model, there would be a lot more space than the C language struct to hold pointers to functions, and every time you read the data members of the class, you would need to address them again--and time consuming.
So the object model is not used in the actual product.
4.2. Table-Driven model
This model adds an indirect layer based on the Simple object model, it divides the data in the class into two parts: the data part and the function section, and uses two tables, one for the data itself, one for the address of the function (i.e. the function is addressed once more than the member), and the class object contains only two pointers, Point to the above two tables, respectively. In this case, the size of the object is fixed to two pointer size. This model is also not used to actually apply to the real C + + compiler. 4.3. Non-inherited C + + object model
Overview: Under this model, nonstatic data members are placed in each class object, while static data members are placed outside the class object. Static and nonstatic functions are also placed outside the class object, and for the virtual function, the virtual function table + virtual pointer to support, specifically as follows: Each class generates a table, called Virtual table (virtual tables, referred to as VTBL). A virtual table holds a bunch of pointers that point to each virtual function of the class. function addresses in virtual tables are arranged in the order in which they are declared, but are discussed later when there are multiple overloaded functions for subclasses. Each class object has a virtual table pointer (vptr) that is generated by the compiler. The setting and resetting of the virtual table pointer is accomplished by the copy control of the class (also the constructor, destructor, assignment operator). The position of the vptr is decided by the compiler, traditionally it is placed after all the members of the display declaration, but now many compilers put vptr on the front end of a class object. The contents of the data member layout are analyzed in detail later.
In addition, a pointer to Type_info is set in front of the virtual function table to support RTTI (run time type identification, Run-time type recognition). Rtti is the information generated for polymorphism, including object inheritance, the description of the object itself, and only objects with virtual functions are generated.
Under this model, the object model for base is shown in figure: