WTL 简单的模板类数组研究

    实际上这里谈到的类是ATL里面的类,位于头文件: atlsimpcoll.h

            如果你去探寻,就会发现WTL实际上就是ATL,只不过它扩展了ATL的界面功能。WTL当然有许多自己的东西,但那是另外的问题了。

           

template <class T, class TEqual = CSimpleArrayEqualHelper< T > >
class CSimpleArray
{
public:
// Construction/destruction
	CSimpleArray() :
		m_aT(NULL), m_nSize(0), m_nAllocSize(0)
	{
	}

	~CSimpleArray();

	CSimpleArray(_In_ const CSimpleArray< T, TEqual >& src) :
		m_aT(NULL), m_nSize(0), m_nAllocSize(0)
	{
        if (src.GetSize())
        {
			m_aT = (T*)calloc(src.GetSize(), sizeof(T));
			if (m_aT != NULL)
			{
				m_nAllocSize = src.GetSize();
				for (int i=0; i<src.GetSize(); i++)
					Add(src[i]);
			}
		}
	}
	CSimpleArray< T, TEqual >& operator=(_In_ const CSimpleArray< T, TEqual >& src)
	{
		if (GetSize() != src.GetSize())
		{
			RemoveAll();
			m_aT = (T*)calloc(src.GetSize(), sizeof(T));
			if (m_aT != NULL)
				m_nAllocSize = src.GetSize();
		}
		else
		{
			for (int i = GetSize(); i > 0; i--)
				RemoveAt(i - 1);
		}
		for (int i=0; i<src.GetSize(); i++)
			Add(src[i]);
		return *this;
	}

// Operations
	int GetSize() const
	{
		return m_nSize;
	}
	BOOL Add(_In_ const T& t)
	{
		if(m_nSize == m_nAllocSize)
		{
			// Make sure newElement is not a reference to an element in the array.
			// Or else, it will be invalidated by the reallocation.
			ATLENSURE(	(&t < m_aT) ||
						(&t >= (m_aT + m_nAllocSize) ) );

			T* aT;
			int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2);

			if (nNewAllocSize<0||nNewAllocSize>INT_MAX/sizeof(T))
			{
				return FALSE;
			}

			aT = (T*)_recalloc(m_aT, nNewAllocSize, sizeof(T));
			if(aT == NULL)
				return FALSE;
			m_nAllocSize = nNewAllocSize;
			m_aT = aT;
		}
		InternalSetAtIndex(m_nSize, t);
		m_nSize++;
		return TRUE;
	}
	BOOL Remove(_In_ const T& t)
	{
		int nIndex = Find(t);
		if(nIndex == -1)
			return FALSE;
		return RemoveAt(nIndex);
	}
	BOOL RemoveAt(_In_ int nIndex)
	{
		ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
		if (nIndex < 0 || nIndex >= m_nSize)
			return FALSE;
		m_aT[nIndex].~T();
		if(nIndex != (m_nSize - 1))
			Checked::memmove_s((void*)(m_aT + nIndex), (m_nSize - nIndex) * sizeof(T), (void*)(m_aT + nIndex + 1), (m_nSize - (nIndex + 1)) * sizeof(T));
		m_nSize--;
		return TRUE;
	}
	void RemoveAll()
	{
		if(m_aT != NULL)
		{
			for(int i = 0; i < m_nSize; i++)
				m_aT[i].~T();
			free(m_aT);
			m_aT = NULL;
		}
		m_nSize = 0;
		m_nAllocSize = 0;
    }
	const T& operator[] (_In_ int nIndex) const
	{
		ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
		if(nIndex < 0 || nIndex >= m_nSize)
		{
			_AtlRaiseException((DWORD)EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
		}
		return m_aT[nIndex];
	}
	T& operator[] (_In_ int nIndex)
	{
		ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
		if(nIndex < 0 || nIndex >= m_nSize)
		{
			_AtlRaiseException((DWORD)EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
		}
		return m_aT[nIndex];
	}
	T* GetData() const
	{
		return m_aT;
	}

	int Find(_In_ const T& t) const
	{
		for(int i = 0; i < m_nSize; i++)
		{
			if(TEqual::IsEqual(m_aT[i], t))
				return i;
		}
		return -1;  // not found
	}

	BOOL SetAtIndex(
		_In_ int nIndex,
		_In_ const T& t)
	{
		if (nIndex < 0 || nIndex >= m_nSize)
			return FALSE;
		InternalSetAtIndex(nIndex, t);
		return TRUE;
	}

// Implementation
	class Wrapper
	{
	public:
		Wrapper(_In_ const T& _t) : t(_t)
		{
		}
		template <class _Ty>
		void * __cdecl operator new(
			_In_ size_t,
			_In_ _Ty* p)
		{
			return p;
		}
		template <class _Ty>
		void __cdecl operator delete(
			_In_ void* /* pv */,
			_In_ _Ty* /* p */)
		{
		}
		T t;
	};

// Implementation
	void InternalSetAtIndex(
		_In_ int nIndex,
		_In_ const T& t)
	{
		new(m_aT + nIndex) Wrapper(t);
	}

	typedef T _ArrayElementType;
	T* m_aT;
	int m_nSize;
	int m_nAllocSize;
};

#define CSimpleValArray CSimpleArray

template <class T, class TEqual> inline CSimpleArray<T, TEqual>::~CSimpleArray()
{
	RemoveAll();
}

          以上就是我们所要说的CSimpleArray类 的主要代码。我之所以把这个类作为典范,是因为它足够简单,而且充分展现了模板类的魅力。你可以从它的代码里学习C++的模板类语法,同时你还可以学习模板成员变量以及模板函数的写法儿。实际上我经常在我的程序里使用这个类,如果是简单的结构或者简单类型(int,long,float,double,char,byte)的数组,我几乎第一个想到的就是这个集合类,它们工作的很好,从没有让我失望。

          下面是一个示例:

		struct TestStru
		{
			int m_order;
			TCHAR m_name[25];
		};
		CSimpleArray<TestStru> testAry;
		TestStru ts;

		ts.m_order = 1;
		lstrcpy( ts.m_name, _T("测试A"));
		testAry.Add(ts);

		ts.m_order = 2;
		lstrcpy( ts.m_name, _T("测试B"));
		testAry.Add(ts);

		ts.m_order = 3;
		lstrcpy( ts.m_name, _T("测试C"));
		testAry.Add(ts);

          你这么使用时没有问题的,这个TestStru换做其他类型,比如FLOAT, 工作的只会更好。CSimpleArray 类在我们已知数组大小的情况下效率有些欠缺。因为它缺少一个一次性初始化数组内存的函数。但如果你不能确定数组大小,那么它很合适,而且效率不低。


         CSimpleArray类,你可以复制一个数组, 你还可以删除指定位置的数组项,或者用下标方式给数组的项赋新值。

  

		CSimpleArray<TestStru> copyAry(testAry); 

		ts.m_order = 3;
		lstrcpy( ts.m_name, _T("将被删除"));
		testAry[2] = ts;
		testAry.RemoveAt(2); 

           你还可以查找一个项,或者删除一个指定的项。当然这涉及到判断相等的操作,这需要一点前提。 对于int,float类型,编译器知道他们的相等操作,如果是你自己定义的结构,那么编译器是不知道的。

CSimpleArray 类好就好在,如果你没有用到这个操作, 前面讲的就够了,编译器也不会报错。如果你用到了相等操作,比如查找,比如删除。那么编译器会要求你为你的结构提供==操作符。

		int nFind = testAry.Find(ts);
		testAry.Remove(ts);

             增加上面两行代码编译器会报错。提示没有 == 操作符,所以我们修改TestStruct 的代码,添加自定义操作符 == ,如下:

 

struct TestStru
{
	int m_order;
	TCHAR m_name[25];

    bool operator ==(const struct TestStru &t) const
    {
        return (lstrcmp(this->m_name, t.m_name ) == 0);
    }
};
            这么一来,编译可以通过了。如果两个结构的m_name字段的文本相同,就认为他们相等。

            到这里这个CSimpleArray类就介绍完了。需要补充一点的就是, CSimpleArray类 也可以处理指针,你可以把任何一个类的指针作为模板类, 建立数组。例如:

             CSimpleArray<TestStru*> ptrArray; 这样用也没有问题,这里是指针的话,那么最后就涉及指针的申请和释放问题,处理好也没什么问题。


最后一点,额外啰嗦一下,下面这个包装类:

	template <typename T>
	class Wrapper
	{
	public:
		Wrapper(_In_ const T& _t) : t(_t)
		{
		}
		template <class _Ty>
		void *operator new(
			_In_ size_t,
			_In_ _Ty* p)
		{
			return p;
		}
		template <class _Ty>
		void operator delete(
			_In_ void* /* pv */,
			_In_ _Ty* /* p */)
		{
		}
		T t;
	};

如果没有任何解释就可以看懂这个类的作用的,那么你的C++水平应该不低了。这个类使用的非常巧妙。它实际上是解决T类型的赋值和构造函数调用问题。改写了new操作符,它只是返回了输入参数的指针位置,并没有真的申请内存, 编辑器看到这个返回指针,就会在这个基础上调用Wrapper的构造函数,于是完成了初始化。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值