1.問(wèn)題
在很多用C++開(kāi)發(fā)服務(wù)器產(chǎn)品時(shí),需要將不同的數(shù)據(jù)類型存儲(chǔ)到一個(gè)容器中(有點(diǎn)類似HttpSession可以保存會(huì)話期間任意類型的數(shù)據(jù)),供其它使用程序查找。
在Java和C#中這是一個(gè)簡(jiǎn)單的問(wèn)題,可以使用Object對(duì)象來(lái)實(shí)現(xiàn)類型無(wú)關(guān)的數(shù)據(jù)結(jié)構(gòu),并且很好的解決了內(nèi)存回收等問(wèn)題。
但C++中很難做到這一點(diǎn),C++是一門靜態(tài)類型語(yǔ)言,沒(méi)有一個(gè)所有類型的基類。
2.一般方法
一般解決這個(gè)問(wèn)題的辦法是使用void*指針來(lái)存儲(chǔ)數(shù)據(jù),象下面的代碼:
map<string,void*>
但是這樣帶來(lái)幾個(gè)問(wèn)題:
(1)因?yàn)镃++在不知道類類型時(shí)無(wú)法正確的釋放內(nèi)存;
(2)很多使用者使用它時(shí),釋放內(nèi)存的時(shí)機(jī)難于確定;
3.讓它正確釋放內(nèi)存
我們可以定義一個(gè)公共的基類,讓所有需要放到容器的類型繼承它
class Object
{
public:
virtual ~Object(){cout<<"Object Destroy" << endl;}
};
由于使用了virtual析構(gòu)函數(shù)因此可以確保delete obj的時(shí)可以正常工作。因此上面的容器定義變成了這樣:
map<string,Object*>
4.讓它知道何時(shí)釋放內(nèi)存
大家都知道,這時(shí)必須使用引用計(jì)數(shù),不過(guò)很幸運(yùn)有現(xiàn)成的,我們使用boost::share_ptr
map<string,boost::share_ptr<Object*> >
很好兩個(gè)問(wèn)題都已經(jīng)解決,但如何向他們中加入C++的基本類型呢?
5.開(kāi)發(fā)基本類型的封裝類
基本類型很多,如果每一個(gè)都寫一個(gè)類,太累了,我們可以定義一個(gè)模板,這里的難點(diǎn)是基本類型之間的操作符重載,不同類型之間的運(yùn)算返回的類型并不相同,這就需要寫很多重載函數(shù),在這里我們使用Loki來(lái)簡(jiǎn)化這些操作。使用Loki的TypeList來(lái)自動(dòng)計(jì)算應(yīng)該是什么返回值
#include"Typelist.h" //Loki頭文件
template <typename T>
class PrimerType:public Object
{
public:
typedef T value_type;//基本類型
typedef PrimerType<T> class_type;//基本類型的對(duì)象類型
public:
PrimerType()
:m_value((value_type)0)
{
}
template<typename Other>
PrimerType(const Other& value)
:m_value(value)
{
}
~PrimerType()
{
cout<<"PrimerType Destroy" << endl;
}
//基本類型轉(zhuǎn)換操作符重載
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;
}
//作為類成員的算術(shù)運(yùn)算符操作符重載
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 );
};
//流輸入函數(shù),不用輸出(通過(guò)類型操作符重載自動(dòng)完成)
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;
//基本類型的對(duì)象類型
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;
//算術(shù)運(yùn)算返回類型的traits,運(yùn)算時(shí)以排在后面的類型返回
#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以前的類型做算術(shù)運(yùn)算都返回int32類型
typedef typename ::Loki::TL::TypeAt<PRIMERTYPELIST, (resulttype_index<5)?5:resulttype_index >::Result result_type;
};
//作為全局的算術(shù)運(yùn)算符操作符重載 + - * /
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;
}
//。。。省略 - * /等等
// 邏輯運(yùn)算符重載
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.小結(jié)
使用對(duì)象來(lái)表示基本類型,由于使用了virtual的析構(gòu)它是有內(nèi)存浪費(fèi)的,但在很多應(yīng)用中它是很有用的。
同時(shí)你可以增加String/DateTime的特化支持,這樣就完整了