Vtable and Virtual Functions
What is a vtable, and how is it related to virtual functions?
A vtable, or virtual table, is a mechanism used by C++ to support dynamic polymorphism through virtual functions.
It is essentially a table of function pointers, with each entry pointing to the most derived implementation of a virtual function that can be called on a given object.
How Vtables Work
When a class declares or inherits virtual functions, the compiler generates a vtable for that class.
Each instance of the class contains a hidden pointer, often called the vptr (virtual table pointer), that points to the class's vtable.
When a virtual function is called on an object, the program uses the vptr to look up the correct function in the vtable and invokes it.
Here's a simple example:
#include <iostream>
#include <string>
class Base {
public:
virtual void Speak() {
std::cout << "Base speaking\n";
}
};
class Derived : public Base {
public:
void Speak() override {
std::cout << "Derived speaking\n";
}
};
void CallSpeak(Base& obj) {
obj.Speak();
}
int main() {
Base base;
Derived derived;
CallSpeak(base);
CallSpeak(derived);
}
Base speaking
Derived speaking
In this example:
Base
has a virtual functionSpeak()
.Derived
overridesSpeak()
.
As a result, two vtables are created:
Base
has a vtable with an entry pointing toBase::Speak()
.Derived
has its own vtable with an entry pointing toDerived::Speak()
.
These vtables are checked when we call class methods:
- When
CallSpeak(base)
is called, the vptr inbase
points to theBase
vtable, andBase::Speak()
is invoked. - When
CallSpeak(derived)
is called, the vptr inderived
points to theDerived
vtable, andDerived::Speak()
is invoked.
Benefits of Vtables
- Polymorphism: Vtables enable polymorphism by allowing the correct function to be called based on the actual type of the object, not the type of the reference or pointer used to call the function.
- Dynamic Binding: They support dynamic binding, meaning the function to be called is determined at runtime based on the object's vtable.
Considerations
- Overhead: There is a slight overhead in terms of memory and performance due to the vtable and vptr. Each object with virtual functions carries an extra pointer, and each virtual call requires an additional indirection to look up the function pointer in the vtable.
- Complexity: The mechanism adds complexity to the program's runtime behavior and can make debugging more challenging.
Despite the overhead, vtables are crucial for implementing polymorphism in C++, providing flexibility and enabling powerful design patterns.
Pure Virtual Functions
Learn how to create interfaces and abstract classes using pure virtual functions