2
votes

I have three shape classes Circle, Square, ConvexPolygon, and I have the functions

bool ShapesIntersect(const Circle& s1, const Circle& s2);
bool ShapesIntersect(const Circle& s1, const Square& s2);
// ... and the other 7 combinations

I would like a polymorphic function sort of like

Matrix<bool> ComputeShapeIntersectionMatrix(
    const vector<Shape>& shapes1,
    const vector<Shape>& shapes2);

that calls the shape-specific methods above to fill the matrix of intersections.

I think it is impossible to do exactly this in c++, but I'm ok with any other solution, as long as I can add a new shape type without changing the code that computes the intersection matrix.

2
I mean impossible without manually switching on the type and casting.Andrea Allais
Why don't you make a virtual Intersect function in the base Shape class that is overridden in the child classes?Some programmer dude

2 Answers

2
votes

I have done a multi-dispatcher.

If you use std::variant, it becomes simpler:

using Shape = std::variant<Circle, Square, ConvexPolygon>;

struct intersect
{
    template <typename Shape1, typename Shape2>
    bool operator()(const Shape1& lhs, const Shape2& rhs) const {
        return ShapesIntersect(lhs, rhs);
    }
};



Matrix<bool> ComputeShapeIntersectionMatrix(
    const vector<Shape>& shapes1,
    const vector<Shape>& shapes2)
{
    Matrix<bool> res(shapes1.size(), shapes2.size());

    for (std::size_t i = 0; i != shapes1.size(); ++i) {
        for (std::size_t j = 0; j != shapes2.size(); ++j) {
            res[i][j] = std::visit(intersect{}, shapes1[i], shapes2[j]);
        }
    }
    return res;
}
0
votes

I would solve it like that:

struct Circle;
struct Polygon;
struct Square;

struct Intersector {
    virtual bool intersects(const Circle& ) const = 0;
    virtual bool intersects(const Polygon& ) const = 0;
    virtual bool intersects(const Square& ) const = 0;
};

template<class SHAPE>
struct ShapeIntersetor;

template<>
struct ShapeIntersetor<Square> : Intersector {
    const Square& square;
    ShapeIntersetor(const Square& square) : square(square) { }
    bool intersects(const Circle& ) const override { /* Intersection code */ }
    bool intersects(const Polygon& ) const override { /* Intersection code */ }
    bool intersects(const Square& ) const override { /* Intersection code */ }
};

// Repeat above for each shape type

struct Shape {
    virtual ~Shape() = default;
    virtual std::unique_ptr<Intersector> get_intersector() const = 0;
    virtual bool intersects(const Intersector& isector) const = 0;
};

struct Polygon : Shape {
    std::unique_ptr<Intersector> get_intersector() const override {
        return make_unique<ShapeIntersector<Polygon>>(*this);
    }
    bool intersects(const Intersector& isector) const override {
        return isector.intersects(*this);
    }
}; 

// Repeat above for each shape type