gpt4 book ai didi

c++ - 为不同的形状实现抽象的 'overlaps' 方法?

转载 作者:太空狗 更新时间:2023-10-29 23:52:03 24 4
gpt4 key购买 nike

我有一个名为 Shape 的抽象基类,看起来像这样:

class Shape {
public:
Shape(Point center);
virtual bool overlaps(Shape *other) = 0;

private:
Point m_center; // has getter&setter
};

我在使用 overlaps(Shape *other); 时遇到问题方法;我不知道如何在子类中实现它。

让我们举两个例子,(我可能不会超过两个或三个形状)CircleRect .基本上我尝试的是在使用前向声明允许 Circle 之后在两个类中创建两个重载和 Rect相互“了解”:

virtual bool Rect::overlaps(Circle *other);
virtual bool Rect::overlaps(Rect *other);
virtual bool Circle::overlaps(Circle *other);
virtual bool Circle::overlaps(Rect *other) { return other->overlaps(this); }

现在很容易在所有重载中实现数学;但是,我会得到一个错误 cannot allocate an object of abstract type 'Circle'note: virtual bool Unit::overlaps(Unit *) .这是因为我的 CircleRect类只有 Circle * 的方法和 Rect *作为他们的参数,但没有Unit * .

我也尝试向前声明 CircleRect在我的 shape.h 中,但由于前向声明与我实际的 Circle 不同和 Rect ,我只会得到同样的错误。

在不删除公共(public)基类的情况下,有没有办法实现这种行为?或者是否有解决方法使其工作?

附加信息

我有一个 2D World包含 vector<Shape *> m_shapes; 的类我需要查看两个形状是否相互重叠;

for (unsigned int i = 0; i < m_shapes.size(); i++) {
if (certainShape->overlaps(m_shapes[i])) {
collapse();
}
}

最佳答案

欢迎多 dispatch !本质上,您要求的方法对于多个对象的运行时类型而言是虚拟的 - 在您的情况下,正在测试重叠的两个形状的类型。

在 C++ 中有几种常见的实现双重分派(dispatch)的方法:例如,您可以使用 visitor pattern , 或者根据 RTTI 制作 map .选择其中之一取决于您。

如果您决定采用访问者模式,您可以制作 Shape通过添加访问方法“可访问”。

这是基于访问者的方法的示例。诚然,它相当冗长,但它也解决了一项复杂的任务,因此它需要大量代码是公平的。我将下面的示例剥离到最低限度——只有两个没有数据成员的形状,以及除了打印之外什么都不做的方法。不过,这应该足以让您入门:

#include <iostream>
using namespace std;

class ShapeVisitor;

struct Shape {
virtual void accept(ShapeVisitor& v) = 0;
virtual bool overlaps(Shape& other) = 0;
};

class Circle;
class Square;

struct ShapeVisitor {
virtual void visitCircle(Circle& c) = 0;
virtual void visitSquare(Square& s) = 0;
};

// These three methods do the actual work
bool checkOverlap(Square& s, Circle& c) {
cout << "Checking if square overlaps circle" << endl;
return false;
}
bool checkOverlap(Square& a, Square& b) {
cout << "Checking if square overlaps square" << endl;
return false;
}
bool checkOverlap(Circle& a, Circle& b) {
cout << "Checking if circle overlaps circle" << endl;
return false;
}

class Square : public Shape {
struct OverlapVisitor : public ShapeVisitor {
OverlapVisitor(Square& _my) : result(false), my(_my) {}
virtual void visitCircle(Circle& c) {
result = checkOverlap(my, c);
}
virtual void visitSquare(Square& s) {
result = checkOverlap(my, s);
}
bool result;
Square& my;
};
public:
virtual void accept(ShapeVisitor& v) {
v.visitSquare(*this);
}
virtual bool overlaps(Shape& other) {
OverlapVisitor v(*this);
other.accept(v);
return v.result;
}
};

class Circle : public Shape {
struct OverlapVisitor : public ShapeVisitor {
OverlapVisitor(Circle& _my) : result(false), my(_my) {}
virtual void visitCircle(Circle& c) {
result = checkOverlap(my, c);
}
virtual void visitSquare(Square& s) {
// Important: note how I switched the order of arguments
// compared to Square::OverlapVisitor! There is only one
// square/circle overlap function checker, and it expects
// the square to be the first argument.
result = checkOverlap(s, my);
}
bool result;
Circle& my;
};
public:
virtual void accept(ShapeVisitor& v) {
v.visitCircle(*this);
}
virtual bool overlaps(Shape& other) {
OverlapVisitor v(*this);
other.accept(v);
return v.result;
}
};

这是正在运行的 demo on ideone .

使用 RTTI 方法,您将制作一个 map<pair<type_info,type_info>,checker>其中 checker 是一种函数,它接受两个指向 Shape 的指针。 ,并返回 truefalse取决于形状是否重叠。您为每对对象类型创建一个这样的函数,根据 type_info 使用指向这些函数的指针填充映射。他们预期的参数类型,并在运行时使用此映射来调用所需的函数。

More Effective C++ 的第 31 项这本书通过一些很好的例子深入解释了这两种方法。事实上,书中讨论的用例(检测一对游戏对象之间的碰撞)与您正在实现的用例类似。

关于c++ - 为不同的形状实现抽象的 'overlaps' 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17674819/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com