#include <iostream>
#include <memory>
#include <vector>
/** Abstract interface class.
*
* This class defines the interface that must be implemented by concrete classes.
* It contains pure virtual functions that provide the contract for derived classes.
* The interface is designed to be used polymorphically through pointers or references.
*/
class IShape {
public:
/** Virtual destructor.
*
* Ensures proper cleanup when deleting through base class pointer.
*/
virtual ~IShape() = default;
/** Calculate area of the shape.
*
* Pure virtual function that must be implemented by derived classes.
* @return The area of the shape as a double.
*/
virtual double area() const = 0;
/** Calculate perimeter of the shape.
*
* Pure virtual function that must be implemented by derived classes.
* @return The perimeter of the shape as a double.
*/
virtual double perimeter() const = 0;
/** Get shape name.
*
* Pure virtual function for getting the name of the shape.
* @return The name of the shape as a C-style string.
*/
virtual const char * name() const = 0;
/** Draw the shape.
*
* Virtual function with default implementation that can be overridden.
* Provides a basic drawing mechanism that derived classes can customize.
*/
virtual void draw() const {
std::cout << "Drawing a " << name() << std::endl;
}
};
/** Concrete implementation of circle shape.
*
* This class implements the IShape interface and provides specific
* implementations for circle geometry calculations.
*/
class Circle : public IShape {
private:
double radius; /*!< Radius of the circle */
public:
/** Circle constructor.
*
* @param r The radius of the circle.
*/
explicit Circle(double r) : radius(r) {}
/** Calculate circle area.
*
* @return The area of the circle (πr²).
*/
double area() const override {
return 3.14159 * radius * radius;
}
/** Calculate circle perimeter.
*
* @return The perimeter of the circle (2πr).
*/
double perimeter() const override {
return 2 * 3.14159 * radius;
}
/** Get shape name.
*
* @return "Circle" as the shape name.
*/
const char * name() const override {
return "Circle";
}
/** Draw the circle.
*
* Custom implementation of draw for circles.
*/
void draw() const override {
std::cout << "Drawing a circle with radius " << radius << std::endl;
}
};
/** Concrete implementation of rectangle shape.
*
* This class implements the IShape interface and provides specific
* implementations for rectangle geometry calculations.
*/
class Rectangle : public IShape {
private:
double width; /*!< Width of the rectangle */
double height; /*!< Height of the rectangle */
public:
/** Rectangle constructor.
*
* @param w The width of the rectangle.
* @param h The height of the rectangle.
*/
Rectangle(double w, double h) : width(w), height(h) {}
/** Calculate rectangle area.
*
* @return The area of the rectangle (width × height).
*/
double area() const override {
return width * height;
}
/** Calculate rectangle perimeter.
*
* @return The perimeter of the rectangle (2 × (width + height)).
*/
double perimeter() const override {
return 2 * (width + height);
}
/** Get shape name.
*
* @return "Rectangle" as the shape name.
*/
const char * name() const override {
return "Rectangle";
}
/** Draw the rectangle.
*
* Custom implementation of draw for rectangles.
*/
void draw() const override {
std::cout << "Drawing a rectangle " << width << "x" << height << std::endl;
}
};
/** Shape processor class.
*
* This class demonstrates using the interface polymorphically.
* It can work with any shape that implements the IShape interface.
*/
class ShapeProcessor {
public:
/** Process a shape.
*
* This function takes a shape through the interface and performs
* operations on it polymorphically.
*
* @param shape Pointer to the shape to process.
*/
void processShape(const IShape * shape) {
if (shape) {
std::cout << "Processing " << shape->name() << ":" << std::endl;
std::cout << " Area: " << shape->area() << std::endl;
std::cout << " Perimeter: " << shape->perimeter() << std::endl;
shape->draw();
std::cout << std::endl;
}
}
/** Calculate total area of multiple shapes.
*
* Demonstrates using the interface with a collection of shapes.
*
* @param shapes Vector of shape pointers.
* @return Total area of all shapes.
*/
double totalArea(const std::vector<const IShape *> & shapes) const {
double total = 0.0;
for (const auto * shape : shapes) {
if (shape) {
total += shape->area();
}
}
return total;
}
};
/** Demonstrates shared virtual functions between interface and objects.
*
* This function shows how the IShape interface defines virtual functions
* that are shared (implemented) by concrete classes like Circle and Rectangle.
* The interface provides the contract, while implementations provide the behavior.
*/
void demonstrateSharedVirtualFunctions() {
std::cout << "=== Shared Virtual Functions Demonstration ===" << std::endl;
// Create concrete objects
Circle circle(5.0);
Rectangle rectangle(4.0, 6.0);
// Create processor
ShapeProcessor processor;
// Process shapes polymorphically through interface
std::cout << "Processing individual shapes:" << std::endl;
processor.processShape(&circle);
processor.processShape(&rectangle);
// Demonstrate collection processing
std::vector<const IShape *> shapes = {&circle, &rectangle};
double totalArea = processor.totalArea(shapes);
std::cout << "Total area of all shapes: " << totalArea << std::endl;
std::cout << "\n=== Key Points ===" << std::endl;
std::cout << "- IShape interface defines pure virtual functions (contract)" << std::endl;
std::cout << "- Circle and Rectangle implement the interface (shared behavior)" << std::endl;
std::cout << "- ShapeProcessor works with any IShape polymorphically" << std::endl;
std::cout << "- Virtual functions enable runtime polymorphism" << std::endl;
std::cout << "- Interface provides abstraction, implementations provide details" << std::endl;
}
int main() {
demonstrateSharedVirtualFunctions();
return 0;
}