参考:
http://www.cnblogs.com/clingingboy/archive/2011/06/15/2081786.html
一.概念
如同标准库一般,也有容器(即集合类)和迭代器
void main() {
// Populate the collection vector<long> rgPrimes;
for (long n = 0; n != 1000; ++n) {
if (IsPrime(n)) rgPrimes.push_back(n);
}
// Count the number of items in the collection cout << "Primes: " << rgPrimes.size() << endl;
// Iterate over the collection using sequential access vector<long>::iterator begin = rgPrimes.begin();
vector<long>::iterator end = rgPrimes.end();
for (vector<long>::iterator it = begin; it != end; ++it) {
cout << *it << " ";
}
cout << endl;
}
二.COM中集合和枚举器的替代品
ICollection提供基本的2个方法
Count取得元素数量,Item通过索引获取一个元素.
除此之外_NewEnum将获取一个与集合相关的枚举器.引用一段话
通过ICollection操纵数组大体上有两种方法。一种是通过Item属性用数组下标取得元素。这种方式,每次只能取得一个元素,而且要传递下标对象,所以效率比较低下。另一种方法是通过枚举器。数组对象的枚举器通过_NewEnum属性取得。通过枚举器只能按顺序获取元素,但每次可以取得任意多的元素,所以效率较高。ICollection对象可以只实现其中的一种访问方法,也可以两种都实现。ICollection中还有一个重要属性:Count。Count属性返回数组的长度,对于无法确定长度的数组,也可以不实现Count属性。
[ object, dual ]
template <typename T>
interface ICollection : IDispatch {
[propget]
HRESULT Count([out, retval] long* pnCount);
[id(DISPID_VALUE), propget]
HRESULT Item([in] long n, [out, retval] T* pnItem);
[id(DISPID_NEWENUM), propget]
HRESULT _NewEnum([out, retval] IUnknown** ppEnum);
};
template <typename T>
interface IEnum : IUnknown {
[local]
HRESULT Next([in] ULONG celt,
[out] T* rgelt,
[out] ULONG *pceltFetched);
[call_as(Next)] // Discussed later... HRESULT RemoteNext([in] ULONG celt,
[out, size_is(celt),
length_is(*pceltFetched)] T* rgelt,
[out] ULONG *pceltFetched);
HRESULT Skip([in] ULONG celt);
HRESULT Reset();
HRESULT Clone([out] IEnum<T> **ppenum);
}
三.集合和枚举器的使用方法
通过一个例子来了解集合和枚举器的使用方法
自定义集合和枚举器接口(暂时不关注实现)
[dual]
interface IPrimeNumbers : IDispatch {
HRESULT CalcPrimes([in] long min, [in] long max);
[propget]
HRESULT Count([out, retval] long* pnCount);
[propget, id(DISPID_VALUE)]
HRESULT Item([in] long n, [out, retval] long* pnPrime);
[propget, id(DISPID_NEWENUM)] // Not quite right... HRESULT _NewEnum([out, retval] IEnumPrimes** ppEnumPrimes);
};
interface IEnumPrimes : IUnknown {
[local]
HRESULT Next([in] ULONG celt,
[out] long* rgelt,
[out] ULONG *pceltFetched);
[call_as(Next)]
HRESULT RemoteNext([in] ULONG celt,
[out, size_is(celt),
length_is(*pceltFetched)] long* rgelt,
[out] ULONG *pceltFetched);
HRESULT Skip([in] ULONG celt);
HRESULT Reset();
HRESULT Clone([out] IEnumPrimes **ppenum);
};
调用示例
void main() {
CoInitialize(0);
CComPtr<IPrimeNumbers> spPrimes;
if (SUCCEEDED(spPrimes.CoCreateInstance(CLSID_PrimeNumbers))) {
// Populate the collection HRESULT hr = spPrimes->CalcPrimes(0, 1000);
// Count the number of items in the collection long nPrimes;
hr = spPrimes->get_Count(&nPrimes);
cout << "Primes: " << nPrimes << endl;
// Enumerate over the collection using sequential access CComPtr<IEnumPrimes> spEnum;
hr = spPrimes->get__NewEnum(&spEnum);
const size_t PRIMES_CHUNK = 64;
long rgnPrimes[PRIMES_CHUNK];
do {
ULONG celtFetched;
hr = spEnum->Next(PRIMES_CHUNK, rgnPrimes, &celtFetched);
if (SUCCEEDED(hr)) {
if (hr == S_OK) celtFetched = PRIMES_CHUNK;
for (long* pn = &rgnPrimes[0];
pn != &rgnPrimes[celtFetched]; ++pn) {
cout << *pn << " ";
}
}
}
while (hr == S_OK);
cout << endl;
spPrimes.Release();
}
CoUninitialize();
}
关注Next方法
HRESULT Next([in] ULONG celt,
[out] long* rgelt,
[out] ULONG *pceltFetched);
celt表示要取的元素个数,rgelt用于存储取到的数据指针,pceltFetched表示实际取到的元素个数
理解这个方式非常关键,由于rgelt存储的指针是外部存储,那么Next方法内部就需要一个的策略来填充这个外部数据的指针,这就从而引出了拷贝策略这个话题,这个到后面实现的时候提到