C ++ object layout and polymorphism realize memory layout of Exploration

Source: Internet
Author: User
Author: Pan Kai Source: vchelp Editor: Ark [] Preface

This article tracks the assembly code of function calls by observing the memory layout of objects. Analyzes the layout of the C ++ object memory, the execution methods of virtual functions, and virtual inheritance.

I wrote this article because of a post I saw on the forum. Someone asked VC which method is used to implement virtual inheritance. At that time, I wrote some code to verify it. The result showed that the situation was more complex than I thought. So I simply tried all the relevant problems and recorded the cost.

My knowledge of C ++ object models mainly comes from Lippman's book "inside the C ++ object model". I have read both the Chinese and English versions of the in-depth exploration C ++ object model translated by Hou Jie, but I still recommend the Chinese version because the Chinese version is indeed quite good, in addition, Hou Jie added a lot of images and fixed some errors in the original version.

The compiler I use is vc7.1, and all the code in this article is verified on vc7.1. If you want to run the program in other compilers, you need to make corresponding adjustments, even for vc7.0 and vc6. The assembly code generated by different compilers is different. It is not surprising that the compilation code generated by the code in the compilation and translation on different compilers is different from the one listed by me. If you want to verify the code on other compilers, make the necessary changes.

In addition, I found that the method used by vc7.1 to Implement Virtual inheritance is different from that used by Microsoft in Lippman's book, but there was no vc7.1 at that time. Interestingly, Lippman worked at Disney when writing that book, and should be related to 3D film rendering software. Now that he has arrived at Microsoft, I believe it should be the design of the vc7.1 compiler.

In the subsequent sections, we can see a lot of the listed assembly code, which is obviously inefficient. This may be because I have not enabled the compiler optimization switch. Turn on the optimization switch and set different optimization options, the compiler may produce much more efficient assembly code. If you are interested, you can try it on your own and compare it with the Assembly Code listed in this article.

To facilitate analysis and observation of the memory layout of objects, I set the structure member alignment option during code generation to 1 byte. The default value is 8 bytes. If you compile the translated code under your project, make the same settings. Because I have written some layout information in the function printing object. If the object option is not 1 byte, a pointer Exception error occurs when running the code.

  Memory layout of common class objects

First, we start with the memory layout of common class objects. C000 is an empty class and is defined as follows:

Struct c000
{};

Run the following code to print its size and content in the object.

Print_size_detail (c000)

Result:

The size of c000 is 1
The detail of c000 is CC

The size is 1 byte, which is a placeholder. We can see that its value is 0xcc. In debug mode, this indicates that the memory is initialized by the debugging code inserted by the compiler. In release mode, it may be a random value. The test value is 0x00.

Define two classes, c010 and c011:

Struct c010
{
C010 (): C _ (0x01 ){}
Void Foo () {C _ = 0x02 ;}
Char C _;
};
Struct c011
{
C011 (): C1 _ (0x02), C2 _ (0x03 ){}
Char C1 _;
Char C2 _;
};

Run the following code to print their size and content in the object.

Print_size_detail (c010)
Print_size_detail (c012)

Result:

The size of c010 is 1
The detail of c010 is 01
The size of c011 is 2
The detail of c011 is 02 03

We can see from the Memory output of the object that their values are the values we assigned in the constructor, c010 is 0x01, and c011 is 0x0203. The sizes are 1 and 2.

Define the c012 class.

Struct c012
{
Static int sfoo () {return 1 ;}
Int Foo () {return 1 ;}
Char C _;
Static int I _;
};
Int c012: I _ = 1;

In this class, we add a static data member, a common member function, and a static member function.

Run the following code to print its size and content in the object.

Print_size_detail (c012)

Result:

The size of c012 is 1
The detail of c012 is CC

We can see that its size is still 1 byte, and its value is 0xcc because we didn't initialize it. The reason is as mentioned above.

From the above results, we can demonstrate that normal member functions, static member functions, and static member variables are not expressed in class objects, the association between member functions and objects is handled by the compiler during compilation. As we will see later, the compiler will determine the correct normal member function address during compilation, the object address is passed to the common member function as the first parameter as the this pointer for association. Static member functions are similar to global functions and are not associated with specific objects. The same is true for static member variables. Static member functions and static member variables are different from common global functions and global variables because they have a limited name.

Memory layout of common inherited class objects

Next let's take a look at the memory layout of ordinary inherited class objects.

Define an empty class c014 inherited from c011, and then define c015 is also an empty class inherited from c010 and c011.

Struct c010
{
C010 (): C _ (0x01 ){}
Void Foo () {C _ = 0x02 ;}
Char C _;
};
Struct c011
{
C011 (): C1 _ (0x02), C2 _ (0x03 ){}
Char C1 _;
Char C2 _;
};
Struct c014: Private c011
{};
Struct c015: Public c010, private c011
{};

Run the following code to print their size and content in the object.

Print_size_detail (c014)
Print_size_detail (c015)

Result:

The size of c014 is 2
The detail of c014 is 02 03
The size of c015 is 3
The detail of c015 is 01 02 03

The size of c014 is 2 bytes, that is, the size of c011. The memory value of the object is also the two values initialized in the c011 constructor 0x0203. The size of c015 is 3 bytes, that is, the sum of c010 and c011, and the object memory value is 0x010203.

Here, we can find that all member variables of the parent class inherit from the quilt class and are irrelevant to the Inheritance Method (public or private). For example, c015 is private inherited from c011. Inheritance only affects the "visibility" of data members ". The member variables inherited from the parent class in the subclass object are initialized by the constructor of the parent class. The default constructor is usually called unless the subclass explicitly calls the non-default constructor of the parent class in its constructor initialization list. If no default constructor is specified and the parent class does not have a default constructor, a compilation error occurs.

We can add another inheritance layer to verify it. Defines the class c016, inherited from c015, and has its own 4-byte int member variable.

Struct c016: c015
{
C016 (): I _ (1 ){}
Int I _;
};

Run the following code to print its size and content in the object.

Print_size_detail (c016)

Result:

The size of c016 is 7
The detail of c016 is 01 02 03 01 00 00

It is 7 bytes in size, that is, the sum of the c015 size (that is, the sum of the values of c010 and c011) plus its own 4-byte int variable. The same object's memory output also verifies this. The first three bytes are inherited from the parent class, and the last four bytes are their own int variables, with a value of 1.

Therefore, for normal inheritance, the subclass object layout includes the data members in the parent class plus the data members in the subclass. For multi-layer inheritance (such as c016), the top-level class is in front, when multiple inheritance occurs, the leftmost parent class goes first.

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.