1

我意识到这是一个非常具体的问题,因此如果人们给出的答案包括有关如何执行此操作的明确代码,那将会很有帮助。谢谢。

我有一个抽象基类 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 的参数正在使用哪个派生类。有人可以解释我将如何为这种情况实施访问者模式吗?或者如果这个问题有另一个更简单的解决方案。

任何帮助,将不胜感激。

4

4 回答 4

2

我现在面临着不同形状之间碰撞的同样问题。

我认为我们不能“按原样”使用访问者模式,因为它要求层次 A(访问者)的类访问另一个层次 B(访问的元素)的类,其中 B 的类只知道 A 的抽象(例如IVisitor)而 B 的类知道 A 的子类(VisitedElement1VisitedElement2 ... VisitedElement 的子类)。

在我们的例子中,我们尝试使用 Shapes 访问 Shapes,同时保持 Shape 类与子类分离,因此访问者模式不适用。

我能想到的最佳解决方案是 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 类(这是你的游戏类使用的接口)与不同的“Figures”(我没有想出更好的名字)解耦,所以添加新的图形甚至不应该导致重新编译您的客户端类。这仅在“图形”层次结构中违反OCP ,并为“形状”和“图形”保留LSP 。

如果有人可以提出更好的方法来避免沮丧,我将非常感激:D

于 2012-09-18T20:29:30.710 回答
2

这个问题似乎与这个问题重叠: 用于检查形状之间碰撞的设计模式

其中使用了访问者模式,看起来很清晰。诀窍是让每个形状(圆形、方形等)成为其他形状的访问者。

于 2013-07-09T20:25:38.173 回答
1

你的解决方案是正确的。

您首先可以获得一个边界框并检查边界框之间的碰撞。请记住,在任何情况下,您都无法将苹果与橙子进行比较。所以开始比较两个边界框。

然后,如果发生碰撞,您可能需要查找各个点。每个形状都可以返回其轮廓的点或向量,您可以轻松找出是否存在碰撞。可能有一些方法可以加快速度,比如知道一个点是否在正方形内很容易,或者知道一个点是否在一个圆内只是检查从一个点到中心的长度是否大于半径。

然后你可以做类似 Shape { bool isPointInside(Point p) = 0; }

这比检查每个单独的点要快得多。

您还可以覆盖 getIntersection for circle 以不同方式检查正方形等。而不仅仅是 Shape。

于 2012-07-08T08:45:35.030 回答
0

您可以使用 fxdynamic_cast<Circle *>(shape)查看形状是否为圆形。如果 shape 不是 Circle,则返回 null,否则返回指向 Circle 实例的有效指针。

如果您的 GetInserection 方法之一知道如何与特定的其他 Shape 子类型相交,请使用此方法。

除此之外,请遵循Loïc Faure-Lacroix 的回答指南。

于 2012-07-09T11:18:11.093 回答