椭圆可以用不同的方式表示。有通过中心点、半轴和倾斜角的表示,所以有五个参数 x、y、a、b、phi,但我们也可以用圆锥系数 A、B、C 表示, D, E, F 其中椭圆由 Ax^2+Bxy+Cy^2+Dx+Ey+F=0 定义。我想知道在面向对象编程中将其表示为一个类的好方法是什么。
我想到的第一种方法是让每个椭圆都有所有数据
struct EllipseCenterSemiAxisTilt {
// center
double x0;
double y0;
// demi-axis
double a;
double b;
//tilt angle
double phi;
};
struct EllipseConicCoeff
{
// the conic is a quadratic given by the general equation ax^2 + 2bx + cy^2 + 2dx + 2fy + g
double a;
double b;
double c;
double d;
double f;
double g;
};
class Ellipse
{
public:
Ellipse(EllipseCenterSemiAxisTilt centerSemiAxisTilt) : m_centerSemiAxisTilt(centerSemiAxisTilt), m_ConicCoeff(CenterSemiAxisTiltToConicCoeff(centerSemiAxisTilt)) {}
Ellipse(EllipseConicCoeff ConicCoeff) : m_centerSemiAxisTilt(ConicCoeffToCenterSemiAxisTilt(ConicCoeff)), m_ConicCoeff(ConicCoeff){}
EllipseConicCoeff CenterSemiAxisTiltToConicCoeff(EllipseCenterSemiAxisTilt CenterSemiAxisTilt);
EllipseCenterSemiAxisTilt ConicCoeffToCenterSemiAxisTilt(EllipseConicCoeff ConicCoeff);
private:
EllipseCenterSemiAxisTilt m_centerSemiAxisTilt;
EllipseConicCoeff m_ConicCoeff;
};
但这对我来说有点不满意,因为也许对于一个特定的椭圆,我们只使用两种表示之一。
我想到的另一种方法是有一个基本椭圆类,每个表示都有两个派生类,然后我们可以定义函数在需要时在它们之间进行转换
struct EllipseCenterSemiAxisTilt {
// center
double x0;
double y0;
// demi-axis
double a;
double b;
//tilt angle
double phi;
};
struct EllipseConicCoeff
{
// the conic is a quadratic given by the general equation ax^2 + 2bx + cy^2 + 2dx + 2fy + g
double a;
double b;
double c;
double d;
double f;
double g;
};
class EllipseClass
{
};
class EllipseClassConicCoeff : EllipseClass
{
public:
EllipseClassConicCoeff(EllipseConicCoeff conicCoeff) : m_conicCoeff(conicCoeff) {}
private:
EllipseConicCoeff m_conicCoeff;
};
class EllipseClassCenterSemiAxisTilt : EllipseClass
{
public:
EllipseClassCenterSemiAxisTilt(EllipseCenterSemiAxisTilt CenterSemiAxisTilt) : m_CenterSemiAxisTilt(CenterSemiAxisTilt) {}
private:
EllipseCenterSemiAxisTilt m_CenterSemiAxisTilt;
};
我的问题是:处理此类数据的合适方法是什么? (这只是一个例子,但通常问题是针对可能具有多种表示形式的数学对象,如椭圆、复数或转换更多的对象)
如果您想留在 C/C++ 世界并且内存管理可能很重要,那么我认为 std::variant 可能是一个很好的方法。这是一个例子:
struct EllipseCenterSemiAxisTilt {
// center
double x0;
double y0;
// demi-axis
double a;
double b;
//tilt angle
double phi;
};
struct EllipseConicCoeff
{
double a;
double b;
double c;
double d;
double f;
double g;
};
int main()
{
std::variant<EllipseCenterSemiAxisTilt, EllipseConicCoeff> e;
// setting underlying to EllipseCenterSemiAxisTilt
e = EllipseCenterSemiAxisTilt{1,2,3,4,5};
// get value as EllipseCenterSemiAxisTilt
auto foo = std::get<EllipseCenterSemiAxisTilt>(e);
try
{ // we try to access it as the other struct
std::get<EllipseConicCoeff>(e);
} catch (const std::bad_variant_access& ex){} // ops, we can't do that here
// but we can redefine it
e = EllipseConicCoeff{1,2,3,4,5,6};
}