C++等效于代数数据类型
C++ equivalent of algebraic datatype?
假设我有这个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;
};
我要问的是,当形状可以是两种类型之一时,如何表示结构内部的形状。
C++中可以使用不同的方法来解决该问题。
纯 OO 方法Shape
定义接口,并将两个不同的选项作为实现该接口的派生类型。然后,RigidBody
将包含一个指向Shape
的指针,该指针将设置为引用Ball
或ConvexPolygon
。优点:人们喜欢OO(不确定这是否真的:)),它很容易扩展(您可以稍后添加更多形状而无需更改类型)。缺点:你应该为Shape
定义一个合适的接口,它需要动态分配内存。
撇开OO不谈,您可以使用boost::variant
或类似的类型,这基本上是一个标记的联合,将保存其中一种类型。优点:没有动态分配,形状是对象的局部。缺点:不是纯OO(人们喜欢OO,你还记得吧?),不太容易扩展,不能一般使用形状
要在这里抛出另一种可能性,您还可以使用 C++17 中添加到标准库中的boost::variant
作为std::variant
struct Ball { float radius; };
struct ConvexPolygon { Triangle t; }
using Shape = boost::variant<Ball, ConvexPolygon>;
这种方法的优点:
- 类型安全,与标记联合不同
- 可以容纳复杂类型,与联合不同
- 不需要跨所有"子"类型的统一接口,与 OO 不同
一些缺点:
- 有时要求您在访问变量时进行类型检查,以确认它是您想要的类型,这与 OO 不同
- 要求您使用 boost 或与 C++17 兼容;对于某些编译器或某些普遍支持 OO 和联合的组织来说,这些可能很困难
在C++中做到这一点的规范方法是贾斯汀伍德的答案中给出的基于继承的解决方案。 通常,您赋予Shape
每种Shape
的虚拟函数
但是,C++也有union
类型。 您可以改为执行"标记联合":
struct Ball { /* ... */ };
struct Square { /* ... */ };
struct Shape {
int tag;
union {
Ball b;
Square s;
/* ... */
}
};
您可以使用tag
成员来说明Shape
是Ball
还是Square
或其他任何东西。 您可以switch
tag
成员之类的。
这样做的缺点是,Shape
比Ball
和Square
中最大的int
大;OCaml中的对象等等都没有这个问题。
您使用哪种技术将取决于您如何使用Shape
。
您将要创建一个基类Shape
。从这里,您可以创建实际的形状类、Ball
和ConvexPolygon
。您需要确保Ball
和ConvexPolygon
是基类的子类。
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
变量时,您可以使用 Ball
或 ConvexPolygon
类对其进行初始化。您可以继续制作任意数量的形状。
- 防止主数据类型C++的隐式转换
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在C++中打印指向不同基元数据类型的指针的内存地址
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 如何计算数据类型的范围,例如int
- C++中数据类型修饰符的顺序
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- 特定数据类型的模板类
- 具有多个模板的模板函数,用于特定数据类型(如字符串)?
- 有没有办法提示用户使用哪种数据类型作为模板 c++
- int数据类型的指针指向的是什么,如果是一个类的私有数据成员,我们创建了该类的两个对象?
- 时间复杂度 当具有复合数据类型(如元组或对)时?
- 如何获取C++字符数据类型的地址
- 将复杂的非基元C++数据类型转换为 Erlang/Elixir 格式,以使用 NIF 导出方法
- 构造智能点数据类型以及普通数据类型的通用方法
- 如何使映射键具有两种不同的数据类型?
- 数据类型"struct seq<0, 1, 2>{}"含义是什么?
- 如何在不破坏现有应用程序的情况下更改 API 中 stl 容器的数据类型?
- C++等效于代数数据类型
- 什么是代数数据类型的惯用现代C++