#include <iostream>
#include <memory>

struct Visitor;

struct Shape {
    virtual void accept(Visitor const &v) = 0;
};

struct Circle : Shape { void accept(Visitor const &v) override; };
struct Triangle : Shape { void accept(Visitor const &v) override; };
struct Square : Shape { void accept(Visitor const &v) override; };

struct Point {
    Point(float x, float y) {}   
};

struct Visitor {
    virtual void visit(Circle   &c) const = 0;
    virtual void visit(Triangle &t) const = 0;
    virtual void visit(Square   &s) const = 0;
};


void Circle::accept(Visitor const &v) {
        v.visit(*this);
}
void Triangle::accept(Visitor const &v) {
        v.visit(*this);
}
void Square::accept(Visitor const &v) {
        v.visit(*this);
}


struct SnapToPoint : Visitor {
    SnapToPoint(float x, float y) : _point(x, y) {}

    void visit(Circle   &c) const override { std::cout << "Snapped a Circle\n"; }
    void visit(Triangle &t) const override { std::cout << "Snapped a Triangle\n"; }
    void visit(Square   &s) const override { std::cout << "Snapped a Square\n"; }

private:
    Point _point;
};

struct ShapeOperationFactory {
    virtual std::unique_ptr<Visitor> snapToPoint(float x, float y) const = 0;
};

struct MyShapeOpFactory : ShapeOperationFactory {
    std::unique_ptr<Visitor> snapToPoint(float x, float y) const override {
        return std::unique_ptr<Visitor>(new SnapToPoint(x, y));
    }
};

int main() {
   
   Shape *pShape = new Circle;
   ShapeOperationFactory *pFactory = new MyShapeOpFactory;
   
   pShape->accept(*pFactory->snapToPoint(4.0f, 7.0f));
   
   delete pFactory;
   delete pShape;
   return 0;
}