小探ATL的集合和迭代器

小探ATL的集合和迭代器

ATL的集合和迭代器为什么会存在,我现在也没有像明白,但是可以肯定的是它的存在自有它的理由,
可能我搞这个的日子尚浅还不明白其中的玄机罢了。

相比STL的迭代器,ATL在外面没有什么大的变换,不过里面可是翻江倒海的变化了,

为了那么几个什么next ,reset...简单的接口,它可是花了老劲了

ATL迭代器一般都要支持一个IEnmXXX接口,不过也就是要实现四个方法:Next,Skip,Reset,Clone

就为了这个东西ATL的作者没少花功夫,大量的运用策略模式

CComEnum我们暂且不提了,ATL自己可能都觉得它不能满足现在的用户,它基本上是为支持数组而存在的
但现在喜欢用数组的还有几个,那么多还用的STL数据结构不用事傻子

现在基本都用CComEnumOnSTL,这个东西很是麻烦,6个模板参数,6种策略(号称)

实现了一大堆的东西,说是灵活了其实很复杂。

不过主要是用它来为你自己维护的一个数据集合产生一个迭代器,从而让用户方便的使用你的数据是它的
最终目的。因而你就只需要产生一个这样的迭代器就可以了。

实现的步骤如下:
1、  确定哪个STL容器是需要枚举的

2、  在客户端需要枚举器接口的时候选用适当的模板参数,typedef出一个特定的枚举器对象

3、  CComObject< >::CreateInstance()产生枚举器实例

4、  对产生的枚举器实例调用Init()方法

5、  返回指针和结果信息给客户

假设你需要将你对象中的一个vector<CComVariant>的集合通过这个迭代器暴露给用户,那么
就这么定义。
typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
                          _Copy<VARIANT>, std::vector<CComVariant> > VarVarEnum;

这个类就是这样的,
产生它的实例也容易
就这样:
         CComObject<VarVarEnum;>* pEnum = NULL;

         HRESULT hr = CComObject<VarVarEnum;>::CreateInstance(&pEnum);

         if (FAILED(hr))

              return hr;

         hr = pEnum->Init(pUnkForRelease, collection);

         if (SUCCEEDED(hr))

              hr = pEnum->QueryInterface(ppUnk);

         if (FAILED(hr))

              delete pEnum;

pUnkForRelease 是你包含数据的对象指针,就是你最终给用户的类
collection     是你包含的数据指针, 就是你最终给用户的类一个真正的数据成员
而产生的这个迭代实例就是你最终给用户的类产生的一个对象,这个对象可以访问你的类中的这个数据成员

这样看起来,数据和迭代器是完全不相关的两个东西,看来它这么写和要充分的解耦合有关系

为了很好的创建它,你最好是写个函数
template <class EnumType, class CollType>

     HRESULT CreateSTLEnumerator(IUnknown** ppUnk, IUnknown* pUnkForRelease, CollType& collection)

     {

         if (ppUnk == NULL)

              return E_POINTER;

         *ppUnk = NULL;

         CComObject<EnumType>* pEnum = NULL;

         HRESULT hr = CComObject<EnumType>::CreateInstance(&pEnum);

         if (FAILED(hr))

              return hr;

         hr = pEnum->Init(pUnkForRelease, collection);

         if (SUCCEEDED(hr))

              hr = pEnum->QueryInterface(ppUnk);

         if (FAILED(hr))

              delete pEnum;

         return hr;

     }

这个msdn的例子里面的东西,就是用来写这个的

你可以这么用

 typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,

                          _Copy<VARIANT>, std::vector<CComVariant> > VarVarEnum;

         std::vector<CComVariant> m_vec;

         STDMETHOD(get__NewEnum)(IUnknown** ppUnk)

         {

              return CreateSTLEnumerator<VarVarEnum>(ppUnk, this, m_vec);

     }

忘了说了一般你提供给用户的类都是通过(get__NewEnum)来提供一个迭代器的,这个迭代器是用来访问类中的数据的。不过通过上面的分析
你一定要记住,这个返回的接口不是类的接口,而是另外一个对象的接口。

这个东西基本讲清楚了。

下面说说集合,

集合可能就是ATL觉得用户自己写这个集合不太放心,因为本来就比较麻烦,不如就帮我们写了

ATL中有个叫做ICollectionOnSTLIml的类帮我们搞定了这一切麻烦的事情。
看看吧
STDMETHOD(get_Count)(long* pcount)
 {
  if (pcount == NULL)
   return E_POINTER;
  ATLASSUME(m_coll.size()<=LONG_MAX);

  *pcount = (long)m_coll.size();

  return S_OK;
 }
 STDMETHOD(get_Item)(long Index, ItemType* pvar)
 {
  //Index is 1-based
  if (pvar == NULL)
   return E_POINTER;
  if (Index < 1)
   return E_INVALIDARG;
  HRESULT hr = E_FAIL;
  Index--;
  CollType::const_iterator iter = m_coll.begin();
  while (iter != m_coll.end() && Index > 0)
  {
   iter++;
   Index--;
  }
  if (iter != m_coll.end())
   hr = CopyItem::copy(pvar, &*iter);
  return hr;
 }
 STDMETHOD(get__NewEnum)(IUnknown** ppUnk)
 {
  if (ppUnk == NULL)
   return E_POINTER;
  *ppUnk = NULL;
  HRESULT hRes = S_OK;
  CComObject<EnumType>* p;
  hRes = CComObject<EnumType>::CreateInstance(&p);
  if (SUCCEEDED(hRes))
  {
   hRes = p->Init(this, m_coll);
   if (hRes == S_OK)
    hRes = p->QueryInterface(__uuidof(IUnknown), (void**)ppUnk);
  }
  if (hRes != S_OK)
   delete p;
  return hRes;
 }
 CollType m_coll;

我们要实现的类的数据部分基本就要这么写的,继承它就写了,岂不是很轻松,不过它真正的数据成员是m_coll,上面
写的并没有对它进行初始化,所以在我们实现的类的初始化中一定要初始化这个类。

至于怎么用它,ATL的书里面应该是都有介绍吧,基本就是写好那些复杂的模板参数参数,同时如果希望生成和数据不同类型的
迭代器也是有办法的,你只需要写个带转换的copy函数就可以了,这个都可以通过模板参数来变化的。这个就是将数据和迭代器
分离的好处。

至于CAdapt就是简单的封装,目的是为了对付&操作符直接将ATL智能类型直接将内部数据指针直接暴露的问题,一般就是这样子,
没有什么玄机,不信自己看就知道了,很简单的

template <class T>
class CAdapt
{
public:
 CAdapt()
 {
 }
 CAdapt(__in const T& rSrc) :
  m_T( rSrc )
 {
 }

 CAdapt(__in const CAdapt& rSrCA) :
  m_T( rSrCA.m_T )
 {
 }

 CAdapt& operator=(__in const T& rSrc)
 {
  m_T = rSrc;
  return *this;
 }
 bool operator<(__in const T& rSrc) const
 {
  return m_T < rSrc;
 }
 bool operator==(__in const T& rSrc) const
 {
  return m_T == rSrc;
 }
 operator T&()
 {
  return m_T;
 }

 operator const T&() const
 {
  return m_T;
 }

 T m_T;
};

就是没有&操作符而已,希望能够直接将智能类型指针传入集合中而产生的一个东西。

同时不要小看了ATL 它同样也有CAtlArray CAtlList CAtlMap,不一定非要用STL.

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值