auto形式(更多功能)类结构实现

  最近思来索去~一直都是写模板做数据结构还没有真正意义上的可以储存任意数据类型的结构,使用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!

发布了94 篇原创文章 · 获赞 206 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/a29562268/article/details/72340838