6

角度クラスをラジアンまたは度で初期化したいのですが、それが良い考えかどうかわかりません。私は次のようなことを考えています:

クラス図

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);
...

このようにして、コードでラジアンと度を混同しません。しかし、これは良い考えですか、それとも他のデザインを使用する必要がありますか?

4

4 に答える 4

15

ここでは、継承はまったく必要ありません。オブジェクトが構築されると、違いは気にしなくなります - オブジェクトはまったく同じように動作します。したがって、解決しなければならない唯一の問題は、構成 Angleオブジェクトを読みやすい方法で作成する方法です。

これに対する通常の解決策は、名前付きコンストラクターを使用することです。

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 ) );
于 2012-08-25T18:40:20.820 に答える
11

ここでは継承の必要性がわかりません。クラスの使用に関する限り、重要なのは角度を取得することだけです最初に角度またはラジアンであったかどうかは関係ありません。

免責事項:私はこれを以前にやったことがあります。まったく同じユースケースです。私の解決策は、コンストラクターが 2 つの引数を取るようにすることでした: 数値とユニット列挙型です。クラスを次のように使用します。

Angle a(1.2345, Angle::Radians);
std::cout << a.radians() << a.degrees() << sin(a);

共通の単位から角度を作成する便利なメソッドが必要な場合は、ヘルパー メソッドを使用できます。個別のクラスは必要ありません。

Angle r = Radians(2.3);
Angle d = Degrees(180);

とにかく - 私が過去に喜んで使っていたもの。それが役に立てば幸い!

于 2012-08-25T18:23:04.383 に答える
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与えられた角度の種類をチェックし、別の計算を行う関数を書くべきではありません。2 つのバージョンを作成し、コンパイラに作業を任せます。

float Sin(Radians x);
float Sin(Degrees x);

または、次のように記述します (実装に必要な型 (おそらくラジアン) を使用):

float Sin(Radians x);

ポイントは、「抽象的な」角度を持つことができるということではありません(これは有用な概念ではないと思います)。ポイントは、ラジアンと度数を混同しないようにし、2 つの暗黙的な変換を行うことです。

抽象基本Angleクラスを持つと、構文ノイズが増加し (どこでも参照を使用する必要があります)、パフォーマンスが低下する可能性があります。このソリューションでは、「高速パス」を取得することを期待するのではなく、角度を目的の単位で保存することもできます。

于 2012-08-25T18:31:09.357 に答える
1

角度をオブジェクトとして使用し、度とラジアンを同じ内部角度値の異なるゲッター セッターとして使用します。

于 2012-08-25T18:20:39.200 に答える