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.