Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Runtime Polymorphism with Virtual Functions Summary
Review and test your understanding of all virtual function and polymorphism concepts covered in this chapter.
Virtual Functions recap
Excellent work! You've mastered inheritance and virtual functions in C++. Let's review the key concepts from this section.
Base Class Pointers and References
C++ allows you to set base class pointers and references to a derived object. This is useful when we want to write a function or array that can work with any type of object derived from a base class.
Without virtual functions, base class pointers and references to a derived class will only have access to base class member variables and versions of functions.
Virtual Functions and Overrides
A virtual function is a special type of function that resolves to the most-derived version of the function (called an override) that exists between the base and derived class. To be considered an override, the derived class function must have the same signature and return type as the virtual base class function. The one exception is for covariant return types, which allow an override to return a pointer or reference to a derived class if the base class function returns a pointer or reference to the base class.
A function that is intended to be an override should use the override specifier to ensure that it is actually an override.
The final specifier can be used to prevent overrides of a function or inheritance from a class.
Virtual Destructors
If you intend to use inheritance, you should make your destructor virtual, so the proper destructor is called if a pointer to the base class is deleted.
Scope Resolution and Virtual Resolution
You can ignore virtual resolution by using the scope resolution operator to directly specify which class's version of the function you want: e.g. storage.Storage::getType().
Early Binding vs Late Binding
Early binding occurs when the compiler encounters a direct function call. The compiler or linker can resolve these function calls directly. Late binding occurs when a function pointer is called. In these cases, which function will be called can not be resolved until runtime. Virtual functions use late binding and a virtual table to determine which version of the function to call.
Using virtual functions has a cost: virtual functions take longer to call, and the necessity of the virtual table increases the size of every object containing a virtual function by one pointer.
Pure Virtual Functions and Abstract Classes
A virtual function can be made pure virtual/abstract by adding "= 0" to the end of the virtual function prototype. A class containing a pure virtual function is called an abstract class, and can not be instantiated. A class that inherits pure virtual functions must concretely define them or it will also be considered abstract. Pure virtual functions can have a body, but they are still considered abstract.
Interface Classes
An interface class is one with no member variables and all pure virtual functions. These are often named starting with a capital I.
Virtual Base Classes
A virtual base class is a base class that is only included once, no matter how many times it is inherited by an object.
Object Slicing
When a derived class is assigned to a base class object, the base class only receives a copy of the base portion of the derived class. This is called object slicing.
Dynamic Casting and Downcasting
Dynamic casting can be used to convert a pointer to a base class object into a pointer to a derived class object. This is called downcasting. A failed conversion will return a null pointer.
Overloading operator<< for Inherited Classes
The easiest way to overload operator<< for inherited classes is to write an overloaded operator<< for the most-base class, and then call a virtual member function to do the printing.
Key Terminology
- Virtual function: Function resolved to most-derived version at runtime
- Override: Derived class version of a virtual function
- override specifier: Keyword ensuring function is actually an override
- final specifier: Keyword preventing further overrides or inheritance
- Covariant return type: Override returning derived pointer/reference when base returns base pointer/reference
- Virtual destructor: Destructor declared virtual for proper cleanup through base pointers
- Early binding: Function call resolved at compile time
- Late binding: Function call resolved at runtime
- Virtual table (vtable): Data structure storing virtual function pointers
- Pure virtual function: Virtual function with no implementation (= 0)
- Abstract class: Class with at least one pure virtual function
- Interface class: Class with only pure virtual functions and no data members
- Virtual base class: Base class included only once in diamond inheritance
- Object slicing: Losing derived portion when assigning to base class object
- Dynamic casting: Runtime conversion between related class types
- Downcasting: Converting base class pointer/reference to derived class
Looking Forward
You've completed your journey through inheritance and virtual functions in C++. These powerful features enable polymorphism and are fundamental to object-oriented design. The concepts you've learned—virtual functions, abstract classes, interfaces, dynamic casting, and proper memory management with virtual destructors—are essential tools for building flexible, maintainable C++ applications. As you move forward, you'll discover how these principles integrate with other advanced C++ features to create robust software systems.
Runtime Polymorphism with Virtual Functions Summary - Quiz
Test your understanding of the lesson.
Practice Exercises
Polymorphic Animal Simulation
Create a polymorphic animal simulation using virtual functions, abstract base classes, and runtime polymorphism. Animals can speak, move, and be managed through base class pointers.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!