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的特化支持,這樣就完整了