OOP 表示具有多种表示形式的数学对象

问题描述 投票:0回答:1

椭圆可以用不同的方式表示。有通过中心点、半轴和倾斜角的表示,所以有五个参数 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++ oop software-design
1个回答
0
投票

如果您想留在 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};
}

有关变体的更多信息:https://en.cppreference.com/w/cpp/utility/variant

© www.soinside.com 2019 - 2024. All rights reserved.