C + + object Model (V): The semantics of data data semantics

Source: Internet
Author: User

This article is "Inside the C + + Object Model" Chapter III of the Reading notes. Mainly discusses the memory layout of C + + data member. The data member here contains the layout of the Vptr and vtable when class has virtual functions. 1. First few small questions

1. First answer a question: an empty class, sizeof is how much. The answer is 1. Because the compiler generates a cryptic 1bytes that distinguishes the individual objects from allocating unique addresses in memory when the class is multiple objects.

2. There are also pointer vptr of virtual function tables, either at the beginning of the class or at the end of the class. Usually the end of a class. (Note: Relatively new VC + + and GCC are all at the beginning.) I don't know if all the versions are).

3. About the memory alignment of a member variable, such as a class that has only char a attribute; But its size is 4 (32 bits). The 64-bit machine is 8. But I'm using gcc sizeof is still 1. Familiar with the Assembly should know that this address should not save other content, so that sizeof is 4/8 can also be understood. Although the size of the char is 1.

4. The memory order and declaration order of the attributes are consistent. The order of the different levels (public, protected, and private) is relatively consistent, which means that it may be discontinuous, but it must conform to a higher address for a later occurrence of the attribute. 2. Different storage mode of vptr value

The following figure comes from Http://blog.csdn.net/hherima. Thank you very much for Hherima's picture. I will use Hherima's diagram, plus my own understanding to thoroughly consolidate and share to you lovely program apes.

The following illustration shows the layout of the data in the case of single inheritance and containing virtual functions. POINT2D and Point3D are inheritance relationships. POINT2D contains virtual functions, while Point3D itself has no virtual functions.


Note: Vptr is placed at the end of the class. This approach is used by many compilers at the beginning, because the memory layout of base C struct can be saved.

But at c++2.0, it starts to support virtual inheritance and abstract base classes, and because of the rise of Oo, some compilers start putting vptr at the beginning of class object. Microsoft's first C + + compiler, for example, is using this approach.
The advantage of the front-end storage is that the compiler can directly access the virtual function table without having to pass offset. Of course the price is no longer compatible with C's struct. But who derives from a C struct C + + class with a virtual function?

If the front-end is stored, there is a problem: if the base class does not have virtual functions, derived classes have virtual functions, then the natural polymorphism of single inheritance will be broken. If you want to convert a derived class to a base class, you must intervene by the compiler. But this is also less, so polymorphism is to inherit, who will design this inheritance. Since this is not the case in most cases, the use of vptr in the beginning, then has a very good meaning. This conventional actually helps compilers compile C + + into the assembly, and the compilation is easier to read. Otherwise, at the end, the number of data member for each class is different, so the offset of the Vptr store is not the same. On the head, then the location of the No. 0 is the first data member in the position of vptr,1, which is not only good for compiling the code, but also convenient for us to read the Disassembly assembly code. 3. Memory layout for data member

In the previous section we discussed the different ways in which vptr are stored. The compiler needs to access vptr and data member by setting offset. On page 98, a description of the access operation for a nonstatic data member, feel confused: The author means that if the first data member of the object is taken directly, then the address +1 of the object is required. I don't quite understand. If you are accessing the first member of an object, the address of the object should be the first member, it may be vptr, or it may be the first. So if the assembly, then directly to the content of the address, the content of the address may be the value of members, may still be the address (pointer), then offset+1 meaningless. If it is C + + code, then it does not need to be so troublesome, who will directly explain the object's address, rather than the way through C + +.    Of course some high-performance programming may be, but I really can't think of any reason to do so. The C + + language guarantees that "the base class object appearing in the derived class has its integrity", so that it can be copied correctly in the presence of a copy. Typically, each member will have an exclusive address, meaning that at least 4 B is used for each data member on a 32-bit machine. Of course for the memory alignment, for example, the class:

Class data{
  char A;
  Char b;
  int c;
};

Then A and B may share an address cell, i.e. sizeof (data) = 8, but subclasses, the data members of the parent class can share an address cell for space efficiency.

If both Concrete1 and Concere2 have a char attribute, and Concere2 inherits from Concrete1. So what's the problem if the two data members share an address cell? So let's think about the following assignment to meet our expectations.

Concrete1 *pc1_1, pc1_2;
Concrete2 C2;
Pc1_1 = &c2;
Memory allocate for pc1_2
*pc1_2 = *pc1_1;

Note that pc1_1 Char B is erased from pc1_1 to pc1_2 memberwise replication (copying one member). Then Pc1_1 lost the information of the derived class. And this replication is obviously not what we need.


This is why the C + + language guarantees "a base class object that appears in a derived class with its integrity."



3. Multiple inheritance (multiple inheritance) for a multiple-derived object, assign its address to the "most left (that is, the first) base class pointer", as in the case of single inheritance, since both point to the same starting address. The cost is only the specified operation of the address, and for the second or subsequent base class address specified operation, address modification is required: plus or minus the middle base class size.

The following illustration shows the relationship of multiple inheritance. Involving 4 classes of point2d, Point3D, Vertex and Vertex3d (p115)



The object model for multiple inheritance is shown below.


Note that in the case of multiple inheritance, drived Clas may have two or more virtual function table pointers .

Take a look at the following expression:

Vertex3d   v3d;
vertex*     PV;
point2d*   p2d;
Point3D *  p3d;
So this operation PV = &v3d need to convert the internal code

PV = (vertex*) (((char*) &v3d) + sizeof (Point3D))

So if PV is copied from another Vertex3d pointer (such as a pv3d). Then you need to consider the case of NULL pointers.

PV = pv3d
     ? ( vertex*) (((char*) &v3d) + sizeof (Point3D))   
     : 0;
The following two operations, only need to copy the address on the line.

p2d = &v3d;

P3d = &v3d;

The following is a quote from Mr. Chenhao's classic "Memory layout for C + + objects" multiple inheritance. The use of VC + + and GCC3.4.4

Using a picture representation is the following:

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.
3 in the memory layout, the parent class layout is arranged in the order of declaration in turn.
4 the F () function in the virtual table of each parent class is overwrite to the F () of the subclass. This is done in order to solve the different parent class type of pointer to the same subclass instance, and can call to the actual function.
4. Virtual Multiple inheritance

The following figure shows the Vertex3d inheritance system diagram. The left is multiple inheritance, and the right is virtual multiple inheritance.

Each class is defined as follows:

Class point2d{...
Protect:
  float _x, _y;

Class Vertex:public virtual point2d{...
Protected:
  Vertex *next;

Class Point3d:public virtual point2d{...
Protected:
  float _z;

Class Vertex3d:public Vertex, public point3d{
...
Protected:
  float mumble;

Whether it is VertexStill is Point3DContains a point2d。 However in Vertex3dObject layout, we only need a single copy of the point2dJust fine. How to make multiple inheritance, then there will be two point2d in the Vertex3d object, then the reference to point2d may be ambiguous. So the virtual inheritance is introduced. However, the compiler to achieve virtual inheritance, it is difficult to be quite high. The principle of virtual inheritance is: let VertexAnd Point3DThe respective maintained point2d are folded into a single point2d with vertex3d maintenance and can also hold multiple specified operations between the pointers of base class and derived class.

If a class contains virtual base classsubobjects, the object is divided into two parts: an invariant local and a shared part. Invariant local data, regardless of subsequent evolution, always has fixed offset, so this part of the data can be directly accessed. As for shared local (that is, virtual base class), this part of the data, whose location is changed by each derivative operation, can only be accessed indirectly. The difference between the implementations of the compilers is that the methods of indirect access are different.

How to access the shared part of class? The Cfront compiler will insert a pointer to the virtual base class in each derived class so that it can be accessed indirectly. This implementation model has the following two main drawbacks:

1. Each object must bear an additional pointer to each of its virtual base class. The workaround is: First, the Microsoft compiler introduces the so-called virtual base class table. Each class object if there is one or more virtual base class, the compiler will insert a pointer to the virtual base class table. The real virtual base class pointer, of course, is placed in the table.

See the following virtual inheritance object model, as shown in figure.


The red box is called "Shared local", and its position varies with each derivation operation. virtual destruction of the base class object integrity, virtual inheritance will generate a virtual function table pointer in its own class.

Second, in the virtual function table, place the offset (not the address) of the virtual base class.


The advantage of this method is that the structure of the virtual function table is cleverly exploited, so that drived class can save a pointer size. The blue curve in the above figure is offset

2. Because of the increase of the virtual inheritance chain, the indirect access level is increased. For example, if we have a three-layer virtual derivation, I need three indirect access (via three virtual base class pointers).

The solution to this problem is to copy all the virtual base class pointers into the DriveD class. This solves the problem of access time, although there will be space overhead.


Resources:

1. http://blog.csdn.net/haoel/archive/2008/10/15/3081328.aspx

2. http://blog.csdn.net/hherima/article/details/8888539

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.