面向对象的方程式API

时间:2014-09-07 03:15:48

标签: 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 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;

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

1 个答案:

答案 0 :(得分:0)

你问题的标题是:

  

面向对象的方程式API

但是,没有任何面向对象的代码示例,至少没有我所知道的“面向对象编程”的既定定义。 您没有虚拟功能,因此它不是面向对象的。

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

  

在C ++ [...]的上下文中,它意味着使用类层次结构和虚拟编程   函数允许操作各种类型的对象   通过定义良好的接口并允许程序扩展   通过推导逐步增加。

标准C ++常见问题解答(也引用第一个来源),回答"Are virtual functions (dynamic binding) central to OO/C++?",如下所示:

  

没有虚函数,C ++就不会是面向对象的。


因此,

  

我的问题是,是否有其他代表和工作的方法   使用面向对象语言中的方程?

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

  

是否有比上述更惯用的方法?

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

您展示的所有代码都使用double值。如果我想将其与floatstd::complex<double>或甚至是自定义BigNumber类一起使用,该怎么办?

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

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

#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还有更多工作要做,例如将成员变量设为私有。)

问题是这整件事只适用于double。如果您尝试将其与int一起使用,则会发生以下情况:

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>并用double替换每个T(并添加两个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或{等浮点类型{1}}(或自定义浮点类型)。 float被截断为sqrt(2)的结果很少是可取的。

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

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

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