Object-Oriented Programming
Polymorphism
Virtual functions and runtime polymorphism
Interview: Critical OOP concept
Polymorphism
Polymorphism allows objects of different types to be treated through a uniform interface. C++ supports two kinds: compile-time (static) polymorphism via templates and function overloading, and runtime (dynamic) polymorphism via virtual functions and inheritance.
How Virtual Functions Work (vtable)
Every class with virtual functions has a vtable (virtual dispatch table) — an array of function pointers to the most-derived overrides. Each object of a polymorphic class contains a hidden pointer (vptr) to its class's vtable. Virtual function calls dereference the vptr to find the correct function — one level of indirection.
override and final
override (C++11) tells the compiler the function is intended to override a base virtual. If the signature doesn't match, it's a compile error — catches typos. final prevents further overriding of a virtual function or further derivation from a class.
Interview Corner
Q: What is the overhead of virtual function calls?
A: Each virtual call requires: (1) loading the vptr from the object, (2) indexing into the vtable to find the function pointer, (3) an indirect call. This is ~1-2 extra memory accesses vs a direct call. The bigger cost is that indirect calls cannot be inlined and may cause branch mispredictions. For hot paths with millions of calls, this matters. For typical code, virtual call overhead is negligible.
Q: What is the difference between overriding and overloading?
A: Overloading is multiple functions with the same name but different parameters — resolved at compile time (static dispatch). Overriding is providing a new implementation of a base class virtual function in a derived class — resolved at runtime (dynamic dispatch). Overloading is not polymorphism; overriding is.
Common Pitfalls
- Forgetting override keyword: A misspelled or signature-mismatched function silently creates a new function instead of overriding — a common bug. Always use override.
- Object slicing in containers: Storing derived objects in a
vector<Base>instead ofvector<unique_ptr<Base>>slices off derived members and loses polymorphic behavior.
Best Practices
- Always use
overrideon derived virtual functions for compile-time safety. - Store polymorphic objects via pointer or reference (preferably
unique_ptr) to avoid object slicing.