分析模式-計量的C++實現——完美版本 (轉)

worldblog發表於2007-12-13
分析模式-計量的C++實現——完美版本 (轉)[@more@]

以下是/develop/Article/14/14487.shtm">http://www.csdn.net/develop/Article/14/14487.shtm的一個改進版本,本來是作為評論附在上一篇文章後面的,但是作為評論發表的話,會丟失很多文字,很奇怪的說。本文是我和singleracer討論的結果,個人認為幾乎接近完美,希望能對大家有幫助,大家可以自己加入其它的單位體系和單位。

計量的模板類:

#ifndef _QUANTITY_H_
#define _QUANTITY_H_

#ifdef _DE
#define ASSERT_SAME_TYPE( T1, T2) do {T1 v=T2();v; }while(false)
#else
#define ASSERT_SAME_TYPE( T1, T2)
#endif

#include "singleton.h"

template
struct UnitTraits {
 typedef UnitType::Validator Validator;
};

template
class ValueTraits {
public:
 static bool equal(const ValueType & l, const ValueType & r)
 {return (l == r);}
};

template<>
class ValueTraits {
public:
 static bool equal(const double & l, const double & r)
 {
 static double precision = 0.000000001;
 return (l - r < precision);
 }
};

template<>
class ValueTraits {
public:
 static bool equal(const float & l, const float & r)
 {
 static float precision = 0.000000001f;
 return (l - r < precision);
 }
};

template >
class Quantity
{
public:
 typedef UnitValidator Validator;

 templateQuantity(const ValueType & amount, const UnitType & )
 : m_amount(amount), m_unit(Singleton< unit_wrap >::Instance())
 {
 ASSERT_SAME_TYPE(UnitTraits::Validator, Validator);
 }
 ~Quantity()
 {
 }
 Quantity(const Quantity & other)
 : m_amount(other.m_amount), m_unit(other.m_unit)
 {
 }
 Quantity & operator=(const Quantity & rhs)
 {
 if(&rhs != this)
 {
 m_amount = rhs.m_amount;
 m_unit = rhs.m_unit;
 }
 return *this;
 }
 template void convert(const UnitType & )
 {
 ASSERT_SAME_TYPE(UnitTraits::Validator, Validator);
 unit_base * unit = Singleton< unit_wrap >::Instance();
 if(unit != m_unit)
 {
 m_amount = m_unit->to_standard(m_amount);
 m_unit = unit;
 m_amount = m_unit->from_standard(m_amount);
 }

 }
 Quantity & operator+=(const Quantity & rhs)
 {
 m_amount += unitize( rhs );
 return *this;
 }
 Quantity & operator-=(const Quantity & rhs)
 {
 m_amount -= unitize( rhs );
 return *this;
 }
 bool operator==(const Quantity & rhs)
 {
 return _Traits::equal( m_amount, unitize(rhs));
 }
 bool operator>(const Quantity & rhs)
 {
 return m_amount > unitize( rhs );
 }
 bool operator>=(const Quantity & rhs)
 {
 return (m_amount > unitize( rhs ) ? true : (equal( m_amount, unitize(rhs))) );
 }
 bool operator {
 return m_amount < unitize( rhs );
 }
 bool operator<=(const Quantity & rhs)
 {
 return (m_amount < unitize( rhs ) ? true : (equal( m_amount, unitize(rhs))) );
 }

private:
 // 對於單位相同的運算不需要轉換,也就沒有丟失精度的問題
 ValueType unitize( const Quantity & rhs )
 {
 if( m_unit == rhs.m_unit )
 return rhs.m_amount;
 else
 return m_unit->from_standard(rhs.m_unit->to_standard(rhs.m_amount));
 }

private:
 template
 class unit_base
 {
 public:
 virtual ValueType to_standard(const ValueType & val) const = 0;
 virtual ValueType from_standard(const ValueType & val) const = 0;
 };
 // 把unit_wrap設計為singleton,這樣比較單位是否相同只需作簡單的指標比較
 template
 class unit_wrap : public unit_base
 {
protected:
 unit_wrap() {}
 ~unit_wrap() {}
 public:
 virtual ValueType to_standard(const ValueType & val) const
 {
 return UnitType::to_standard(val);
 }
 virtual ValueType from_standard(const ValueType & val) const
 {
 return UnitType::from_standard(val);
 }
 };

private:
 ValueType m_amount;
 unit_base * m_unit;
};

#define QUANTITY Quantity
template
QUANTITY inline _cdecl operator+(const QUANTITY & a,
 const QUANTITY & b)
{return (QUANTITY(a)+=b);}

template
QUANTITY inline _cdecl operator-(const QUANTITY & a, const QUANTITY & b)
{return (QUANTITY(a)-=b);}

#endif /* _QUANTITY_H_ */

重量:
#ifndef _WEIGHT_H_
#define _WEIGHT_H_

#include "../Quantity.h"

class WeightValidator {};
typedef Quantity Weight;

/*
template
Weight inline _cdecl operator*(const ValueType& value, const UnitType& unit )
{return Weight(value, unit);}
*/

class Kilogram
{
public:
 typedef WeightValidator Validator;
 static double to_standard(double val)
 {return val;}
 static double from_standard(double val)
 {return val;}
};

class Gramme
{
public:
 typedef WeightValidator Validator;
 static double to_standard(double val)
 {return val/1000.0;}
 static double from_standard(double val)
 {return val*1000.0;}
};

Kilogram _kg;
Gramme _g;

#endif /* _WEIGHT_H_ */

長度:
#ifndef _LENGTH_H_
#define _LENGTH_H_

#include "../Quantity.h"

class LengthValidator {};
typedef Quantity Length;

/*
template
Length inline _cdecl operator*(const ValueType& value, const UnitType& unit )
{return Length(value, unit);}
*/

class Meter
{
public:
 typedef LengthValidator Validator;
 static double to_standard(double val)
 {return val;}
 static double from_standard(double val)
 {return val;}
};

class Kilometer
{
public:
 typedef LengthValidator Validator;
 static double to_standard(double val)
 {return val*1000.0;}
 static double from_standard(double val)
 {return val/1000.0;}
};

Meter _m;
Kilometer _km;

#endif /* _LENGTH_H_ */

測試程式碼:
// Quantity.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "weight.h"
#include "length.h"

void testWeight()
{
 Weight w1(1.0, _kg); //構造
 Weight w2(1.0, _g); //建構函式

 Weight w3 = w1; //複製建構函式
 w3 = w2; //賦值操作

 Weight w4(1.0, _kg);
 w4 += w1; //相同單位相加
 w4 += w2; //不同單位相加
 Weight w5 = w4 + w1; //相同單位相加
 w5 = w4 + w2; //不同單位相加

 Weight w6(2.0, _kg);
 w6 -= w1; //相同單位相減
 w6 -= w2; //不同單位相減
 Weight w7 = w5 - w1; //相同單位相減
 w7 = w5 - w2; //不同單位相減

 // 比較
 Weight a(1.0, _kg);
 Weight b(2.0, _kg);
 Weight c(2000.0, _g);
 Weight d(3000.0, _g);
 bool f = (a < b);
 f = (a < c);
 f = (b==c);
 f = (b < d);

 //單位換算
 Weight w10(1.0, _kg);
 w10.convert(_g);
 w10.convert(_kg);
}

void testLength()
{
 Length l1(1.0, _km); //建構函式
 Length l2(1.0, _m); //建構函式

 Length l3 = l1; //複製建構函式
 l3 = l2; //賦值操作

 Length l4(1.0, _km);
 l4 += l1; //相同單位相加
 l4 += l2; //不同單位相加
 Length l5 = l4 + l1; //相同單位相加
 l5 = l4 + l2; //不同單位相加

 Length l6(2.0, _km);
 l6 -= l1; //相同單位相減
 l6 -= l2; //不同單位相減
 Length l7 = l5 - l1; //相同單位相減
 l7 = l5 - l2; //不同單位相減

 // 比較
 Length a(1.0, _km);
 Length b(2.0, _km);
 Length c(2000.0, _m);
 Length d(3000.0, _m);
 bool f = (a < b);
 f = (a < c);
 f = (b==c);
 f = (b < d);

 //單位換算
 Length l10(1.0, _km);
 l10.convert(_m);
 l10.convert(_km);
}

void testError()
{
#if(0)
 Weight w1; // 沒有預設建構函式
 Length l1; // 沒有預設建構函式
#endif
#if(0)
 Weight w2(1.0, _km); //錯誤的單位
 Length l2(1.0, _g); //錯誤的單位
#endif
#if(0)
 Weight w3(1.0, _kg);
 Length l3(1.0, _m);
 w3.convert(_km); //錯誤的單位
 l3.convert(_g); //錯誤的單位
#endif
#if(0)
 Weight w4(1.0, _kg);
 Length l4(1.0, _m);
 w4 += l4; //錯誤的型別
 w4 -= l4; //錯誤的型別
#endif
#if(0)
 Weight w5(1.0, _kg);
 Length l5(1.0, _m);
 bool f = (w5 == l5);
 f = (w5 > l5);
 f = (w5 < l5);
#endif
}

int main(int argc, char* argv[])
{
 testWeight();
 testLength();
 testError();
 return 0;
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992498/,如需轉載,請註明出處,否則將追究法律責任。

相關文章