让我们以二次方程为例:
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
如下。设置A
,B
和C
:
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
,我们设置B
,C
和X
:
obj.B(1.2);
obj.C(2.3);
obj.X(3.4);
并显示结果:
cout << obj.A() << endl;
我的问题是,是否有其他方法来表示和使用面向对象语言中的方程式?是否有比上述更惯用的方法?
答案 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
值。如果我想将其与float
,std::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
请记住,这与面向对象编程没有任何关系。