我想做一个以弧度或度数初始化的角度类,但我不知道这是不是一个好主意。我正在考虑这样的事情:
class Radian;
class Degree;
/**
* My angle class.
**/
class Angle
{
private:
float m_radian;
public:
explicit Angle(const Radian& rad);
explicit Angle(const Degree& deg);
float GetRadian(void) const
{
return this->m_radian;
}
float GetDegree(void) const
{
return ToDegree(this->m_radian);
}
bool IsEqual(const Angle& angle, float epsilon = 0.001f) const
{
return Abs<float>(this->m_radian - angle.m_radian) < epsilon;
}
void Set(const Angle& ang);
protected:
Angle(void) : m_radian(0.0f)
{}
Angle(float rad) : m_radian(rad)
{}
};
class Radian : public Angle
{
public:
Radian(void)
{}
Radian(float r) : Angle(r)
{}
};
class Degree : public Angle
{
public:
Degree(void)
{}
Degree(float d) : Angle(ToRadian(d))
{}
};
/// Trigonometric functions.
float Sin(const Angle& angle);
...
这样我就不会在我的代码中混淆弧度和度数。但是,这是一个好主意还是我应该使用其他设计?
答案 0 :(得分:13)
这里根本不需要任何继承。构建对象后,您不再关心差异 - 它们的行为完全相同。因此,您必须解决的唯一问题是如何以可读的方式构建构建 Angle
对象。
通常的解决方法是使用named constructors:
class Angle
{
public:
static Angle fromRadians( float v );
static Angle fromDegrees( float v );
// ...
private:
Angle( float rad );
// ...
};
您可以提供具有表达名称的工厂函数,而不是直接调用构造函数。所以你写道:
void f( Angle::fromDegrees( 3.0 ), Angle::fromRadians( 17.0 ) );
答案 1 :(得分:9)
我认为这里不需要继承。就使用你的课程而言,重要的是你得到一个角度 - 无论是以度数还是以弧度开头都是无关紧要的。
免责声明:我之前已经这样做了。完全相同的用例。我的解决方案是使构造函数采用两个参数:数字和单位枚举。我会这样使用我的课程:
Angle a(1.2345, Angle::Radians);
std::cout << a.radians() << a.degrees() << sin(a);
如果你想要方便的方法来创建普通单位的角度,它们可能只是:辅助方法。不需要单独的课程。
Angle r = Radians(2.3);
Angle d = Degrees(180);
无论如何 - 正是我过去常常使用的东西。希望它有所帮助!
答案 2 :(得分:6)
我会建议:
class Radians {
explicit Radians(float a) : angle_(a) {}
Radians(Degrees a) : angle_(a * PI/180.f) {}
operator float() { return angle_; }
private:
float angle_;
}
class Degrees {
explicit Degrees(float a) : angle_(a) {}
Degrees(Radians a) : angle_(a * 180.f/PI) {}
operator float() { return angle_; }
private:
float angle_;
}
这会强制函数的自然单位成为其界面的一部分,我认为这是一件好事。你永远不应该编写一个Sin
函数来检查它给出的角度,并进行不同的计算。您可以编写两个版本,让编译器完成工作:
float Sin(Radians x);
float Sin(Degrees x);
或者您只需编写一个(使用实现所需的任何类型 - 可能是弧度):
float Sin(Radians x);
关键不在于你可以有一个“抽象”的角度(我认为它不是一个有用的概念),重点是避免使用弧度混淆度数,并在两个隐式之间进行转换。 / p>
具有抽象基类Angle
类会增加语法噪音(您需要在任何地方使用引用)并且可能会降低性能。此解决方案还允许您以所需的单位存储角度,而不是希望您获得“快速路径”。
答案 3 :(得分:1)
对于相同的内角值,我会使用角度作为对象和度,使用弧度作为不同的吸气剂设定器。