C++ virtual functions allow derived classes to override a base class function, enabling dynamic polymorphism and ensuring the correct function is called for an object, regardless of the reference type.
#include <iostream>
class Base {
public:
virtual void show() {
std::cout << "Base class show function called." << std::endl;
}
};
class Derived : public Base {
public:
void show() override {
std::cout << "Derived class show function called." << std::endl;
}
};
int main() {
Base* b = new Derived();
b->show(); // Calls Derived's show() function
delete b;
return 0;
}
What are Virtual Functions in C++?
Virtual functions in C++ are a powerful feature that enables dynamic polymorphism, allowing a member function to be overridden in derived classes. This mechanism provides a way for C++ to decide at runtime which function to invoke when dealing with objects of a derived class through a base class pointer or reference.
Unlike regular functions, which are resolved at compile time, virtual functions are resolved at runtime. This flexibility is essential in applications where behavior can change based on the actual type of the object, rather than the type of the reference or pointer.

Why Use Virtual Functions?
Using virtual functions is crucial for several reasons:
-
Dynamic Polymorphism: Virtual functions allow you to invoke derived class methods via base class pointers. This means that you can write code that operates on base class types but behaves according to the derived class type that is instantiated.
-
Extensibility: They promote extensibility in code. When you define a virtual function in a base class, you can create new derived classes with their own specific behavior without modifying the existing code.
-
Encapsulation of Behavior: Virtual functions allow related class types to share a common interface while having distinct implementations. This encapsulation enhances the organization of your code.

The Role of the Virtual Keyword
The `virtual` keyword indicates that the function defined in the base class can be overridden in any derived class. This keyword serves as a promise that the method's implementation may change based on an object's actual type, irrespective of the reference type used to access it.
Syntax of Virtual Functions in C++
To create a virtual function in C++, you simply declare it using the `virtual` keyword in the base class. Here’s a basic example:
class Base {
public:
virtual void show() {
std::cout << "Base class" << std::endl;
}
};
In the example above, `show` is a virtual function that output "Base class" when invoked. This method can later be overridden in derived classes.

Types of Virtual Functions
Pure Virtual Functions
A pure virtual function serves as an abstract function that does not provide an implementation in the base class and must be overridden in the derived class. It is declared by using `= 0` in its declaration. This tactic is employed when you want to create abstract classes that cannot be instantiated directly.
Example:
class AbstractBase {
public:
virtual void show() = 0; // pure virtual function
};
In this case, `AbstractBase` cannot be instantiated, as it contains a pure virtual function.
Virtual Methods in Derived Classes
Overriding a virtual function in a derived class allows you to provide a specific implementation. When invoking the overridden method through a base class reference, the derived class's version is called:
class Derived : public Base {
public:
void show() override { // overriding base class function
std::cout << "Derived class" << std::endl;
}
};
When you create an instance of `Derived` and call `show` via a `Base` pointer, the derived class's version will execute.

How Virtual Function Calls Work
The runtime mechanism that allows virtual functions to work is known as the Virtual Table (VTable). Each class that has virtual functions maintains a VTable, which is essentially a table of pointers to the virtual functions available for that class. Upon creating an instance of a class, a pointer to the corresponding VTable is also generated.
When a virtual function is called, the C++ runtime will look up the corresponding entry in the VTable of the object being referred to, allowing the appropriate function to be invoked based on the object's actual type at runtime.

The Importance of the Destructor
In C++, when you have virtual functions in a class, you should also provide a virtual destructor. This ensures that the destructor of the derived class is called when an object is deleted through a base class pointer, preventing resource leaks and undefined behavior.
Example:
class Base {
public:
virtual ~Base() { } // virtual destructor
};
If the destructor is not virtual, deleting a derived class object through a base class pointer will result in only the base class's destructor being called, leading to incomplete destruction of the derived class object.

Performance Considerations with Virtual Functions
While virtual functions provide significant advantages in terms of flexibility and code organization, they introduce performance overhead, primarily due to the added indirection required for VTable lookups. However, this overhead is generally negligible for most applications.
Avoid using virtual functions in performance-critical sections or in simple class hierarchies where polymorphic behavior is not needed.
Best Practices for Using Virtual Functions
- Only declare functions as virtual if they absolutely need to support polymorphism.
- Prefer using pure virtual functions in abstract classes to enforce derived classes to implement specific functionalities.
- Avoid complex hierarchies; keep it simple to minimize the overhead.

Advanced Concepts Related to Virtual Functions
Virtual Inheritance
Virtual inheritance resolves the problem of how to handle multiple inheritance, especially the diamond problem. Using virtual inheritance ensures that only one instance of a base class is shared among the derived classes.
Example:
class A {
public:
int value;
A() : value(5) {}
};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
In this structure, class `D` inherits from both `B` and `C`, both of which virtually inherit from `A`, ensuring that `D` contains a single instance of `A`.
Final Specifier in C++11 and Beyond
The `final` specifier can be applied to virtual functions to prevent further overriding in derived classes. This helps maintain the original behavior of a class when no further changes are desired.
Example:
class Base {
public:
virtual void show() final { std::cout << "Base class final" << std::endl; }
};
In this case, `show` cannot be overridden in classes derived from `Base`, providing a safeguard against unintended alterations.

Summarizing the Importance of Virtual Functions
In conclusion, C++ virtual functions are essential for achieving dynamic behavior through polymorphism, which significantly enhances the design and flexibility of object-oriented programs.
By understanding the mechanics, syntax, and proper practices surrounding virtual functions, programmers can create robust and maintainable C++ applications that leverage the full power of object-oriented design principles.

Example Implementation of Virtual Functions
Here’s a complete example that combines various concepts:
#include <iostream>
class Shape {
public:
virtual void draw() = 0; // pure virtual function
virtual ~Shape() { } // virtual destructor
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};
class Square : public Shape {
public:
void draw() override {
std::cout << "Drawing Square" << std::endl;
}
};
void render(Shape* shape) {
shape->draw();
}
int main() {
Circle circle;
Square square;
render(&circle); // Drawing Circle
render(&square); // Drawing Square
return 0;
}
This example illustrates polymorphism, using a base class pointer to call derived class methods, highlighting the strength of cpp virtual functions in action.

Practice Exercises for Readers
- Create an abstract class `Vehicle` with a pure virtual function `display()`. Implement two derived classes: `Car` and `Bike` that override this function.
- Experiment with the VTable by creating a hierarchy that includes at least one class with a virtual destructor.
- Explore the effects of using and not using virtual functions by comparing output in case of function overriding versus regular functions.
This engaging exploration of cpp virtual functions serves as a foundation for building complex and adaptable programs in C++.