我意识到这是一个非常具体的问题,所以如果人们给出的答案包括如何执行此操作的明确代码将会有所帮助。感谢。
我有一个抽象基类Shape:
class Shape
{
.....
virtual bool GetIntersection(Shape* _shape) = 0;
}
class Circle : public Shape {...}
class Triangle : public Shape {...}
这些派生类都会覆盖GetIntersection;
我有:
//main.cpp
....
Shape* shape;
Shape* circle = new Circle;
if(input == 0) shape = new Circle;
else shape = new Triangle;
circle->GetIntersection(shape);
会出错。
我阅读了一些关于访问者模式的内容,并认为这可能是解决我的问题的方法,因为我基本上需要确定GetIntersection的参数使用哪个派生类。有人可以解释我如何为这种情况实现访问者模式吗?或者如果有另一个更简单的解决方案来解决这个问题。
任何帮助都将不胜感激。
答案 0 :(得分:2)
这个问题似乎与这个问题重叠: Design pattern for checking collision between shapes
其中使用了访问者模式,并且看起来非常清楚。诀窍是让每个形状(圆形,方形,无论什么)成为彼此形状的访客。
答案 1 :(得分:1)
你的解决方案是对的。
您最初可以获得一个边界框并检查边界框之间的碰撞。请记住,在任何情况下,您都无法将苹果与橙子进行比较。所以开始比较两个边界框。
然后,如果发生碰撞,您可能想要查找单个点。每个形状都可以返回其轮廓的点或矢量,您可以轻松找出是否存在碰撞。可能有一些方法可以加快速度,比如知道一个点是否在一个正方形内是容易的,或者知道一个点是否在一个圆内只是检查从一个点到另一个中心的长度是否大于半径。
然后你可以做类似的事情 形状{ bool isPointInside(Point p)= 0; }
这比检查每个点要快得多。
您还可以覆盖圆的getIntersection以对方块等进行不同的检查。而不仅仅是Shape。
答案 2 :(得分:0)
您可以使用f.x. dynamic_cast<Circle *>(shape)
查看形状是否为圆形。如果shape不是Circle,则返回null,否则返回Circle实例的有效指针。
如果你的一个GetInserection方法知道如何与特定的其他Shape子类型相交,请使用此方法。
除此之外,请遵循Loïc Faure-Lacroix's answer的指南。
答案 3 :(得分:0)
我现在正面临着不同形状之间碰撞的相同问题。
我认为我们不能“按原样”使用访问者模式,因为它要求层次结构A(访问者)的类访问另一个层次结构B(访问过的元素)的类,其中B的类只知道A的抽象(例如, IVisitor ),而B的类知道A的子类( VisitedElement1 , VisitedElement2 ... ...的子类VisitedElement)。
在我们的例子中,我们尝试使用Shapes访问Shapes,同时保持Shape类与子类分离,因此Visitor模式不适用。
我能想到的最好的解决方案是,Shape类直接或通过另一个接口为所有子类型声明“GetSpecificIntersection”方法:
class Shape
{
.....
public:
virtual bool GetIntersection(Shape* _shape) = 0;
protected:
virtual bool GetSpecificIntersection(Circle* _circle) = 0;
virtual bool GetSpecificIntersection(Triangle* _triangle) = 0;
}
class Circle
{
.....
public:
virtual bool GetIntersection(Shape* _shape);
{
return _shape->GetSpecificIntersection(this);
}
protected:
virtual bool GetSpecificIntersection(Circle* _circle) { ... }
virtual bool GetSpecificIntersection(Triangle* _triangle) { ... }
}
class Triangle { /* analog to Circle */ }
因此,您必须将每种形状的特定交叉方法实现为任何其他类型的形状,并且Shape类与所有可能的形状耦合。如果我没错,则会违反OCP,但会保留LSP。
我刚刚提出的另一个选择是“赞成合成而不是继承”,并做出类似这样的事情:
class Shape
{
.....
public:
virtual bool GetIntersection(Shape* _shape)
{
return _shape->figure->GetIntersection(this->figure);
}
private:
Figure* figure;
}
class Figure
{
.....
public:
virtual bool GetIntersection(Figure* _figure) = 0;
protected:
virtual bool GetSpecificIntersection(Circle* _circle) = 0;
virtual bool GetSpecificIntersection(Triangle* _triangle) = 0;
}
class Circle
{
.....
public:
virtual bool GetIntersection(Figure* _figure)
{
return _figure->GetSpecificIntersection(this);
}
protected:
virtual bool GetSpecificIntersection(Circle* _circle) { ... }
virtual bool GetSpecificIntersection(Triangle* _triangle) { ... }
}
class Triangle { /* analog to Circle */ }
它和以前一样,但通过这样做,你可以将你的Shape类(你的游戏类所使用的界面)与不同的“数字”分开(我没有提出更好的名字),所以添加新数据甚至不应该导致重新编译您的客户端类。这仅在“数字”层次结构中违反OCP,并为“形状”和“图”保留LSP。
如果有人可以提出更好的方法来做到这一点,同时避免向下转换,我会非常感激:D