How C++ Calls the Correct Method with virtual
Functions (Dynamic Dispatch)
How does the computer know whether to call Rectangle::Render()
or GreenRectangle::Render()
when using pointers?
The mechanism that allows C++ to call the correct derived class function through a base class pointer at runtime relies on the virtual
keyword and is typically implemented using Virtual Tables (vtables).
Here's a conceptual breakdown:
1. The virtual
Keyword Signal
First, you must mark the function as virtual
in the base class (Rectangle
).
class Rectangle {
public:
virtual void Render(SDL_Surface* Surface) const;
// ... other virtual functions like HandleEvent ...
virtual ~Rectangle(); // Virtual destructor
// ...
};
Derived classes like GreenRectangle
can then use the override
keyword to indicate they are intentionally providing their own version of a virtual function.
class GreenRectangle : public Rectangle {
public:
// Override the virtual function from Rectangle
void Render(SDL_Surface* Surface) const override;
// ...
};
2. The Virtual Table (vtable)
When a class has one or more virtual
functions, the compiler usually generates a hidden static array associated with that class. This array is called the Virtual Table or vtable.
- The vtable for a class contains function pointers. Each entry points to the correct implementation of a virtual function for that specific class.
- For
Rectangle
, its vtable would contain pointers toRectangle::Render
,Rectangle::HandleEvent
,Rectangle::~Rectangle
, etc. - For
GreenRectangle
, its vtable would contain pointers toGreenRectangle::Render
(if overridden),GreenRectangle::HandleEvent
(if overridden),GreenRectangle::~GreenRectangle
, etc. If a virtual function is not overridden in the derived class, its vtable entry will point to the implementation in the base class.
3. The Virtual Pointer (vptr)
Each object (instance) of a class that has virtual functions (or derives from such a class) typically contains a hidden data member: the Virtual Pointer or vptr.
- This vptr is automatically set by the object's constructor.
- The vptr points to the vtable associated with the object's actual class. A
Rectangle
object's vptr points to theRectangle
vtable. AGreenRectangle
object's vptr points to theGreenRectangle
vtable.
4. Putting It Together: The Runtime Call
Now, consider the call ptr->Render(surface)
, where ptr
is a Rectangle*
but might be pointing to a GreenRectangle
object:
- Follow the vptr: The program uses the
ptr
to access the object's hidden vptr. - Find the vtable: The vptr leads the program to the correct vtable (either
Rectangle
's orGreenRectangle
's, depending on the actual object). - Lookup the Function: The program looks up the function pointer for
Render
within that specific vtable. The compiler knows which slot or index in the vtable corresponds to theRender
function. - Indirect Call: The program calls the function located at the address found in the vtable slot.
This process happens entirely at runtime. The vptr lookup ensures that even though the call is made through a base class pointer, the function executed is the one belonging to the object's actual derived type. This is the essence of dynamic dispatch and polymorphism in C++.
Structuring SDL Programs
Discover how to organize SDL components using manager classes, inheritance, and polymorphism for cleaner code.