У меня есть ряд объектов формы, которые могут проверить, пересекаются ли они друг с другом (пересечение истинно, если какая-либо часть одного объекта перекрывает другую). Это прекрасно работает с двойной диспетчеризацией, потому что пересечение двух объектов может быть представлено относительно любого объекта и при этом быть действительным и истинным.
Недавно я добавил (читается как: «попытался добавить») метод Contains, который проверяет, полностью ли форма охватывает другую. Двойная отправка не удалась, потому что две формы разных размеров будут работать на Intersect, но не содержит: shape_one
большой круг, и shape_two
меньший круг, полностью окруженный shape_one
, Вызов shape_one.Contains(shape_two)
вернется правда, но shape_two.Contains(shape_one)
вернет ложь.
Есть ли способ реализовать двойную диспетчеризацию для этого типа сценария?
(Редактирование заголовков рекомендуется для лучшего понимания вопроса …)
Пример методов Intersects с двойной отправкой:
bool Rectangle::Intersects(const Shape& shape) const {
return shape.Intersects(*this);
}
bool Rectangle::Intersects(const Point& point) const {
return point.Intersects(*this);
}
bool Rectangle::Intersects(const Line& line) const {
return line.Intersects(*this);
}
bool Rectangle::Intersects(const Rectangle& rectangle) const {
double myTop = this->GetY();
double myLeft = this->GetX();
double myRight = myLeft + this->GetWidth();
double myBottom = myTop + this->GetHeight();
double rTop = rectangle.GetY();
double rLeft = rectangle.GetX();
double rRight = rLeft + rectangle.GetWidth();
double rBottom = rTop + rectangle.GetHeight();
if(myTop > rBottom) return false;
if(myBottom < rTop) return false;
if(myLeft > rRight) return false;
if(myRight < rLeft) return false;
return true;
}
Пример методов Contains с двойной отправкой:
//THIS RESULTS IN A STACK OVERFLOW! DUE TO INFINITE RECURSION!
bool Rectangle::Contains(const Shape& shape) const {
return this->Contains(shape);
}
//THIS IS NOT TRUE IN ALL CASES!
bool Rectangle::Contains(const Shape& shape) const {
return shape.Contains(*this);
}bool Rectangle::Contains(const Point& point) const {
return this->Intersects(point);
}
bool Rectangle::Contains(const Line& line) const {
return this->Intersects(line.GetPointOne()) && this->Intersects(line.GetPointTwo());
}
bool Rectangle::Contains(const Rectangle& rectangle) const {
return this->Intersects(rectangle.GetTopLeft()) && this->Intersects(rectangle.GetTopRight()) && this->Intersects(rectangle.GetBottomLeft()) && this->Intersects(rectangle.GetBottomRight());
}
Решается путем нажатия, содержит методы до базового класса и динамическое приведение к нужному типу с параметром типа в вызове от базы к базе Contains:
bool Shape::Contains(const Shape& shape) const {
std::string type = shape.GetShapeType();
if(type == "arc") {
return this->Contains(dynamic_cast<const Arc&>(shape));
} else if(type == "circle") {
return this->Contains(dynamic_cast<const Circle&>(shape));
} else if(type == "ellipse") {
return this->Contains(dynamic_cast<const Ellipse&>(shape));
} else if(type == "line") {
return this->Contains(dynamic_cast<const Line&>(shape));
} else if(type == "point") {
return this->Contains(dynamic_cast<const Point&>(shape));
} else if(type == "polygon") {
return this->Contains(dynamic_cast<const Polygon&>(shape));
} else if(type == "rectangle") {
return this->Contains(dynamic_cast<const Rectangle&>(shape));
} else if(type == "sector") {
return this->Contains(dynamic_cast<const Sector&>(shape));
} else if(type == "spline") {
return this->Contains(dynamic_cast<const Spline&>(shape));
} else if(type == "triangle") {
return this->Contains(dynamic_cast<const Triangle&>(shape));
} else {
return false;
}
}
bool Shape::Contains(const Point& point) const {
return this->Intersects(point);
}
bool Shape::Contains(const Line& line) const {
return this->Intersects(line.GetPointOne()) && this->Intersects(line.GetPointTwo());
}
bool Shape::Contains(const Rectangle& rectangle) const {
return this->Intersects(rectangle.GetTopLeft()) && this->Intersects(rectangle.GetTopRight()) && this->Intersects(rectangle.GetBottomLeft()) && this->Intersects(rectangle.GetBottomRight());
}
//...etc
Других решений пока нет …