In this blog, we will be learning all about virtual functions in C++. We will discuss what they are, their rules, how to use them, and the differences between compile-time and runtime behaviors of virtual functions. Additionally, we will also be learning pure virtual functions, providing an overview of their role in C++ programming.
Table of Contents
Check out our YouTube video on C programming language for the absolute beginners:
What is a Virtual Function in C++?
In C++, a virtual function is a member function within a base class that’s designed to be overridden in its derived classes. It allows a specific function to be reimplemented in the derived class while preserving a common interface across all derived classes. This concept is required for implementing runtime polymorphism.
When a function is declared “virtual” in a base class, it enables late binding or dynamic binding that ensures the correct overridden function in the derived class is invoked during runtime. This feature executes the function of the derived class when a pointer or reference to the base class type is used. Virtual functions make code more flexible by using a dynamic method of resolution that provides efficient utilization of polymorphism in complex object-oriented designs.
Rules of Virtual Functions in C++
Virtual function rules are important to ensure a consistent and structured approach while implementing dynamic polymorphism in C++. Here are the rules that must be followed while writing a virtual function in C++:
- Virtual functions cannot be static and must be declared in the base class to be overridden in derived classes.
- Friend functions can be virtual, offering access to private or protected members of the class.
- To achieve runtime polymorphism, virtual functions should be accessed through pointers or references of the base class.
- The prototype of virtual functions must match both the base and derived classes for proper overriding.
- Overriding a virtual function in derived classes is optional; otherwise, the base class’s version is used.
- While a class can have a virtual destructor, a virtual constructor is not permitted in C++.
How to Use a Virtual Function in C++
To use a virtual function in C++, follow these steps:
- Define a virtual function in the base class by declaring it with the “virtual” keyword.
- Implement the virtual function in the base class.
- Optionally, override the virtual function in derived classes to provide specific implementations.
- Access the virtual function through a pointer or reference to the base class to achieve dynamic binding at runtime.
- Utilize the virtual function in your code to enable polymorphic behavior based on the actual object type.
Get 100% Hike!
Master Most in Demand Skills Now!
Example of a Virtual Function in C++
In C++, a virtual function enables runtime polymorphism, allowing a base class pointer to call overridden functions in derived classes. Let’s consider an example with a base class Shape and its derived classes Circle and Square, each having its own draw() method.
#include <iostream>
class Shape {
public:
virtual void draw() { std::cout << "Drawing a Shape" << std::endl; }
};
class Circle : public Shape {
public:
void draw() override { std::cout << "Drawing a Circle" << std::endl; }
};
class Square : public Shape {
public:
void draw() override { std::cout << "Drawing a Square" << std::endl; }
};
int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();
shape1->draw(); // Calls Circle's draw()
shape2->draw(); // Calls Square's draw()
delete shape1;
delete shape2;
return 0;
}
In the above example, Base Class ‘Shape’ contains a virtual function draw() that serves as an interface for its derived classes. This function is marked as virtual, indicating that it can be overridden by derived classes. Both derived classes, Circle and Square, inherit from the Shape class and override the draw() function with their specific implementations. Pointers of the base class type (Shape*) are used to hold derived class objects Circle and Square. When calling shape1->draw() or shape2->draw(), even though the pointers are of type Shape*, the appropriate derived class’s draw() method is invoked. This happens because of the implementation of late binding or runtime polymorphism by the virtual function. It allows the correct overridden method draw() of class Circle or Square to be called based on the actual object type.
Compile Time (Early Binding) Vs. Runtime (Late Binding) Behavior
This table summarizes the key distinctions between early binding and late binding behaviors by virtual functions based on characteristics in terms of method resolution, flexibility, performance, and usage in C++.
Aspect | Compile-Time (Early Binding) | Runtime (Late Binding) |
Method Resolution | Resolved at compile time | Executed until runtime (dynamically determined) |
Decision Timing | Method call determined by pointer/reference type | Method call determined by the object’s actual type |
Flexibility | Limited polymorphism and extensibility | Enhanced polymorphism, allowing for code extensibility |
Performance | Faster execution due to static binding | Slightly slower execution due to dynamic binding |
Function Call Resolution | Bound directly to the method associated with the type | Invokes the appropriate derived class method |
Usage | Non-virtual functions and regular member function | Virtual functions enabling runtime polymorphism |
Pure Virtual Function in C++
A pure virtual function in C++ is a virtual function that is declared in a base class but has no implementation provided in that class. It is denoted by assigning 0 to the function declaration, making it mandatory for any derived class to implement it. Classes containing pure virtual functions are known as abstract classes and cannot be instantiated; they are designed to serve as base classes for other classes to inherit from.
#include <iostream>
// Abstract class with a pure virtual function
class Shape {
public:
// Pure virtual function
virtual void area() = 0;
};
// Derived class implementing the pure virtual function
class Circle : public Shape {
public:
void area() override {
std::cout << "Area of circle: πr^2" << std::endl;
}
};
int main() {
// Shape* pointer to Circle object
Shape* shape = new Circle();
shape->area(); // Calls the overridden area() function in Circle
delete shape; // Free memory
return 0;
}
In the above example, the Shape class contains a pure virtual function area() with no implementation. The Circle class inherits from Shape and provides an implementation for the area() function. In the main() function, a pointer of type Shape is created and assigned the address of a Circle object. When shape->area() is called, it invokes the overridden area() function in Circle, printing the area of the circle.
Conclusion
Understanding virtual functions in C++ is fundamental for achieving polymorphic behavior and implementing runtime binding. They enable dynamic method resolution, allowing different classes to override base class functions and facilitating flexibility and extensibility in object-oriented programming. The concept of virtual functions enhances code reusability, scalability, and the creation of robust class hierarchies. Embracing virtual functions optimizes code structure and facilitates the development of efficient, maintainable software systems.