C++ internals: mapping inheritance and virtual functions to C

EventHelix
Software Design
Published in
3 min readJun 3, 2017

We look at mapping from C++ inheritance and virtual functions to C code.

Mapping a base class with virtual functions to C

A C++ base class with virtual functions requires extra logic to support the machinery for handling virtual functions. The following C++ base class….

class Shape
{
protected:
int m_x;
int m_y;

public:
virtual void Draw() = 0;
virtual void MoveTo(int newX, int newY);
void Erase();
Shape(int x, int y);
virtual ~Shape();
};

…maps to the following C code.

typedef void (*VirtualFunctionPointer)(...);

struct VTable
{
int d; /* d and i are used in multiple inheritance */
int i;
VirtualFunctionPointer pFunc;
};

VTable VTableArrayForShape[] =
{
{ 0, 0, (VirtualFunctionPointer) pure_virtual_called_error_handler },
{ 0, 0, (VirtualFunctionPointer) Shape_MoveTo },
{ 0, 0, (VirtualFunctionPointer) Shape_Destructor }
};
struct Shape
{
int m_x;
int m_y;
VTable *pVTable;
};

Points to note here are:

  • VTable structure used by the compiler to keep track of the virtual functions associated with a class.There is one instance of a VTable for every class containing virtual functions. All instances of a given class point to the same VTable.
  • The C++ compiler inserts an extra pointer to a vtable which will keep a function pointer to the virtual function that should be called.
  • The VTable pointer in the base class points to an array of VTables. The number of entries in the array of VTables depends upon the number of virtual functions in the class.
  • Note that a pure virtual function maps to function that will result in an exception.

For details refer to the article: Mapping from C++ inheritance and virtual functions to C code.

Mapping an inherited class with virtual functions to C

The inheriting Circle class…

class Circle : public Shape
{
private:
int m_radius; // Radius of the circle

public:
// Override to draw a circle
virtual void Draw();

// Constructor for Circle
Circle(int x, int y, int radius);

// Destructor for Circle
virtual ~Circle();
};

…maps to a new VTable array and a new struct:

VTable VTableArrayForCircle[] =
{
{ 0, 0, (VirtualFunctionPointer) Circle_Draw },
{ 0, 0, (VirtualFunctionPointer) Shape_MoveTo },
{ 0, 0, (VirtualFunctionPointer) Circle_Destructor }
};

struct Circle
{
/* Fields inherited from Shape */
int m_x;
int m_y;
VTable *pVTable;

/* Fields added by Circle */
int m_radius;
};
  • The inheriting class preserves structure offsets for inherited base class fields and the VTable array pointers.
  • A new VTable array is defined for the inherited class.
  • The pure virtual function entry has now been replaced with a call to Circle’s Draw function.
  • The entry for a function that is not being inherited is preserved (Shape’s MoveTo)
  • Shape class has a virtual destructor. The destructor vtable entry now points to Circle’s destructor.

For details refer to the article: Mapping from C++ inheritance and virtual functions to C code.

Mapping a virtual function call to C code

A virtual function call like…

pShape->Draw();

…is replaced by a call through a virtual table function pointer.

(pShape->pVTable[0].pFunc)(pShape);

Explore More

We have covered basics of inheritance handling here. For details about constructor and destructor definitions and vtable array pointer initialization refer to the article: Mapping from C++ inheritance and virtual functions to C code.

--

--