Explore C++ class memory distribution together
What is the memory distribution in C++ classes, especially when C++ contains inheritance, virtual functions, virtual inheritance, and diamond inheritance.
linux
Since there is no windows
lower display intuitively, we use vs2015
it for debugging.
Deployment environment
We are in
属性->C/C++ ->命令行 -> /d1 reportSingleClassLayoutXXX
, XXX represents the class name;
single base class
class Base { private: int a; int b; public: void test(); };
Memory distribution:
class Base size(8): +-- - 0 | a 4 | b +-- -
Summary : We found that the memory distribution of ordinary classes is carried out according to the order of declaration, and member functions do not occupy memory.
base class + inherited class
class Base { int a; int b; public: void test(); }; class Divide :public Base { public: void run(); private: int c; int d; };
Memory distribution:
class Divide size(16) : +-- - 0 | +-- - (base class Base) 0 | | a 4 | | b | +-- - 8 | c 12 | d +-- -
Summary : According to the memory distribution, we found that for common inherited classes, the memory distribution is also carried out in the order of declaration, and member functions do not occupy memory; the order of classes is the base class first, then the subclass.
base class with virtual functions
class Base { int a; int b; public: void test(); virtual void run(); };
Memory distribution:
class Base size(12) : +-- - 0 | {vfptr} 4 | a 8 | b +-- - Base::$vftable@: | &Base_meta | 0 0 | &Base::run
Summary : The memory distribution with virtual functions is divided into two parts, one is the memory distribution, and the other is the virtual table; we found from the top that it
vfptr
is placed at the beginning of the memory, and then the member variables;run
the front of the virtual function indicates this virtual table. The sequence number of the function is0
.
Base class with virtual function + inherited subclass
class Base { int a; int b; public: void test(); virtual void run(); }; class Divide :public Base { public: void DivideFun(); virtual void run(); private: int c; int d; };
Memory distribution:
class Divide size(20) : +-- - 0 | +-- - (base class Base) 0 | | {vfptr} 4 | | a 8 | | b | +-- - 12 | c 16 | d +-- - Divide::$vftable@: | &Divide_meta | 0 0 | &Divide::run
Summary : We found that the inherited class has only one virtual table, and it is still at the beginning of the memory, and the memory arrangement order is the same as that of the ordinary inherited class;
Base class with virtual function + inherited subclass (add one more virtual function)
class Base { int a; int b; public: void test(); virtual void run(); }; class Divide :public Base { public: void DivideFun(); virtual void run(); virtual void DivideRun(); private: int c; int d; };
Memory distribution:
class Divide size(20) : +-- - 0 | +-- - (base class Base) 0 | | {vfptr} 4 | | a 8 | | b | +-- - 12 | c 16 | d +-- - Divide::$vftable@: | &Divide_meta | 0 0 | &Divide::run 1 | &Divide::DivideRun
Summary : The virtual table is still inherited from the base class, and there are more virtual functions with the
DivideRun
serial number in the virtual table part;1
multiple inheritance
class Base { int a; int b; public: virtual void run(); }; class Divide1 :public Base { public: virtual void run(); private: int c; }; class Divide2 :public Base { public: virtual void run(); private: int d; }; class Divide :public Divide1, Divide2 { public: virtual void run(); private: int d; };
Memory distribution:
class Divide1 size(16) : +-- - 0 | +-- - (base class Base) 0 | | {vfptr} 4 | | a 8 | | b | +-- - 12 | c +-- - Divide1::$vftable@: | &Divide1_meta | 0 0 | &Divide1::run Divide1::run this adjustor: 0 class Divide2 size(16) : +-- - 0 | +-- - (base class Base) 0 | | {vfptr} 4 | | a 8 | | b | +-- - 12 | d +-- - Divide2::$vftable@: | &Divide2_meta | 0 0 | &Divide2::run Divide2::run this adjustor: 0 class Divide size(36) : +-- - 0 | +-- - (base class Divide1) 0 | | +-- - (base class Base) 0 | | | {vfptr} 4 | | | a 8 | | | b | | +-- - 12 | | c | +-- - | +-- - (base class Divide2) | | +-- - (base class Base) | | | {vfptr} | | | a | | | b | | +-- - | | d | +-- - | d +-- - Divide::$vftable@Divide1@: | &Divide_meta | 0 0 | &Divide::run Divide::$vftable@Divide2@: | -16 0 | &thunk: this -= 16; goto Divide::run Divide::run this adjustor: 0
Summary: mainly look at the last
Divide
class, the memory order is Divide1 first, then Divide2, and there is a virtual table in Divide1 and Divide2;
Virtual inheritance (diamond inheritance)
class Base { int a; int b; public: virtual void run(); }; class Divide1 :virtual public Base { public: virtual void run(); private: int c; }; class Divide2 :virtual public Base { public: virtual void run(); private: int d; }; class Divide :public Divide1, Divide2 { public: virtual void run(); private: int d; };
Memory distribution:
class Divide1 size(20) : +-- - 0 | {vbptr} 4 | c +-- - +-- - (virtual base Base) 8 | {vfptr} 12 | a 16 | b +-- - Divide1::$vbtable@: 0 | 0 1 | 8 (Divide1d(Divide1 + 0)Base) Divide1::$vftable@: | -8 0 | &Divide1::run Divide1::run this adjustor: 8 vbi: class offset o.vbptr o.vbte fVtorDisp Base 8 0 4 0 class Divide2 size(20) : +-- - 0 | {vbptr} 4 | d +-- - +-- - (virtual base Base) 8 | {vfptr} 12 | a 16 | b +-- - Divide2::$vbtable@: 0 | 0 1 | 8 (Divide2d(Divide2 + 0)Base) Divide2::$vftable@: | -8 0 | &Divide2::run Divide2::run this adjustor: 8 vbi: class offset o.vbptr o.vbte fVtorDisp Base 8 0 4 0 class Divide size(32) : +-- - 0 | +-- - (base class Divide1) 0 | | {vbptr} 4 | | c | +-- - 8 | +-- - (base class Divide2) 8 | | {vbptr} 12 | | d | +-- - 16 | d +-- - +-- - (virtual base Base) 20 | {vfptr} 24 | a 28 | b +-- - Divide::$vbtable@Divide1@: 0 | 0 1 | 20 (Divided(Divide1 + 0)Base) Divide::$vbtable@Divide2@: 0 | 0 1 | 12 (Divided(Divide2 + 0)Base) Divide::$vftable@: | -20 0 | &Divide::run
Summary: From the memory distribution, we can see that
Divide1
andDivide2
are two virtual tables, but Divide has become three virtual tables and only one base; so: the role of virtual inheritance is to reduce the repetition of base classes, at the cost of increasing Reduces the burden of virtual table pointers (adds more required pointers)