1.问题
在很多用C++开发服务器产品时,需要将不同的数据类型存储到一个容器中(有点类似HttpSession可以保存会话期间任意类型的数据),供其它使用程序查找。
在Java和C#中这是一个简单的问题,可以使用Object对象来实现类型无关的数据结构,并且很好的解决了内存回收等问题。
但C++中很难做到这一点,C++是一门静态类型语言,没有一个所有类型的基类。
2.一般方法
一般解决这个问题的办法是使用void*指针来存储数据,象下面的代码:
map<string,void*>
但是这样带来几个问题:
(1)因为C++在不知道类类型时无法正确的释放内存;
(2)很多使用者使用它时,释放内存的时机难于确定;
3.让它正确释放内存
我们可以定义一个公共的基类,让所有需要放到容器的类型继承它
class Object
{
public:
virtual ~Object(){cout<<"Object Destroy" << endl;}
};
由于使用了virtual析构函数因此可以确保delete obj的时可以正常工作。因此上面的容器定义变成了这样:
map<string,Object*>
4.让它知道何时释放内存
大家都知道,这时必须使用引用计数,不过很幸运有现成的,我们使用boost::share_ptr
map<string,boost::share_ptr<Object*> >
很好两个问题都已经解决,但如何向他们中加入C++的基本类型呢?
5.开发基本类型的封装类
基本类型很多,如果每一个都写一个类,太累了,我们可以定义一个模板,这里的难点是基本类型之间的操作符重载,不同类型之间的运算返回的类型并不相同,这就需要写很多重载函数,在这里我们使用Loki来简化这些操作。使用Loki的TypeList来自动计算应该是什么返回值
#include"Typelist.h" //Loki头文件
template <typename T>
class PrimerType:public Object
{
public:
typedef T value_type;//基本类型
typedef PrimerType<T> class_type;//基本类型的对象类型
public:
PrimerType()
:m_value((value_type)0)
{
}
template<typename Other>
PrimerType(const Other& value)
:m_value(value)
{
}
~PrimerType()
{
cout<<"PrimerType Destroy" << endl;
}
//基本类型转换操作符重载
operator value_type() const
{
return m_value;
}
//赋值操作符重载
const class_type& operator=(value_type value)
{
m_value=value;
return *this;
}
bool operator!( ) const
{
return !m_value;
}
//作为类成员的算术运算符操作符重载
class_type& operator++()
{// ++ 前缀
m_value+=1;
return *this;
}
const class_type operator++(int)
{// ++ 后缀
class_type oldValue=*this;
m_value+=1;
return oldValue;
}
class_type& operator--()
{// -- 前缀
m_value-=1;
return *this;
}
const class_type operator--(int)
{// -- 后缀
class_type oldValue=*this;
m_value-=1;
return oldValue;
}
class_type& operator+=(const value_type& value)
{
m_value+=value;
return *this;
}
//。。。省略-= /= *= &= |= ^= %= 等等
private:
value_type m_value;
friend istream& operator>><T> ( istream& is, class_type& ptvalue );
};
//流输入函数,不用输出(通过类型操作符重载自动完成)
template<typename T>
istream& operator>> ( istream& is, PrimerType<T>& ptvalue )
{
is >> ptvalue.m_value;
return is;
}
//基本类型重定义
typedef __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef __int64 int64;
typedef unsigned __int8 uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
//基本类型的对象类型
typedef PrimerType<bool> Boolean;
typedef PrimerType<int8> Int8;
typedef PrimerType<int16> Int16;
typedef PrimerType<int32> Int32;
typedef PrimerType<int64> Int64;
typedef PrimerType<uint8> UInt8;
typedef PrimerType<uint16> UInt16;
typedef PrimerType<uint32> UInt32;
typedef PrimerType<uint64> UInt64;
typedef PrimerType<float> Float;
typedef PrimerType<double> Double;
typedef PrimerType<long> Long;
typedef PrimerType<unsigned long> ULong;
//更友好的名字
typedef Int8 Char;
typedef Int16 Short;
typedef Int32 Int;
typedef UInt8 Byte;
typedef UInt16 UShort;
typedef UInt32 UInt;
//算术运算返回类型的traits,运算时以排在后面的类型返回
#define PRIMERTYPELIST TYPELIST_13(bool,int8,uint8,int16,uint16,int32,uint32,long,unsigned long,int64,uint64,float,double)
// |
// int
template <typename T1, typename T2>
struct ResultType_Traits
{
enum { lefttype_index =::Loki::TL::IndexOf<PRIMERTYPELIST,T1>::value};
enum { righttype_index =::Loki::TL::IndexOf<PRIMERTYPELIST,T2>::value};
enum { resulttype_index = (lefttype_index>righttype_index)?lefttype_index:righttype_index};
//在vc7.1下int32以前的类型做算术运算都返回int32类型
typedef typename ::Loki::TL::TypeAt<PRIMERTYPELIST, (resulttype_index<5)?5:resulttype_index >::Result result_type;
};
//作为全局的算术运算符操作符重载 + - * /
template<typename T1,typename T2>
typename ResultType_Traits<T1,T2>::result_type operator +(const PrimerType<T1>& lhs,const T2& rhs)
{
return (T1)lhs+rhs;
}
template<typename T1,typename T2>
typename ResultType_Traits<T1,T2>::result_type operator +(const T1& lhs,const PrimerType<T2>& rhs)
{
return lhs+(T2)rhs;
}
template<typename T1,typename T2>
typename ResultType_Traits<T1,T2>::result_type operator +(const PrimerType<T1>& lhs,const PrimerType<T2>& rhs)
{
return (T1)lhs+(T2)rhs;
}
//。。。省略 - * /等等
// 逻辑运算符重载
template<typename T1,typename T2>
bool operator ==(const PrimerType<T1>& lhs,const T2& rhs)
{
return (T1)lhs==rhs;
}
template<typename T1,typename T2>
bool operator ==(const T1& lhs,const PrimerType<T2>& rhs)
{
return lhs==(T2)rhs;
}
template<typename T1,typename T2>
bool operator ==(const PrimerType<T1>& lhs,const PrimerType<T2>& rhs)
{
return (T1)lhs==(T2)rhs;
}
//。。。省略 != >= 等等
6.小结
使用对象来表示基本类型,由于使用了virtual的析构它是有内存浪费的,但在很多应用中它是很有用的。
同时你可以增加String/DateTime的特化支持,这样就完整了