以下是http://www.csdn.net/develop/Article/14/14487.shtm的一个改进版本,本来是作为评论附在上一篇文章后面的,但是作为评论发表的话,会丢失很多文字,很奇怪的说。本文是我和singleracer讨论的结果,个人认为几乎接近完美,希望能对大家有帮助,大家可以自己加入其它的单位体系和单位。
计量的模板类:
#ifndef _QUANTITY_H_
#define _QUANTITY_H_
#ifdef _DEBUG
#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<class UnitType>
struct UnitTraits {
typedef UnitType::Validator Validator;
};
template<class ValueType>
class ValueTraits {
public:
static bool equal(const ValueType & l, const ValueType & r)
{return (l == r);}
};
template<>
class ValueTraits<double> {
public:
static bool equal(const double & l, const double & r)
{
static double precision = 0.000000001;
return (l - r < precision);
}
};
template<>
class ValueTraits<float> {
public:
static bool equal(const float & l, const float & r)
{
static float precision = 0.000000001f;
return (l - r < precision);
}
};
template<typename ValueType, class UnitValidator, class _Traits = ValueTraits<ValueType> >
class Quantity
{
public:
typedef UnitValidator Validator;
template<typename UnitType>Quantity(const ValueType & amount, const UnitType & )
: m_amount(amount), m_unit(Singleton< unit_wrap<UnitType, ValueType> >::Instance())
{
ASSERT_SAME_TYPE(UnitTraits<UnitType>::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<typename UnitType> void convert(const UnitType & )
{
ASSERT_SAME_TYPE(UnitTraits<UnitType>::Validator, Validator);
unit_base<ValueType> * unit = Singleton< unit_wrap<UnitType, ValueType> >::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<(const Quantity & rhs)
{
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<typename ValueType>
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<typename UnitType, typename ValueType>
class unit_wrap : public unit_base<ValueType>
{
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<ValueType> * m_unit;
};
#define QUANTITY Quantity<ValueType,Validator,Traits>
template<typename ValueType,typename Validator,typename Traits>
QUANTITY inline _cdecl operator+(const QUANTITY & a,
const QUANTITY & b)
{return (QUANTITY(a)+=b);}
template<typename ValueType,typename Validator,typename Traits>
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<double, WeightValidator> Weight;
/*
template<typename ValueType, typename UnitType>
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<double, LengthValidator> Length;
/*
template<typename ValueType, typename UnitType>
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;
}