Class Memory Layout
This page explains how the class features you write โ members, virtual functions, inheritance โ translate into a memory layout. It's the OOP-level intuition; the byte-exact ABI details and tooling live in Object Layout.
- Members sit in declaration order, with padding for alignment (see Memory Alignment).
- Virtual functions add a hidden vtable pointer.
- Base classes are embedded as subobjects.
Members: declaration order + paddingโ
The compiler lays members out in declaration order โ never reordered โ and inserts padding so
each is aligned. That predictability is what makes C interop and offsetof possible.
class Simple {
int a; // offset 0
char b; // offset 4
// 3 bytes padding
int c; // offset 8
};
sizeof(Simple); // 12, not 9
Because you control the order, ordering members largest โ smallest is the cheapest way to shrink a class. The mechanics (alignment rules, why trailing padding exists) are covered once in Memory Alignment; the packing/bit-field options in Padding and offsetof.
Virtual functions add a vptrโ
A class with any virtual function gains a hidden vtable pointer (vptr), conventionally first.
Every object carries the vptr; the vtable itself is shared per type.
class NoVirtual { int data; };
sizeof(NoVirtual); // 4
class WithVirtual { int data; virtual void f(); };
sizeof(WithVirtual); // 16 on 64-bit: 8 (vptr) + 4 (data) + 4 (padding)
So virtual dispatch costs 8 bytes per object plus one indirection per call. How the vtable is built and used for overriding is in Virtual Functions; the byte-level picture across inheritance is in Object Layout.
Empty classes and the empty base optimizationโ
Every object needs a unique address, so even an empty class has sizeof == 1. But an empty base
contributes nothing โ the empty base optimization (EBO) folds it away. This is why stateless
policy/allocator base classes are free.
class Empty {};
sizeof(Empty); // 1 โ needs a distinct address
class Derived : Empty { int value; };
sizeof(Derived); // 4 โ Empty base takes no space (EBO)
Inheritance: bases are subobjectsโ
A base class is embedded whole inside the derived object; derived members follow. With multiple
inheritance, each base is a separate subobject โ which is why converting Derived* to a second
base may adjust the pointer to land on that base's subobject.
struct Base1 { int b1; };
struct Base2 { int b2; };
struct Derived : Base1, Base2 { int d; }; // layout: [b1][b2][d]
If those bases have virtual functions, the derived object carries one vptr per polymorphic base. The diamond/virtual-inheritance cases and their shared-base layout are detailed in Object Layout and Multiple Inheritance.
Standard-layout: the contract for C interopโ
A standard-layout class has a predictable, C-compatible layout โ required for offsetof, for
memcpy-style serialization, and for passing structs to C. The rules in practice: no virtual
functions or virtual bases, and all non-static data members with the same access.
struct Ok { int a; int b; }; // standard-layout
struct NotOk { private: int a; public: int b; }; // mixed access โ not standard-layout
static_assert(std::is_standard_layout_v<Ok>);
Inspecting real layoutโ
Don't guess โ ask the compiler:
g++ -fdump-lang-class file.cpp # GCC
clang++ -Xclang -fdump-record-layouts file.cpp # Clang
cl /d1reportAllClassLayout file.cpp # MSVC
Summaryโ
- Members lay out in declaration order with alignment padding; order them largeโsmall to save space.
- A virtual function adds an 8-byte
vptrper object and one indirection per call. - Empty classes are size 1, but empty bases vanish under the empty base optimization.
- Each base is a subobject; multiple polymorphic bases mean multiple vptrs and pointer adjustment.
- Standard-layout types give the C-compatible layout that
offsetofand serialization rely on.
Relatedโ
- Object Layout โ byte-exact ABI view, vtables, virtual inheritance
- Virtual Functions โ how the vtable enables overriding
- Memory Alignment ยท Padding and offsetof