2014年4月14日月曜日

角度を扱うクラス (未完成)

角度を扱うクラスって見ないなぁ,と思って作ってみた.angle(度数法)とradian(弧度法)を表すクラスで,それぞれに代入する場合は意図的に書かないとできないようにした.角度を受け取る関数なんかで仮引数の型としてこのクラスを使うことで,度数法で渡して欲しいのか,弧度法で渡して欲しいのかがはっきりするな,と思ったり.

#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
using namespace std;
class angle;
class radian;
// angle(度数法)とradian(弧度法)の実装がほぼ同じなため
// 共通処理をまとめる
template <typename T>
class angle_base {
protected:
explicit angle_base(float v)
: mValue(v)
{}
explicit angle_base(angle_base const & v)
: mValue(v.value())
{}
public:
float value() const
{
return mValue;
}
T & operator+=(T const & rhs)
{
mValue += rhs.value();
return *static_cast<T *>(this);
}
T & operator-=(T const & rhs)
{
mValue -= rhs.value();
return *static_cast<T *>(this);
}
T & operator*=(float rhs)
{
mValue *= rhs;
return *static_cast<T *>(this);
}
private:
float mValue;
};
class angle : public angle_base<angle> {
public:
explicit angle(float v = 0.f)
: angle_base<angle>(v)
{}
explicit angle(radian const & rad);
};
class radian : public angle_base<radian> {
public:
explicit radian(float v = 0.f)
: angle_base<radian>(v)
{}
explicit radian(angle const & ang);
};
// 両方のクラスがangle_baseを継承していることがわからないと
// value()が利用できないので,実装を分離
angle::angle(radian const & rad)
: angle_base<angle>(rad.value() / M_PI * 180.f)
{}
radian::radian(angle const & ang)
: angle_base<radian>(ang.value() / 180.f * M_PI)
{}
int main(int argc, char ** argv)
{
angle a(90.f);
angle b(45.f);
angle c;
radian r;
c += a;
// compile error
// r = a;
r = radian(a);
cout << a.value() << endl;
cout << b.value() << endl;
cout << c.value() << endl;
cout << r.value() << endl;
return 0;
}
view raw angle.cpp hosted with ❤ by GitHub


一度作ってから,実装がほぼ同じなのでCRTPでまとめてみたものの,二項演算子の実装があんまりすっきりしなくて,いったん放置.

しかし,何故こういう安全策が用意されないのかなぁ,と考えていて,そもそもこういう角度を扱うような状況って処理速度が云々って言っていることが多いし,const参照で渡したら間接参照になるから多少は速度が落ちるかも,とか考えているのではないかと.

0 件のコメント:

コメントを投稿