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 speakingIn this example:
Basehas a virtual functionSpeak().DerivedoverridesSpeak().
As a result, two vtables are created:
Basehas a vtable with an entry pointing toBase::Speak().Derivedhas 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 inbasepoints to theBasevtable, andBase::Speak()is invoked. - When
CallSpeak(derived)is called, the vptr inderivedpoints to theDerivedvtable, 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