In C++, the memory layout of a class, both with and without virtual methods in the case of class hierarchy, is determined by how the compiler organizes the various components of the class. Let’s explore both scenarios:
Memory layout of a C++ Class without Virtual Methods:
Consider a simple class without any virtual methods:
class MyClass {
public:
int x;
double y;
char z;
};
The memory layout of an object of the class MyClass will typically be contiguous in memory and follow the declaration order of its members:
| int x | double y | char z |
Here, the members x, y, and z are laid out in memory one after the other. The size of an object of MyClass is the sum of the sizes of its individual members, and the alignment of the members might also introduce padding between them.
Memory layout of a C++ Class with Virtual Function(s) in the Base Class:
Consider a base class with a virtual function:
class Base {
public:
int x;
virtual void print() const;
};
The memory layout of an object of the class Base with a virtual function would look like this:
| vtable ptr | int x |
- vtable ptr: This is the hidden pointer (usually the first element) that points to the virtual function table (vtable) for the class Base. It enables dynamic dispatch of virtual functions.
- int x: This is the member variable of the class Base.
The vtable for the class Base will contain a pointer to the print() function (the only virtual function in this case). If there were more virtual functions in the Base class, the vtable would have pointers to all those virtual functions.
Memory layout of a C++ Class with Virtual Function(s) in the Derived Class (Class Hierarchy):
Consider a derived class that inherits from the Base class and has additional members:
class Derived : public Base {
public:
double y;
void print() const override;
};
The memory layout of an object of the class Derived, which inherits from Base, would look like this:
| vtable ptr | int x | double y |
- vtable ptr: This is the hidden pointer (usually the first element) that points to the virtual function table (vtable) for the class Derived. It enables dynamic dispatch of virtual functions.
- int x: This is the member variable of the base class Base, which is inherited by Derived.
- double y: This is the member variable of the class Derived.
The vtable for the class Derived will contain a pointer to the print() function of Derived. If Derived overrides multiple virtual functions from Base, the vtable would have pointers to all those overridden functions.
It’s important to note that for classes with virtual functions, there is a memory overhead due to the presence of the vtable pointer. This overhead is usually one machine word (the size of a pointer) per object instance.
In summary,
the memory layout of a class hierarchy with virtual functions involves adding a hidden vtable pointer to each class in the hierarchy that has virtual functions. The vtable pointers in each class point to their respective virtual function tables, and the rest of the memory layout follows the order of member variables in each class.