ATL中的集合和列舉

2021-03-31 08:56:59 字數 4474 閱讀 3532

cool - ** ( 2004-11-22 11:55:00 )

類別:vc/mfc

***中集合和列舉器的關係非常類似於stl中的容器和迭代器的關係。

列舉器

如果乙個***物件可以被稱為乙個「集合」,那麼很顯然,該物件內部肯定是一些型別相同的資料的集合,當我們要將內部這些資料「暴露」給客戶端使用時,如果直接照搬stl的模式,提供乙個iterator型別,那麼會造成伺服器端的資料封裝得太弱,資料易被客戶端破壞。鑑於此,***提供了列舉器供客戶使用——客戶通過集合的介面,取得列舉器的介面,使用列舉器訪問資料;除開列舉器介面以外,一般的集合物件還要提供get__item方法暴露自身資料。

假設icollection介面支援列舉器ienumsth,那麼通過如下**得到列舉器介面,列舉內部元素:

hresult hres ;

ienumsth psth ;

hres = icollection->get__newenum( (iunknown**) &psth ) ;

我們的程式中並沒有提供ienumsth的宣告,***規定了,凡是ienum***型別的介面,都需要用有如下四個方法:next,skip,reset,clone。很明顯,get__newenum()方法的作用就是構造出乙個物件(下面稱其為列舉器物件),該物件實現了上面所列的4個方法,然後將該物件的介面指標返回給客戶端即可。

atl提供了乙個列舉器物件的通用實現模板,極大的方便了我們的工作。該列舉器物件模板的設計思想是「基於策略」的,讓我們首先來看看要實現該模板,需要有哪些策略:

1、 列舉器介面的名字——也就是上面例子中的ienumsth

2、 列舉器介面的iid——也就是__uuidof(ienumsth)

3、 被列舉的資料的型別——也就是上面例子中的sth(可以是variant,bstr等)

4、 複製策略——這個策略最複雜,它完成的功能是將「集合」物件內部的資料copy到客戶提供的緩衝區的功能

5、 資料存放形式——「集合」物件內資料存放的資料結構(陣列、stl容器等)

6、 執行緒模型

atl提供的模板類其宣告如下:

template

class atl_no_vtable c***enumonstl

該類正好具有6個模板引數,其每個引數與上面所列的相應的策略對應,因此,應用該類前,先仔細考慮這6個模板引數的值,然後將其組合起來,即可得到自己所需要的列舉器物件——與atl中其他的物件一樣,該物件也需要用c***object< >::createinstance的形式來建立其實例,而非直接new c***object< >。

nb:對於以上6個模板引數,一般而言iid = __uuidof(name)這個等式是成立的,所以真正正交的策略類不過5個而已。不過由於__uuidof運算子是visual c++編譯器對標準c++的擴充套件,所以atl並沒有在此處省略掉iid這個策略類。不過在atl的其他很多地方,都有對於__uuidof運算子的使用——在***的世界裡,拋開ms是不可能的…………。

使用c***enumonstl的步驟如下:

1、 確定哪個stl容器是需要列舉的

2、 在客戶端需要列舉器介面的時候選用適當的模板引數,typedef出乙個特定的列舉器物件

3、 c***object< >::createinstance()產生列舉器例項

4、 對產生的列舉器例項呼叫init()方法

5、 返回指標和結果資訊給客戶

整個過程說簡單也不算簡單,特別是一些步驟很容易被遺忘,atl開發小組在隨msdn提供的atl sample中,提供了乙個名為:atlcollections的工程,該工程內有乙個名為reuse的資料夾,其中的3個檔案其**都是具有很強的復用性的,在vcue_collection.h檔案中,atl開發小組給我們提供了createstlenumerator()函式,封裝了整個列舉器物件的建立過程,該函式是這樣的:

template

hresult createstlenumerator(iunknown** ppunk, iunknown* punkforrelease, colltype& collection)

createstlenumerator()函式封裝了建立c***enumonstl樣式的列舉器所必需的初始化和錯誤處理**,我們可以這樣使用該函式來完成get__newenum()方法:

typedef c***enumonstl, std::vector> varvarenum;

std::vectorm_vec;

stdmethod(get__newenum)(iunknown** ppunk)

整個get__newenum就一條語句:

return createstlenumerator(ppunk, this, m_vec);

顯得乾淨利落。

讓我們來看乙個例子:

該例子的功能很簡單,我們的***元件內部有乙個std::vector,我需要將該vector內的資料以列舉器的形式暴露給客戶端。該例子的實作步驟如下(程式設計環境為vs2002,也就是vc7+atl7):

1、 建立乙個新的名為atlenum1的解決方案,在其下新增乙個新的型別為atl專案名為atlenum1的專案,在專案屬性設定中,取消其「屬性化」選擇,勾上「允許合併proxy/stub**的核取方塊,點完成建立專案。

2、 切換到「類檢視」,按照如下所示給該工程新增乙個模板為atl簡單物件名為atlenum的類:

圖 atlenum-01

圖 atlenum-02

vc對於新增的類的預設屬性設定是支援雙介面的,我們將其改為自定義介面,免去idispatch介面實現的諸多麻煩。

3、 我們假設vector是全域性性的,並且在atlenum類的建構函式中被初始化。開啟atlenum.h檔案,新增標頭檔案包含:

#include

新增vector宣告:

std::vectortest_vec ;

改寫catlenum建構函式如下:

catlenum()

}使得catlenum在構造時可以初始化vector。

4、 按照下圖說明給catlenum新增乙個名為getenum()的方法,用來向客戶端提供列舉器:

圖 atlenum-03

圖 atlenum-04

5、 從msdn附帶的atl sample中找到atlcollections工程,copy其中的reuse資料夾到我們的atlenum1工程的資料夾中。開啟atlenum.cpp,新增包含檔案:

#include "../reuse/vcue_collection.h"

列出文章最開始所列出的策略類:

typedef std::vector< variant > containertype;

typedef variant exposedtype;

typedef ienumvariant enumeratorinte***ce;

typedef _copycopytype;

根據以上的策略類,定義出列舉器物件:

typedef

c***enumonstl< enumeratorinte***ce, &__uuidof(enumeratorinte***ce), 

exposedtype,copytype, containertype > 

enumeratortype;

此處typedef出來的enumeratortype就是我們所需要的列舉器類。

改寫getenum()方法的**如下:

stdmethodimp catlenum::getenum(iunknown** ppunk)

6、 整個伺服器的編碼工作已經完成了!我們只是簡單的寫了5個typedef語句,然後呼叫了atl小組提供的乙個函式,就完成了我們所需要的提供列舉器的功能。

client測試

server端編碼完成,下面我們編寫乙個client端的程式對寫好的server進行測試。

出於簡單起見,該client端**並沒有實現過多的功能,僅僅是取得了列舉器的介面,並測試了列舉器的next()方法而已。

整個client端**如下:

#include "stdafx.h"

#include

#import "../atlenum1/debug/atlenum1.dll" no_namespace

static const ulong nbatchsize = 5 ;

int main()

;penumvar->next(nbatchsize, &arrvar[0], &nreturned) ;

penumvar->release() ;

patlenum->release() ;

couninitialize();

return 0;

}執行完penumvar->next(nbatchsize, &arrvar[0], &nreturned) ;這一條語句,可以從除錯視窗看到如下結果:

圖 atlenum - 05

變數nreturned = 2說明該列舉器取回了2個資料,展開arrvar陣列的顯示,可以看到列舉器介面正確地實現了next()方法,將兩個variant資料傳遞給了客戶端**。

mysql 列舉與集合 mysql列舉和集合型別

列舉和集合型別 列舉 enum 型別,最多可以定義 65535 種不同的字串從中做出選擇,只能並且必須選擇其中一種,占用儲存空間是乙個或兩個位元組,由列舉值的數目決定 集合 set 型別,最多可以有 64 個成員,可以選擇其中的零個到不限定的多個,占用儲存空間是乙個到八個位元組,由集合可能的成員數目...

集合的列舉和排序

原文 先來看看ienumerable介面的定義 public inte ce ienumerable 這個介面非常簡單,主要就是乙個方法getenumerator,用來返回乙個ienumerator物件。繼續深入下去,ienumerator介面的定義如下 public inte ce ienumer...

js中的列舉和不可列舉

列舉是指物件中的屬性是否可以遍歷出來,再簡單點說就是屬性是否可以以列舉出來。1.for in迴圈可以列舉 遍歷 出物件本身具有的屬性,通過object.defineproperty 方法加的可列舉屬性,或者通過原型物件繫結的可以列舉屬性。function enumer enumer.prototyp...