C++ - это первый язык, который я использовал во всем экстенсивно, который использует объектную ориентацию, поэтому я все еще немного новичок в этой идее. Я пытаюсь портировать библиотеку игр, с которой я работал, от Go (который использует интерфейсы вместо истинной системы OOP) до C++.
У меня есть система столкновений, которая использует четыре типа: точку, ограничительную, линию и многоугольник. То, что я хотел бы сделать, состоит в том, чтобы все они были абстрактно-способными в класс "Коллайдер" и имели функцию, которая способна принимать два объекта коллайдера и проверять наличие столкновения. Это будет выглядеть примерно так:
bool Collides(Collider obj1, Collider obj2);
Первоначально я думал, что у меня могут быть методы для каждого типа столкновения, которые будут проверять наличие столкновения с другим типом (то есть методы OnPoint, OnBounding, OnLine и OnPolygon), а затем иметь "Коллайдер" как виртуальный класс, который требует всех этих методов, но то я понял, что это невозможно в C++, потому что он будет заставлять классы зависеть друг от друга для компиляции (правильно?).
Я немного растерялся о том, что еще я могу сделать. Является ли моя идея дизайна мечтой?
То, что вы хотите, - это функция, которая отправляет не только по первому аргументу, но и по второму, т.е. двойную отправку. Это не поддерживается в C++, но может быть эмулировано.
class Collider {
public:
virtual bool Collides(Collider const& x) const = 0;
private:
virtual bool Collides(Point const& p) const = 0;
virtual bool Collides(Line const& l) const = 0;
};
class Point: public Collider {
public:
virtual bool Collides(Collider const& x) const {
// here, the type of this is now Point
// now, find out what x is and call the overload on this type
x.Collides(*this);
}
private:
virtual bool Collides(Point const& p) const {
// we now know that we are a point and checking vs. another point
}
virtual bool Collides(Line const& l) const {
// we now know that we are a point and checking vs. a line
}
};
class Line: public Collider {
public:
virtual bool Collides(Collider const& x) const {
// here, the type of this is now Line
x.Collides(*this);
}
private:
virtual bool Collides(Point const& p) const {
// we now know that we are a line and checking vs. a point
}
virtual bool Collides(Line const& l) const {
// we now know that we are a line and checking vs. another line
}
};
Теперь, проверка двух объектов будет выполнять две рассылки:
Collider* p = new Point();
Collider* l = new Line();
p.Collides(l)
// first dynamically dispatches on p to call Point::Collides
// in Collides, this (which is p) now has the static Point.
// now do the second dispatch on l and use *this as the parametet
// to find the overload.
Это, например, используется в шаблоне проектирования Visitor. Если ваш набор объектов исправлен, но вы ожидаете, что сделанные на них операции будут изменены или расширены, Visitor - хороший выбор.
bool collision(const Circle&, const% Rectangle&)