最近思來索去~一直都是寫模板做數據結構還沒有真正意義上的可以儲存任意數據類型的結構,使用auto還需要先初始化類型,便着手自己實現了一個支持儲存所有數據類型(包括自己創建的類或者結構體)。
設計初衷打算仿auto形式(傳入什麼類型便使用什麼類型),這麼做確實比較簡單點但實用性不強。後來考慮可以參考CString增加Format格式化輸入字符串和任意類型轉換(當然不包括自己創建的類,因爲不是一種形式),其中包括char(1個字節)到long long(8個字節)之間的轉換等等…,首先展覽下用法···:
Testauto testte;//這個便是類的名稱 和類對象,下面以這個對象作展示
testte = /*(char*)*/"-1234567890";//傳入的是個常量字符串,不過我們採用的是拷貝形式,把字符串內存(內容)拷貝到我們的對象內
short testchar1234 = testte.OutShort();//在這裏我們做了字符串轉換到short類型輸出,這裏按照了short的最大值做儲存範圍(我們只要在32767之內的部分,保證數據正確有時候我們只需要這麼多數字這麼做比較合理)
testte = /*(int)*/-123456789;//前面註釋的類型可以自己指明,如果按照默認系統將會根據字節數長度(比如32000這個數在1字節到2字節之間,默認調用2字節方法)來自動判斷類型(還是挺好的```)
testte.Format("%s%d!","123",456);//這裏就採用了CStirng風格增加Format方法儲存數據爲字符串,使用起來還不算太無聊,可以省用些CString
/*********************************************************
在介紹這個結構後介紹存儲自定義類方式~~~~~~
**********************************************************/
簡單介紹了一小部分用法,下面說下結構設計:
1.爲了確保最大化支持數據類型以及自己定義的類,採用Void*類型做數據儲存對象(這樣的設計類似於容器形式,可以稱這個類爲容器,通過代碼無法實現auto那麼靈活,不過功能卻比auto強大許多);
2.爲了更好的知道傳入的是什麼類型以及省事(傳自己定義類的時候,用設計的宏調用保證類型的正確)針對每個數據類型都做了一個運算符方法(float,double沒有做專門運算符,我很少用浮點數···);
3.針對輸出字符串(可以傳入數字轉換到字符串進行輸出),定義了一個void*類型對象做 數據儲存對象的拷貝 ,這麼做是爲了數據儲存對象不被修改;
4.針對void運算符特作說明:起初設計void運算符是爲了傳入自己定義的類以及儲存類對象,後來發現一個類對象轉換爲數據類型也是一個(比如接收到void類對象轉換到char對象得到是一個字節,獲取指針式四個字節)這樣的結果就是丟失數據! 後來思考Java反射得到思路,雖然不能像Java那麼用,但是我們傳參數時可以穿類對象或者類名…,就這樣實現了自定義類對象儲存;
5.針對自定義類對象這塊我採用了可以直接修改對象內參數的方式(考慮到之前寫過的模板類都可以直接修改內部數據);
6.關於內存管理還是延續了STL系列經典思路,用多少內存就分配多少內存,多餘的內存及時釋放,儘量少留下碎片,析構函數還是採用一貫風格採用虛析構並做最後一次內存判斷處理。
下面介紹下重點實現部分,然後貼上全部代碼:
1.首先說下自定義類對象傳入宏:
第一個參數是 Testauto類對象 ,
第二個參數是 自定義類對象 (這裏以Test1類做參考),
第三個參數是 自定義類名稱或者自定義類對象,下面是宏原型
#define WriteType(obj,class_obj,class_name)\
obj.InClassObj(class_obj,sizeof(class_name));
使用參考:
傳入自定義類名稱方式 WriteType(testte,&testtest12,Test1);
傳入自定義類對象方式 WriteType(testte,&testtest12,testtest12);
2.類內部採用了enum結構做數據類型儲存:
enum
{
type_int8 //char
,type_uint8 // unsigned char
,type_int16 // short
,type_uint16 // unsigned short
,type_int32 // int
,type_uint32 //unsigned int
,type_int64 // long long
,type_uint64 // unsigned long long
,type_string // char*
,type_obj // 自定義類對象
};
3.類內部針對數據類型接收採用運算符方法:
void* operator = (const void* obj);
4.獲取自定義類對象:
void* GetObj()
{
return m_data;
}
通過GetObj()方法獲取自定義類對象,可以直接給自定義類做內存地址傳入,或者直接修改對象內數據。
使用參考:
數據形式傳參 Test1 test2 = *(Test1*)testte.GetObj();
指針形式傳內存地址 Test1* test2 = (Test1*)testte.GetObj();
指針形式調用內存變量 ((Test1*)testte.GetObj())->nNum = 5;
下面貼上全部代碼:
/*
******************************************************
*李坤昱
*[email protected]
******************************************************
*/
#define WriteType(obj,class_obj,class_name)\\類對象保存調用宏
obj.InClassObj(class_obj,sizeof(class_name));
class Testauto//參考類實現
{
enum
{
type_int8
,type_uint8
,type_int16
,type_uint16
,type_int32
,type_uint32
,type_int64
,type_uint64
,type_string
,type_obj
};
public:
virtual ~Testauto()//虛析構函數 做最後一次內存判斷並處理
{
if (0 != m_data && 0 != m_ndataSize)
{
delete[] m_data;
}
if (0 != m_Condata && 0 != m_nCondataSize)
{
delete[] m_Condata;
}
}
Testauto():m_ntype(0),m_data(0),m_ndataSize(0),m_Condata(0),m_nCondataSize(0)//做了最基本的構造函數
{
}
void* InClassObj(const void* obj,int nlen);/* 這個用來代替模版,可以儲存自己寫的類對象 */
void* operator = (const void* obj);/* 幾乎沒有起到作用 */
char operator = (const char & obj);
unsigned char operator = (const unsigned char & obj);
short operator = (const short & obj);
unsigned short operator = (const unsigned short & obj);
int operator = (const int & obj);
unsigned int operator = (const unsigned int & obj);
long long operator = (const long long & obj);
unsigned long long operator = (const unsigned long long & obj);
char* operator = (const char* obj);
void* GetObj()//獲取自定義類對象
{
return m_data;
}
char OutChar()//輸出char 一個字節(是ascll 10進制數字)
{
if (0 != m_data && 0 != m_ndataSize)
{
return *static_cast<char*>(m_data);
}
return NULL;
}
unsigned char OutUChar()//輸出unsigned char 一個字節(是ascll 10進制數字)
{
if (0 != m_data && 0 != m_ndataSize)
{
return *static_cast<unsigned char*>(m_data);
}
return NULL;
}
short OutShort()//輸出short
{
return *static_cast<short*>(GetData(type_int16));
}
unsigned short OutUShort()//輸出unsigned short
{
return *static_cast<unsigned short*>(GetData(type_uint16));
}
int OutInt()//輸出int
{
return *static_cast<int*>(GetData(type_int32));
}
unsigned int OutUInt()//輸出unsigned int
{
return *static_cast<unsigned int*>(GetData(type_uint32));
}
long long OutInt64()//輸出long long
{
return *static_cast<long long*>(GetData(type_int64));
}
unsigned long long OutUInt64()//輸出unsigned long long
{
return *static_cast<unsigned long long*>(GetData(type_uint64));
}
void* GetData(int type);//獲取需要輸出的數據類型(在這裏封裝了大部分數據類型)
char* Outstring();//輸出字符串
int Format(const char *fmt, ...);//格式化輸入字符串
private:
int m_ntype;//儲存數據類型
void* m_data;//儲存數據對象
int m_ndataSize;//數據對象的大小 字節爲單位
void* m_Condata;//儲存輸出字符串地址
int m_nCondataSize;//字符串內存大小
};
inline void* Testauto::InClassObj(const void* obj,int nlen)/* 這個用來代替模版,可以儲存自己寫的類對象 */
{
int nLen = nlen;
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
memcpy(m_data,obj,nLen);
m_ntype = type_obj;
return m_data;
}
inline void* Testauto::operator = (const void* obj)/* */
{
int nLen = sizeof(static_cast<const char*>(obj));
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
memcpy(m_data,obj,nLen);
char* data = (char*)obj;
m_data = data;
return m_data;
}
inline char Testauto::operator = (const char & obj)
{
//definetype(char,m_data);
int nLen = sizeof(char);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<char*>(m_data) = obj;
m_ntype = type_int8;
return *static_cast<char*>(m_data);
}
inline unsigned char Testauto::operator = (const unsigned char & obj)
{
//definetype(char,m_data);
int nLen = sizeof(unsigned char);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<unsigned char*>(m_data) = obj;
m_ntype = type_uint8;
return *static_cast<unsigned char*>(m_data);
}
inline short Testauto::operator = (const short & obj)
{
int nLen = sizeof(short);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<short*>(m_data) = obj;
m_ntype = type_int16;
return *static_cast<short*>(m_data);
}
inline unsigned short Testauto::operator = (const unsigned short & obj)
{
//definetype(char,m_data);
int nLen = sizeof(unsigned short);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<unsigned short*>(m_data) = obj;
m_ntype = type_uint16;
return *static_cast<unsigned short*>(m_data);
}
inline int Testauto::operator = (const int & obj)
{
//definetype(char,m_data);
int nLen = sizeof(int);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<int*>(m_data) = obj;
m_ntype = type_int32;
return *static_cast<int*>(m_data);
}
inline unsigned int Testauto::operator = (const unsigned int & obj)
{
//definetype(char,m_data);
int nLen = sizeof(unsigned int);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<unsigned int*>(m_data) = obj;
m_ntype = type_uint32;
return *static_cast<unsigned int*>(m_data);
}
inline long long Testauto::operator = (const long long & obj)
{
//definetype(char,m_data);
int nLen = sizeof(long long);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<long long*>(m_data) = obj;
m_ntype = type_int64;
return *static_cast<long long*>(m_data);
}
inline unsigned long long Testauto::operator = (const unsigned long long & obj)
{
//definetype(char,m_data);
int nLen = sizeof(unsigned long long);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
*static_cast<unsigned long long*>(m_data) = obj;
m_ntype = type_uint64;
return *static_cast<unsigned long long*>(m_data);
}
inline char* Testauto::operator = (const char* obj)
{
int nLen = strlen(obj);
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = nLen;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != nLen)
{
m_ndataSize = nLen;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
for (int i = 0;i < m_ndataSize;i++)
{
*(static_cast<char*>(m_data) + i) = *obj++;
}
m_ntype = type_string;
return static_cast<char*>(m_data);
}
inline void* Testauto::GetData(int type)
{
unsigned long long nMax;
long long nMin;
long long nLen;
long long nData;
int len;
if (0 != m_data && 0 != m_ndataSize)
{
len = strlen(static_cast<char*>(m_data));
switch (type)
{
case type_int16:
{
nMax = 32767;
nMin = -32768;
nLen = 5;
len = len > sizeof(short) ? len : sizeof(short);
break;
}
case type_uint16:
{
nMax = 65535;
nMin = 0;
nLen = 5;
len = len > sizeof(unsigned short) ? len : sizeof(unsigned short);
break;
}
case type_int32:
{
nMax = 2147483647;
nMin = -2147483647 - 1;
nLen = 10;
len = len > sizeof(int) ? len : sizeof(int);
break;
}
case type_uint32:
{
nMax = 4294967296;
nMin = 0;
nLen = 10;
len = len > sizeof(unsigned int) ? len : sizeof(unsigned int);
break;
}
case type_int64:
{
nMax = 9223372036854775807;
nMin = -9223372036854775808;
nLen = 19;
len = len > sizeof(long long) ? len : sizeof(long long);
break;
}
case type_uint64:
{
nMax = 18446744073709551615;
nMin = 0;
nLen = 20;
len = len > sizeof(unsigned long long) ? len : sizeof(unsigned long long);
break;
}
default:
{
nMax = 9223372036854775807;
nMin = -9223372036854775808;
nLen = 19;
len = len > sizeof(long long) ? len : sizeof(long long);
break;
}
}
switch (m_ntype)
{
case type_string:
{
if (0 == m_Condata)
{
m_Condata = ::operator new(len);
m_nCondataSize = len;
}
else if (m_nCondataSize != len)
{
delete[] m_Condata;
m_Condata = ::operator new(len);
m_nCondataSize = len;
}
memset(m_Condata,0,len);
memcpy(m_Condata,m_data,len);
if (nLen <= len && -1 < _atoi64(static_cast<char*>(m_Condata)))
{
memcpy(m_Condata,m_data,nLen);
if (nMax < _atoi64(static_cast<char*>(m_Condata)))
{
memset(m_Condata,0,len);
memcpy(m_Condata,m_data,nLen - 1);
nData = _atoi64(static_cast<char*>(m_Condata));
}
else
{
nData = _atoi64(static_cast<char*>(m_Condata));
}
}
else if (nLen <= len && nMin > _atoi64(static_cast<char*>(m_Condata)) && 0 != nMin)
{
memset(m_Condata,0,len);
memcpy(m_Condata,m_data,nLen + 1);
nData = _atoi64(static_cast<char*>(m_Condata));
}
else if (nMin > _atoi64(static_cast<char*>(m_Condata)) && 0 == nMin)
{
nData = 0;
}
else
{
memcpy(m_Condata,m_data,len);
nData = _atoi64(static_cast<char*>(m_Condata));
}
}
break;
default:
long long nRem;
switch (m_ntype)
{
case type_int8:
nRem = *static_cast<char*>(m_data);
break;
case type_uint8:
nRem = *static_cast<unsigned char*>(m_data);
break;
case type_int16:
nRem = *static_cast<short*>(m_data);
break;
case type_uint16:
nRem = *static_cast<unsigned short*>(m_data);
break;
case type_int32:
nRem = *static_cast<int*>(m_data);
break;
case type_uint32:
nRem = *static_cast<unsigned int*>(m_data);
break;
case type_int64:
nRem = *static_cast<long long*>(m_data);
break;
case type_uint64:
nRem = *static_cast<unsigned long long*>(m_data);
break;
default:
nRem = *static_cast<long long*>(m_data);
break;
}
if (0 == nMin && nMin > nRem)
{
nData = 0;
}
else if (nMin > nRem)
{
while (nMin > nRem)
{
nRem /= 10;
}
nData = nRem;
}
else if (nRem > nMax && 0 < nRem)
{
while (nRem > nMax&& 0 < nRem)
{
nRem /= 10;
}
nData = nRem;
}
else
{
nData = nRem;
}
break;
}
return static_cast<void*>(&nData);
}
return NULL;
}
inline char* Testauto::Outstring()
{
if (0 != m_data && 0 != m_ndataSize)
{
if (0 == m_Condata)
{
m_Condata = ::operator new(m_ndataSize * 3);
m_nCondataSize = m_ndataSize * 3;
}
else if (m_nCondataSize != m_ndataSize * 3)
{
delete[] m_Condata;
m_Condata = ::operator new(m_ndataSize * 3);
m_nCondataSize = m_ndataSize * 3;
}
memset(m_Condata,0,m_nCondataSize);
switch (m_ntype)
{
case type_int8:
ltoa(*static_cast<char*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_uint8:
ltoa(*static_cast<unsigned char*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_int16:
ltoa(*static_cast<short*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_uint16:
ltoa(*static_cast<unsigned short*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_int32:
ltoa(*static_cast<int*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_uint32:
ltoa(*static_cast<unsigned int*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_int64:
_i64toa(*static_cast<long long*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_uint64:
_i64toa(*static_cast<unsigned long long*>(m_data),static_cast<char*>(m_Condata),10);
break;
case type_string:
memcpy(m_Condata,m_data,m_ndataSize);
break;
default:
memcpy(m_Condata,m_data,m_ndataSize);
break;
}
return static_cast<char*>(m_Condata);
}
return NULL;
}
inline int Testauto::Format(const char *fmt, ...)
{
va_list args;
int i;
char buf[10240 * 100] = {0};/* 最大可以輸入1M字節 */
va_start(args, fmt);
i = vsprintf(buf, fmt, args);
va_end(args);
int len = strlen(buf);
if (0 >= len)
{
return -1;
}
if (0 == m_data && 0 == m_ndataSize)
{
m_ndataSize = len;
m_data = ::operator new(m_ndataSize);
}
else if (m_ndataSize != len)
{
m_ndataSize = len;
delete[] m_data;
m_data = ::operator new(m_ndataSize);
}
memcpy(m_data,buf,len);
m_ntype = type_string;
return i;
}
class Test1//這個是自定義參考類
{
public:
Test1():nNum(0),nData(0)
{
}
int nNum;
int nData;
};
下面貼上參考使用方法:
Testauto testte;//類結構對象
Test1 testtest12;//自定義參考類對象
testtest12.nNum = 1;
testtest12.nData = 2;
WriteType(testte,&testtest12,Test1);//傳入Test1類對象
Test1 testtest123 = *static_cast<Test1*>(testte.GetObj());//可以採用靜態方式輸出類對象
Test1 testtest123 = *(Test1*)testte.GetObj();//也可以強制轉換方式輸出類對象
((Test1*)testte.GetObj())->nNum = 5;//可以直接修改儲存的類對象變量
testte = /*(char*)*/"-1234567890";//傳入字符串
short testchar1234 = testte.OutShort();//以short輸出數字範圍在32767 ~ -32768之間 ,這裏是-12345
int testchar123412 = testte.OutInt();//以int輸出數字範圍在2147483647 ~ -2147483648之間,這裏是-1234567890
char* testchar12345 = testte.Outstring();//這裏以字符串形式輸出"-1234567890"
testte.Format("%s%d!","123",456);//仿CString形式格式化輸入字符串
testchar12345 = testte.Outstring();//輸出"123456!"
*testchar12345 = '9';//修改後爲"923456!"
testchar12345 = testte.Outstring();//再次輸出"123456!"
這裏演示了其中一部分方法,在enum定義中的類型都可以任意轉換,如果哪位朋友有興趣浮點數可以自行添加測試,或者提下建議~~~謝謝!
源代碼地址:http://download.csdn.net/detail/a29562268/9844092!