Class Size in C ++

Source: Internet
Author: User

The following discussion is about the result of # pragma pack (Num). Num indicates how many bytes are aligned.

When beginners are Learning Object-oriented programming languages, they have more or less questions. The code we write is quite different from the code that is finally compiled and translated, we don't know what the compiler does in the background. these are all because we only stay at the language layer. The so-called language layer is to teach us some basic syntax rules, but won't tell us why? One thing I want to talk about today is my experience in programming and a specific function of compilers.

First, we need to know what is class instantiation. The so-called class instantiation is to allocate an address in the memory.

Let's take a look at an example:

#include<iostream.h>class a {};class b{};class c:public a{virtual void fun()=0;};class d:public b,public c{};int main(){cout<<"sizeof(a)"<<sizeof(a)<<endl;cout<<"sizeof(b)"<<sizeof(b)<<endl;cout<<"sizeof(c)"<<sizeof(c)<<endl;cout<<"sizeof(d)"<<sizeof(d)<<endl;return 0;}

The output result of program execution is:

sizeof(a) =1sizeof(b)=1sizeof(c)=4sizeof(d)=8

The above is the result compiled in VC ++ 6.0, but the result obtained in Dev-C ++ and code: blocks is sizeof (d) = 4.

Why is this result? Beginners will be very upset, right? Class A and B are clearly empty classes, and their size should be 0. Why is the compiler output 1? This is the reason we just mentioned for instantiation (empty classes can also be instantiated). Each instance has a unique address in the memory. To achieve this, the compiler often implicitly adds a byte to an empty class, so that the empty class gets a unique address in the memory after instantiation. so the size of A and B is 1.

Class C is generated by Class A, which has a pure virtual function. Due to the virtual function, there is a pointer to the virtual function (vptr ), in the 32-bit system, the pointer size is 4 bytes, so the size of class C is 4.

The size of class D is even more confusing for beginners. Class D is derived from Class B and C. Its size should be the sum of 5 and why is it 8? This is because it is used to improve the access efficiency of the instance in the memory. the class size is usually adjusted to an integer multiple of the system. and take the nearest law, in which the nearest multiple is the size of the class, so the size of class D is 8 bytes.

Of course, the results may be different on different compilers, but this experiment tells us that beginners can be instantiated regardless of whether the class is empty or not (empty classes can also be instantiated ), each instance has a unique address.

The compiler I use is VC ++ 6.0.

Let's look at another example.

#include<iostream.h>class a{pivate: int data;};class b{ private:     int data;static int data1;};int b::data1=0;void main(){cout<<"sizeof(a)="<<sizeof(a)<<endl;cout<<"sizeof(b)="<<sizeof(b)<<endl;}

The execution result is:

Sizeof (A) = 4;

Sizeof (B) = 4;

Why is the size of Class B the same as that of Class A when class B has one more data member? This is because the static data member of Class B is put in a global data members program by the compiler, which is a data member of the class. however, it does not affect the size of the class. No matter how many instances the class actually produces or how many new classes are derived, static member data will always have only one entity in the class, non-static data members of a class exist only when they are instantiated. however, once a static data member of a class is declared, it already exists no matter whether the class is instantiated or not. in this case, static data members of a class are special global variables.

So the size of A and B is the same.

Next, let's take a look at the size of a constructor and destructor class. How big is it?

#include<iostream.h>class A{public :A(int a){   x=a;}void f(int x){   cout<<x<<endl;}~A(){}private:   int x;   int g;   };class B{public:private:int data; int data2;static int xs;};int B::xs=0;void main(){A s(10);s.f(10);cout<<"sozeof(a)"<<sizeof(A)<<endl;cout<<"sizeof(b)"<<sizeof(B)<<endl;}
Program Execution output result: 10, sizeof (a) 8 sizeof (B) 8

The results are the same. We can see that the class size is irrelevant to the constructor, destructor, and other member functions in the class. It is only related to the member data in the class.

From the above examples, it is not difficult to find the class size:

1. It is the sum of the types of non-static member data of the class.

2. The size of member variables added by the compiler is used to support certain features of the language (for example, pointers to virtual functions ).

3. Edge adjustment to optimize access efficiency.

4. It is irrelevant to the constructor, destructor, and other member functions in the class.

Memory layout of a virtual inheritance ticket

First read a piece of code

Class A {virtual AA () {};}; Class B: Public Virtual A {char J [3]; // Add a variable to check the position of vfptr in the class public: Virtual BB () {};}; Class C: Public Virtual B {char I [3]; public: Virtual CC (){}
};

I will not give the results this time. I will analyze the results first to enhance my impression.
1. for Class A, because there is only one virtual function, there must be a corresponding virtual function table to record the corresponding function entry address. In the memory space of Class A, A vfptr_a must point to the table. Sizeof (a) is also easy to determine, for 4.
2. for Class B, because Class B is based on class A, it also has its own virtual function. Therefore, Class B first has a vfptr_ B, pointing to its own virtual function table. In addition, char J [3] is used to perform an alignment operation. The general size is 4. How can virtual inheritance be implemented? First, you must add a virtual L class pointer (vbptr_ B _a) to point to its parent class, and then include all the content of the parent class. It's complicated, but it's not hard to imagine. Sizeof (B) = 4 + 4 + 4 + 4 = 16 (vfptr_ B, char
J [3] perform alignment, vbptr_ B _a, and Class ).
3. The next step is Class C. Class C should first have a vfptr_c, then Char I [3], then vbptr_c_ B, and then Class B, so sizeof (c) = 4 + 4 + 4 + 16 = 28 (vfptr_c, char I [3] for alignment, vbptr_c_a, and Class B ).


 

I wrote a program in VC 6.0 and printed the size of the above classes. The results are 4, 16, and 28.

Virtual inheritance memory layout in VC-single inheritance


 

The case of Class A is too simple, no problem. The following conclusions can be drawn from the memory layout diagram of Class B.
1. vf_ptr B is placed in the Class header. It is very dangerous if you want to copy the class directly with memcpy, and it is impossible to use struct.

2. Why is vbtbl_ptr_ B not described previously? This pointer is very different from the content I have previously guessed. This Pointer Points to the virtual class table of Class B. Look at VB table. There are two items in VB table. The first item is fffffffc. The value of this item may be meaningless. It may be to ensure that the virtual table is not empty. The second item is 8, which looks like the shift of Class A in Class B to this vbtbl_ptr_ B, that is, an offset. Similar methods in C ++ object
Model (p121) has an introduction, you can go and have a look.
The memory layout of class C is complicated, but its memory layout also further shows that my understanding of the content in vbtbl_ptr_ B, that is, the virtual table, is correct. However, it is worth noting that Class A in Class B is moved to the front during layout. Although the entire size has not changed, if such an operation is performed C; B * B; B = & C; how does B perform? In this case, you only need to obtain the position of Class B from the virtual class table in C, which can be assigned to B. However, the construction of class C is complicated, and the subsequent use is very simple and efficient. Class
If the memory layout of A is moved forward, you may consider the virtual inheritance sequence of C.


 

Conclusion
1. VC puts vfptr in the Class header during compilation;
2. VC uses the virtual table pointer (vbtbl_ptr) to determine the virtual class inherited by a class.
3. VC will re-adjust the memory layout of the parent class of the virtual inheritance in the subclass. (The specific rules are unclear)
4. the first item in the virtual table in VC is meaningless, probably to ensure sizeof (virtual table )! = 0; the following content is the offset of the parent class in the subclass relative to the virtual class Table pointer.

 #include <iostream> #include <cstdio> using namespace std;  class Base { public:     Base(){};     virtual ~Base(){};     void set_num( int num ) {         a = num;     }     virtual int get_num() {         return a;     } private:     int a;     char *p; };  class Derive : public Base { public:     Derive() : Base(){};     ~Derive(){};     virtual int get_num() {         return d;     } private:     static int st;     int d;     char *p;     char c; };  int main() {     cout << sizeof( Base ) << endl;     cout << sizeof( Derive ) << endl;      return 0; }

The virtual int get_num () function is added to the base class, And the subclass implements the virtual int get_num () function again.

But the result is

12

24

It indicates that the subclass only shares the virtual function table of the parent class. Therefore, once the parent class has a virtual function, the virtual function of the subclass is not included in the sizeof size.

The abstract class concept of a base class and a derived class is a virtual table. However, in an instance of a specific class, for example, a derived class object, it has only one virtual table entry address and points to the virtual table of the abstract class concept of the derived class.

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.