c++ - 面向对象的方程式 API

标签 c++ oop equation

我们以二次方程为例:

a x^2 + b x + c = 0

可以将此等式视为描述值 a、b、c 和 x 之间的关系。给定其中三个,你可以计算出第四个。四种可能性是:

a = - (b x + c) / x^2
b = - (a x^2 + c) / x
c = - x (a x + b)
x = [-b +- sqrt(b^2 - 4 a c)] / (2 a)

这是表示该等式的一种方法。给定以下类(class):

class Quadratic
{

public: 

    double a; bool HasA = false; void A(double a_) { a = a_; HasA = true; }
    double b; bool HasB = false; void B(double b_) { b = b_; HasB = true; }
    double c; bool HasC = false; void C(double c_) { c = c_; HasC = true; }
    double x; bool HasX = false; void X(double x_) { x = x_; HasX = true; }

    // a = - (b x + c) / x^2

    double A()
    {
        if (HasB == false) throw domain_error("B not set");
        if (HasC == false) throw domain_error("C not set");
        if (HasX == false) throw domain_error("X not set");

        if (x == 0.0) throw domain_error("X cannot be 0.0");

        return - (b*x + c) / (x*x);
    }

    // x = [-b +- sqrt(b^2 - 4 a c)] / (2 a)

    vector<double> X()
    {
        if (HasA == false) throw domain_error("A not set");
        if (HasB == false) throw domain_error("B not set");
        if (HasC == false) throw domain_error("C not set");

        if (a == 0.0) throw domain_error("A cannot be 0.0");

        return 
        { 
            (-b + sqrt(b*b - 4 * a*c)) / (2 * a),
            (-b - sqrt(b*b - 4 * a*c)) / (2 * a)
        };
    }

    // b = - (a x^2 + c) / x
    // ...

    // c = - x (a x + b)
    // ...
};

我们可以按如下方式找到x。设置ABC:

obj.A(2.3);
obj.B(3.4);
obj.C(1.2);

X 可能有两个值,因此遍历结果:

for each (auto elt in obj.X()) cout << elt << endl;

如果未设置任何依赖值,则会抛出 domain_error 异常。

同样,为了找到A,我们设置BCX:

obj.B(1.2);
obj.C(2.3);
obj.X(3.4);

并显示结果:

cout << obj.A() << endl;

我的问题是,是否有其他方法可以用面向对象的语言表示和处理方程式?是否有比上述方法更惯用的方法?

最佳答案

你的问题的标题是这样的:

Object-oriented API for equations

但是,您的代码示例没有任何面向对象的内容,至少在我所知道的“面向对象编程”的既定定义中没有。 你没有虚函数,所以它不是面向对象的。

Bjarne Stroustrup 的常见问题 "What is "OOP" and what's so great about it?"说(重点是我加的):

In the context of C++ [...] it means programming using class hierarchies and virtual functions to allow manipulation of objects of a variety of types through well-defined interfaces and to allow a program to be extended incrementally through derivation.

标准 C++ 常见问题解答(也引用了第一个来源),答案 "Are virtual functions (dynamic binding) central to OO/C++?"像这样:

Without virtual functions, C++ wouldn’t be object-oriented.


因此,

My question is, are there other approaches to representing and working with equations in an object-oriented language?

答案应该是数学计算和面向对象编程通常不能很好地结合。面向对象就是在运行时选择抽象操作的具体实现。例如,您可以根据用户在运行时 的选择选择具有相同输入和输出的不同算法。这可以通过虚函数来完成。不过,面向对象会发生在您的应用程序的更高级别,并且计算本身不会是面向对象的。

Is there a more idiomatic approach than the above?

是的,通用编程,即模板。

您提供的所有代码都适用于 double值。如果我想将它与 float 一起使用怎么办? , std::complex<double>甚至是自定义 BigNumber类(class)?

使用模板,您可以编写通用代码,并在编译时选择具体实现。

首先,让我们让您的原始代码可编译:

#include <vector>
#include <stdexcept>
#include <math.h>

class Equation
{
public:
    bool HasA;
    bool HasB;
    bool HasC;
    bool HasX;

    double a;
    double b;
    double c;
    double x;


    double A()
    {
        if (!HasB) throw std::domain_error("B not set");
        if (!HasC) throw std::domain_error("C not set");
        if (!HasX) throw std::domain_error("X not set");

        if (x == 0.0) throw std::domain_error("X cannot be 0.0");

        return - (b*x + c) / (x*x);
    }

    // x = [-b +- sqrt(b^2 - 4 a c)] / (2 a)

    std::vector<double> X()
    {
        if (!HasA) throw std::domain_error("A not set");
        if (!HasB) throw std::domain_error("B not set");
        if (!HasC) throw std::domain_error("C not set");

        if (a == 0.0) throw std::domain_error("A cannot be 0.0");

        return 
        { 
            (-b + sqrt(b*b - 4 * a*c)) / (2 * a),
            (-b - sqrt(b*b - 4 * a*c)) / (2 * a)
        };
    }

    // b = - (a x^2 + c) / x
    // ...

    // c = - x (a x + b)
    // ...
};

int main()
{
    Equation e;
    std::vector<double> v = e.X();
}

(我已经修复了 == false 比较,这几乎总是糟糕的风格,但是从 C++ 编码质量 POV 来看还有更多工作要做,例如,将成员变量设为私有(private)。)

问题是整个事情只适用于 double秒。如果您尝试将它与 int 一起使用s,这是发生了什么:

int main()
{
    Equation e;
    std::vector<int> v = e.X();
}

结果:

error C2440: 'initializing' : cannot convert from
'std::vector<double,std::allocator<_Ty>>' to 'std::vector<int,std::allocator<_Ty>>'

以下是将类转换为模板的方法:添加 template <class T>在顶部并替换每个 doubleT (并添加两个 static_cast 告诉编译器您同意缩小转换,这可能由于 sqrt 的返回类型而发生):

#include <vector>
#include <stdexcept>
#include <math.h>

template <class T>
class Equation
{
public:
    bool HasA;
    bool HasB;
    bool HasC;
    bool HasX;

    T a;
    T b;
    T c;
    T x;


    T A()
    {
        if (!HasB) throw std::domain_error("B not set");
        if (!HasC) throw std::domain_error("C not set");
        if (!HasX) throw std::domain_error("X not set");

        if (x == 0.0) throw std::domain_error("X cannot be 0.0");

        return - (b*x + c) / (x*x);
    }

    // x = [-b +- sqrt(b^2 - 4 a c)] / (2 a)

    std::vector<T> X()
    {
        if (!HasA) throw std::domain_error("A not set");
        if (!HasB) throw std::domain_error("B not set");
        if (!HasC) throw std::domain_error("C not set");

        if (a == 0.0) throw std::domain_error("A cannot be 0.0");

        return 
        { 
            static_cast<T>((-b + sqrt(b*b - 4 * a*c)) / (2 * a)),
            static_cast<T>((-b - sqrt(b*b - 4 * a*c)) / (2 * a))
        };
    }

    // b = - (a x^2 + c) / x
    // ...

    // c = - x (a x + b)
    // ...
};

int main()
{
    Equation<int> e;
    std::vector<int> v = e.X();
}

当然,这只是故事的一半,因为很有可能您确实不想允许整数类型,只允许浮点类型,例如double。或 float (或自定义浮点类型)。 sqrt(2)的结果截断为 1很少可取。

为了让您的代码保持通用但防止出现此类问题,请继续阅读 static assertions用于编译时检查,将模板限制为特定类型。 std::is_floating_point 也可能有用。另请参阅以下最近关于 SO 的问题:

Getting std::complex<double> to pass std::is_floating_point test

请记住,这与面向对象编程没有任何关系。

关于c++ - 面向对象的方程式 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25706765/

相关文章:

c++ - 如何调用另一个对话框(Win32 应用程序)

c++ - 简单的多线程帮助? C++、WaitForSingleObject 和同步

python - 最大方程长度

C++ 目标用简单的语法 T.g 抛出错误

c++ - 未定义对 `inflate' 的引用

PHP 更改方法/函数可见性

oop - 面向对象的逻辑和数学

java - 如何在不重复代码的情况下编写子类构造函数?

animation - iOS 7 Spring 动画的时间与位置图方程(animateWithDuration :delay:usingSpringWithDamping:. ..)

Java字符串型方程两位数值问题