Understanding Interfaces in C++: A Beginner's Practice Guide with Pure Virtual Classes
Introduction
In C++, there is no dedicated interface keyword as found in programming languages such as Java or C#. Instead, interfaces are implemented using abstract classes that contain one or more pure virtual functions.
An interface defines a contract that specifies what operations a class must perform without providing the implementation details. Any class inheriting from the interface is required to implement all of its pure virtual functions. This approach promotes abstraction, flexibility, and polymorphism while encouraging a clean separation between interface and implementation.
This document presents two practical examples demonstrating how interfaces are created and used in C++ through abstract classes and pure virtual functions.
Example 1: The NotificationProvider Interface
This example demonstrates an interface that defines a common contract for sending notifications. Different notification services, such as SMS and Email, provide their own implementations while sharing the same interface.
Program
Explanation
The program defines an abstract class named NotificationProvider. This class contains a pure virtual function named sendAlert(), making it an interface. Since it is an abstract class, objects of NotificationProvider cannot be created directly.
Two concrete classes, SMSNotification and EmailNotification, inherit from the interface and provide their own implementations of the sendAlert() function. Although both classes perform the same operation conceptually, each uses a different implementation for sending notifications.
Inside the main() function, pointers of type NotificationProvider are used to reference objects of the derived classes. When the sendAlert() function is called through these interface pointers, the appropriate implementation is selected at runtime using runtime polymorphism.
Finally, the dynamically allocated objects are released using the delete operator. The virtual destructor ensures that the derived class destructors are executed correctly during object destruction.
Example 2: The RenderableShape Interface
This example demonstrates an interface that defines a common contract for graphical shapes. Every shape must be capable of calculating its area and drawing itself, while each shape provides its own implementation of these operations.
Program
Explanation
The RenderableShape class is an abstract class that acts as an interface. It declares two pure virtual functions: getArea() and draw(). Any class inheriting from this interface must provide implementations for both functions.
The Square class calculates its area using the square of its side length and displays a simple graphical representation of the shape. The Line class also implements both functions. Since a line has no two-dimensional area, its getArea() function returns zero, while the draw() function displays a horizontal line.
In the main() function, an array of interface pointers named canvas stores objects of different derived classes. Although the objects belong to different classes, they are managed uniformly through the RenderableShape interface.
A loop iterates through the array and calls the draw() function for each object. Due to runtime polymorphism, the appropriate version of draw() is executed for each shape. Finally, all dynamically allocated objects are deleted to release the allocated memory.
Conclusion
Interfaces in C++ are implemented using abstract classes that contain pure virtual functions. They define a common contract that derived classes must follow while allowing each class to provide its own implementation. This approach promotes abstraction, flexibility, code reusability, and runtime polymorphism. As demonstrated in the NotificationProvider and RenderableShape examples, interfaces make it possible to write generic, maintainable, and extensible programs by interacting with objects through a common interface rather than their specific implementations.