#include <iostream>
#include <cmath>
#include <memory>
#include <vector>

// Forward declaration of visitor base class
class ShapeVisitor;

// Abstract element class: shape
class Shape {
public:
    virtual ~Shape() = default;
    // Accept visitor, implemented by subclasses to call visitor.visit(*this)
    virtual void accept(ShapeVisitor& visitor) = 0;
};

// Concrete element: circle
class Circle : public Shape {
public:
    explicit Circle(double r) : radius(r) {}
    double getRadius() const { return radius; }
    void accept(ShapeVisitor& visitor) override;

private:
    double radius;
};

// Concrete element: rectangle
class Rectangle : public Shape {
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double getWidth() const { return width; }
    double getHeight() const { return height; }
    void accept(ShapeVisitor& visitor) override;

private:
    double width, height;
};

// Abstract visitor: declare visit methods for each concrete element
class ShapeVisitor {
public:
    virtual ~ShapeVisitor() = default;
    virtual void visit(Circle& circle) = 0;
    virtual void visit(Rectangle& rectangle) = 0;
};

// Concrete visitor: calculate area
class AreaCalculator : public ShapeVisitor {
public:
    void visit(Circle& circle) override {
        double area = M_PI * circle.getRadius() * circle.getRadius();
        std::cout << "Circle area: " << area << std::endl;
    }

    void visit(Rectangle& rectangle) override {
        double area = rectangle.getWidth() * rectangle.getHeight();
        std::cout << "Rectangle area: " << area << std::endl;
    }
};

// Concrete visitor: print description
class DescriptionPrinter : public ShapeVisitor {
public:
    void visit(Circle& circle) override {
        std::cout << "This is a circle with radius " 
                  << circle.getRadius() << std::endl;
    }

    void visit(Rectangle& rectangle) override {
        std::cout << "This is a rectangle with width " 
                  << rectangle.getWidth() << " and height " 
                  << rectangle.getHeight() << std::endl;
    }
};

// Implement accept methods (must appear after visitor class definition)
void Circle::accept(ShapeVisitor& visitor) {
    visitor.visit(*this);
}

void Rectangle::accept(ShapeVisitor& visitor) {
    visitor.visit(*this);
}

int main() {
    // Create a set of shapes
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.push_back(std::make_unique<Circle>(5.0));
    shapes.push_back(std::make_unique<Rectangle>(3.0, 4.0));
    shapes.push_back(std::make_unique<Circle>(2.5));

    // Create visitors
    AreaCalculator areaCalc;
    DescriptionPrinter descPrinter;

    std::cout << "=== Calculating areas ===" << std::endl;
    for (auto& shape : shapes) {
        shape->accept(areaCalc);
    }

    std::cout << "\n=== Printing descriptions ===" << std::endl;
    for (auto& shape : shapes) {
        shape->accept(descPrinter);
    }

    return 0;
}

results matching ""

    No results matching ""