I have circles, boxes and lines. And now I want to implement collision detection between them. This means that I have to have a function for each combination of two kinds of shapes. Of course I can use the same for line vs circle and circle vs line, but I think my point still stands. What's the most elegant way to implement this in C++?
-
double dispatch is done with the visitor pattern as shown in this (java) example: http://en.wikipedia.org/wiki/Visitor_pattern#Java_example – stefaanv Jan 08 '14 at 16:23
-
1I woul make an oveloaded function like `bool isCOlliding(Circle object1, Line object2);` then `bool isCOlliding(Box object1, Circle object2);` etc, that way you can call the same function name on every combination – GMasucci Jan 08 '14 at 16:23
-
http://ideone.com/lTsc7M may help (require C++11) – Jarod42 Feb 04 '14 at 16:13
3 Answers
In the Modern C++ Design book, Multimethods chapter explains how to implement them and documents how to use [implementation provided by Loki library][2]. There is also Boost.Multimethod proposal, but it's not there yet. The book demonstrates the power of multimethods exactly on the topic of object collision.

- 737
- 1
- 11
- 23
Polymorphism
first you have Shape
and all the other sub classes:
class Shape;
class Circle : Shape;
class Square : Shape;
...etc
and you want them all to implement intersect with each other, so have one general function:
class Shape{
bool isIntersect(const Shape&)
{
return isIntersecting(this, shape);
}
};
Now overload isIntersecting with all the pair options, since each case is unique you don't have much of a choice here but to implement each case:
bool isIntersecting(Circle, Square);
bool isIntersecting(Circle, Line);
...
You can also try visitor pattern, but I think it's useless here.

- 4,322
- 3
- 37
- 69
-
1I agree with the comment about visitor pattern, but the important difference between function overloading and multiple dispatch is that function overloading works only if types are known at compile-time. That's something to consider, e.g. in case when objects are kept within container of top-most type (`Shape` in this case). – LavaScornedOven Jan 08 '14 at 16:41
You may do collision detection in a scene and not handle each incident of two shapes. Also, you will face some problems. Among them is type elision and registering geometric shapes:
#include <iostream>
#include <map>
class Shape
{
public:
struct Type {
public:
typedef unsigned Identifier;
const char* name;
Identifier id;
Type(const char* name)
: name(name), id(register_name(name))
{}
private:
static Identifier register_name(const char*);
};
virtual const Type& get_type() const = 0;
virtual ~Shape() {}
};
Shape::Type::Identifier Shape::Type::register_name(const char* name) {
typedef std::map<const char*, Identifier> Types;
static std::map<const char*, Identifier> types;
auto& id = types[name];
if( ! id) id = types.size();
return id;
}
class Scene
{
public:
typedef bool (*CollisionDetector)(const Shape&, const Shape&);
void register_collision_detector(CollisionDetector, const Shape::Type&, const Shape::Type&);
bool collision(const Shape& a, const Shape&, bool strict = false) const;
private:
typedef std::pair<Shape::Type::Identifier, Shape::Type::Identifier> Identifier;
typedef std::map<Identifier, CollisionDetector> CollisionDetectors;
CollisionDetectors m_detectors;
};
void Scene::register_collision_detector(
CollisionDetector detector,
const Shape::Type& t0,
const Shape::Type& t1)
{
m_detectors[Identifier(t0.id, t1.id)] = detector;
}
bool Scene::collision(const Shape& s0, const Shape& s1, bool strict) const {
const Shape::Type::Identifier i0 = s0.get_type().id;
const Shape::Type::Identifier i1 = s1.get_type().id;
auto pos = m_detectors.find(Identifier(i0, i1));
if(pos == m_detectors.end() && ! strict && i0 != i1)
pos = m_detectors.find(Identifier(i1, i0));
if(pos != m_detectors.end())
return pos->second(s0, s1);
else return false;
}
class Circle : public Shape
{
public:
static const Type type;
virtual const Type& get_type() const { return type; }
};
const Shape::Type Circle::type("Circle");
class Rectangle : public Shape
{
public:
static const Type type;
virtual const Type& get_type() const { return type; }
};
const Shape::Type Rectangle::type("Rectangle");
bool circle_rectangle_collision(const Shape& circle, const Shape& rectangle) {
std::cout << "circle_rectangle_collision" << std::endl;
return false;
}
int main()
{
Scene scene;
scene.register_collision_detector(circle_rectangle_collision, Circle::type, Rectangle::type);
Circle circle;
Rectangle rectangle;
scene.collision(circle, rectangle);
scene.collision(rectangle, circle);
}