C ++相当于代数数据类型?

时间:2013-12-24 19:35:03

标签: c++ haskell algebraic-data-types

我们说我有这个Haskell代码:

data RigidBody = RigidBody Vector3 Vector3 Float Shape -- position, velocity, mass and shape
data Shape = Ball Float -- radius
           | ConvexPolygon [Triangle]

用C ++表达这个的最好方法是什么?

struct Rigid_body {
    glm::vec3 position;
    glm::vec3 velocity;
    float mass;
    *???* shape;
};

我问的问题是如何在结构中表示形状,它可以是两种类型中的一种。

4 个答案:

答案 0 :(得分:10)

可以使用不同的方法在C ++中解决该问题。

您将定义接口Shape的纯OO方法,并将两个不同的选项作为实现该接口的派生类型。然后,RigidBody将包含指向Shape的指针,该指针将设置为引用BallConvexPolygon。亲:人们喜欢OO(不确定这是专业人员:)),它很容易扩展(你可以在以后添加更多形状而不改变类型)。 Con:你应该为Shape定义一个合适的接口,它需要动态分配内存。

将OO放在一边,你可以使用boost::variant或类似的类型,它基本上是一个标记的联合,它将包含其中一种类型。 Pro:没有动态分配,形状是对象的本地。骗局:不是纯粹的OO(人们喜欢OO,你还记得吗?),不那么容易扩展,不能使用一般的形状

答案 1 :(得分:5)

为了在这里抛出另一种可能性,您还可以使用boost::variant作为std::variant添加到C ++ 17中的标准库中:

struct Ball { float radius; };
struct ConvexPolygon { Triangle t; }

using Shape = boost::variant<Ball, ConvexPolygon>;

这种方法的优点:

  • 类型安全,与标记的联盟不同
  • 与工会不同,可以容纳复杂的类型
  • 与OO
  • 不同,不需要跨所有“子”类型的统一界面

一些缺点:

  • 有时需要您在访问变量时进行类型检查,以确认它是您希望的类型,与OO不同
  • 要求您使用boost,或与C ++ 17兼容;对于一些编制者或一些OO和工会得到普遍支持的组织来说,这些可能很难。

答案 2 :(得分:2)

在C ++中执行此操作的规范方法是Justin Wood的答案中给出的基于继承的解决方案。通常,您为Shape赋予了每种Shape

的虚函数

但是,C ++也有union种类型。您可以改为使用“已标记的工会”:

struct Ball { /* ... */ };
struct Square { /* ... */ };
struct Shape {
  int tag;
  union {
    Ball b;
    Square s;
    /* ... */
  }
};

您使用tag成员说出ShapeBall还是Square还是其他任何内容。您可以switch成员tag以及

。{/ p>

这样做的缺点是,ShapeintBall以及其他人的Square大一{{}}}; OCaml中的对象,以及没有这个问题。

您使用哪种技术取决于您使用Shape的方式。

答案 3 :(得分:0)

您将要创建基类Shape。在这里,您可以创建实际的形状类BallConvexPolygon。您将要确保BallConvexPolygon是基类的子级。

class Shape {
    // Whatever commonalities you have between the two shapes, could be none.
};

class Ball: public Shape {
    // Whatever you need in your Ball class
};

class ConvexPolygon: public Shape {
    // Whatever you need in your ConvexPolygon class
};

现在,您可以制作像这样的通用对象

struct Rigid_body {
    glm::vec3 position;
    glm::vec3 velocity;
    float mass;
    Shape *shape;
};

当您实际初始化shape变量时,可以使用BallConvexPolygon类对其进行初始化。您可以继续制作任意数量的形状。