DevAcademia lesson/C++ Classes
Virtual Functions
Topic progressTopic 98 of 109 - 90% complete
~12 min lesson34 learning blocks5 code examples1 checks/interactions
Lesson outline
Virtual Function Mechanics
Virtual functions enable runtime polymorphism. While the C++ standard does not mandate a specific layout, most implementations use:
- Compile-time: The compiler emits metadata (e.g., a vtable) and arranges for a per-subobject pointer (often called a vptr) in polymorphic types.
- Runtime: The vptr selects the appropriate function implementation (dynamic dispatch).
Typical vtable contents/associations include:
- Pointers to the class's virtual functions (possibly with thunks for adjustments)
- A way to reach RTTI (type_info), implementation-dependent
- Offsets/adjusters for multiple/virtual inheritance when needed
Pure Virtual Functions & Abstract Classes
Pure virtual functions (declared with = 0):
- Make a class abstract (it cannot be instantiated).
- Must be overridden in a concrete derived class for that class to be instantiable.
- May still provide a definition in the base (rare but legal).
Abstract classes can also contain data members and implemented methods.
override & final Keywords
override:
- Marks a function as overriding a virtual function in a base; the compiler diagnoses mismatches.
final:
- Applied to a virtual function: prevents further overriding.
- Applied to a class: prevents further inheritance from that class (but methods in that class may still override its base).
Virtual Destructors
Rules for polymorphic destruction:
- Declare base destructors virtual when deleting objects via base pointers/references.
- Derived destructors are implicitly virtual if the base destructor is virtual.
- Destruction order is derived first, then base.
If the base destructor is non-virtual and you delete via a base pointer to a derived object, behavior is undefined and resources may leak.
Virtual Calls in Constructors/Destructors
During base-class construction and destruction, dynamic dispatch is suppressed: the effective dynamic type is the class currently being constructed/destructed.
- Overridden functions in derived classes are not called from base constructors/destructors.
- Calling a pure virtual function in a constructor/destructor leads to a runtime error ("pure virtual call").
Performance Optimization
- Devirtualization: Compilers may resolve some virtual calls at compile time (especially on
finalclasses/methods or with whole-program optimization). - Use
finalon classes/methods when further overriding is unnecessary. - Profile-guided and link-time optimizations can improve indirect-call performance.
- Avoid virtual calls in tight, performance-critical loops; consider CRTP/templates for compile-time polymorphism when appropriate.
Was this topic clear?