C++中基于枚举值的Shape类构造函数特化方案问询
问题描述
需要创建一个描述多种数学形状的Shape类,包含Sphere、Cylinder、AABB、OBB四种形状,并用ShapeType枚举标识。当前构造函数要求传入所有参数(即使部分参数对目标形状无用,如Sphere无需halfLength),希望无需使用继承,实现基于枚举值的构造函数特化,让不同形状仅需传入对应所需参数,伪代码示例如下:
// Shapes.h enum ShapeType { Sphere, Cylinder, AABB, OBB, Count}; class Shape { public: Shape(ShapeType type = Sphere, const float r); Shape(ShapeType type = Cylinder, const float r, const float hl); Shape(ShapeType type = AABB, const Vector3& minExtend, const Vector3& maxExtend); Shape(ShapeType type = OBB, const Vector3& minExtend, const Vector3& maxExtend); // ... 其余成员同上 }
实现方案
C++无法直接根据枚举值实现构造函数特化,但可以通过标签分发重载或静态工厂方法实现需求,以下是两种实用方案:
方案一:标签分发+重载构造函数
定义空结构体作为形状标签,配合重载构造函数,让不同形状对应专属参数列表,内部存储枚举类型和对应数据:
// 定义形状标签 struct SphereTag {}; struct CylinderTag {}; struct AABBTag {}; struct OBBTag {}; enum ShapeType { Sphere, Cylinder, AABB, OBB, Count}; class Shape { private: ShapeType m_type; // 存储所有形状可能用到的数据(可根据需求调整存储方式) float m_radius; float m_halfLength; Vector3 m_minExtend; Vector3 m_maxExtend; public: // 球体构造函数 Shape(SphereTag, float r) : m_type(Sphere), m_radius(r) {} // 圆柱体构造函数 Shape(CylinderTag, float r, float hl) : m_type(Cylinder), m_radius(r), m_halfLength(hl) {} // AABB构造函数 Shape(AABBTag, const Vector3& minExt, const Vector3& maxExt) : m_type(AABB), m_minExtend(minExt), m_maxExtend(maxExt) {} // OBB构造函数 Shape(OBBTag, const Vector3& minExt, const Vector3& maxExt) : m_type(OBB), m_minExtend(minExt), m_maxExtend(maxExt) {} // 获取形状类型 ShapeType getType() const { return m_type; } // 按需添加数据获取方法(注意判断类型避免非法访问) float getRadius() const { if (m_type != Sphere && m_type != Cylinder) { /* 抛出异常或处理错误 */ } return m_radius; } };
使用示例:
Shape sphere(SphereTag{}, 1.0f); Shape cylinder(CylinderTag{}, 0.5f, 2.0f); Shape aabb(AABBTag{}, Vector3(-1,-1,-1), Vector3(1,1,1)); Shape obb(OBBTag{}, Vector3(-1,-1,-1), Vector3(1,1,1));
方案二:静态工厂方法
通过静态成员函数创建实例,每个工厂方法仅接收对应形状的必要参数,内部封装构造逻辑:
enum ShapeType { Sphere, Cylinder, AABB, OBB, Count}; class Shape { private: ShapeType m_type; float m_radius; float m_halfLength; Vector3 m_minExtend; Vector3 m_maxExtend; // 私有构造函数,仅允许工厂方法调用 explicit Shape(ShapeType type) : m_type(type) {} public: // 创建球体 static Shape createSphere(float r) { Shape s(Sphere); s.m_radius = r; return s; } // 创建圆柱体 static Shape createCylinder(float r, float hl) { Shape s(Cylinder); s.m_radius = r; s.m_halfLength = hl; return s; } // 创建AABB static Shape createAABB(const Vector3& minExt, const Vector3& maxExt) { Shape s(AABB); s.m_minExtend = minExt; s.m_maxExtend = maxExt; return s; } // 创建OBB static Shape createOBB(const Vector3& minExt, const Vector3& maxExt) { Shape s(OBB); s.m_minExtend = minExt; s.m_maxExtend = maxExt; return s; } ShapeType getType() const { return m_type; } // 按需添加数据获取方法 };
使用示例:
Shape sphere = Shape::createSphere(1.0f); Shape cylinder = Shape::createCylinder(0.5f, 2.0f); Shape aabb = Shape::createAABB(Vector3(-1,-1,-1), Vector3(1,1,1)); Shape obb = Shape::createOBB(Vector3(-1,-1,-1), Vector3(1,1,1));
进阶优化:用std::variant存储数据(C++17+)
如果不想冗余存储所有成员变量,可使用std::variant存储不同形状的专属数据结构,减少内存占用:
#include <variant> // 定义各形状的数据结构 struct SphereData { float radius; }; struct CylinderData { float radius; float halfLength; }; struct AABBData { Vector3 minExtend; Vector3 maxExtend; }; struct OBBData { Vector3 minExtend; Vector3 maxExtend; }; enum ShapeType { Sphere, Cylinder, AABB, OBB, Count}; class Shape { private: ShapeType m_type; std::variant<SphereData, CylinderData, AABBData, OBBData> m_data; public: Shape(SphereData data) : m_type(Sphere), m_data(std::move(data)) {} Shape(CylinderData data) : m_type(Cylinder), m_data(std::move(data)) {} Shape(AABBData data) : m_type(AABB), m_data(std::move(data)) {} Shape(OBBData data) : m_type(OBB), m_data(std::move(data)) {} ShapeType getType() const { return m_type; } const auto& getData() const { return m_data; } };
使用示例:
Shape sphere({1.0f}); Shape cylinder({0.5f, 2.0f}); Shape aabb({Vector3(-1,-1,-1), Vector3(1,1,1)}); Shape obb({Vector3(-1,-1,-1), Vector3(1,1,1)});
内容的提问来源于stack exchange,提问作者ChaoSXDemon
相关产品推荐
相关产品推荐

