Sdílet prostřednictvím


Implementace kolekce založené na standardní knihovně C++

ATL poskytuje ICollectionOnSTLImpl rozhraní, které umožňuje rychle implementovat rozhraní kolekcí založené na standardní knihovně C++ na objekty. Abyste pochopili, jak tato třída funguje, budete pracovat pomocí jednoduchého příkladu (níže), který tuto třídu používá k implementaci kolekce jen pro čtení zaměřené na klienty Automation.

Vzorový kód pochází z ukázky ATLCollections.

Chcete-li provést tento postup, budete:

Generování nového jednoduchého objektu

Vytvořte nový projekt a ujistěte se, že pole Atributy v části Nastavení aplikace je nezaškrtnuto. Pomocí dialogového okna Přidat třídu ATL a Průvodce přidáním jednoduchého objektu vygenerujte jednoduchý objekt s názvem Words. Ujistěte se, že je vygenerováno IWords duální rozhraní. Objekty vygenerované třídy budou použity k reprezentaci kolekce slov (to znamená řetězce).

Úprava souboru IDL

Nyní otevřete soubor IDL a přidejte tři vlastnosti potřebné k převodu IWords na rozhraní kolekce jen pro čtení, jak je znázorněno níže:

[
   object,
   uuid(7B3AC376-509F-4068-87BA-03B73ADC359B),
   dual,                                                    // (1)
   nonextensible,                                           // (2)
   pointer_default(unique)
]
interface IWords : IDispatch
{
   [id(DISPID_NEWENUM), propget]                            // (3)
   HRESULT _NewEnum([out, retval] IUnknown** ppUnk);

   [id(DISPID_VALUE), propget]                              // (4)
   HRESULT Item([in] long Index, [out, retval] BSTR* pVal); // (5)

   [id(0x00000001), propget]                                // (6)
   HRESULT Count([out, retval] long* pVal);

};

Toto je standardní formulář pro rozhraní kolekce jen pro čtení navržené s ohledem na klienty Automation. Očíslované komentáře v této definici rozhraní odpovídají následujícím komentářům:

  1. Rozhraní kolekce jsou obvykle duální, protože klienti Automation přistupují k _NewEnum vlastnosti prostřednictvím IDispatch::Invoke. Klienti Automation ale můžou přistupovat ke zbývajícím metodám prostřednictvím tabulky vtable, takže duální rozhraní jsou vhodnější než dispinterfaces.

  2. Pokud duální rozhraní nebo dispinterface nebude rozšířeno za běhu (to znamená, že nebudete poskytovat další metody nebo vlastnosti prostřednictvím IDispatch::Invoke), měli byste použít nonextensible atribut pro vaši definici. Tento atribut umožňuje klientům Automation provádět úplné ověření kódu v době kompilace. V tomto případě by rozhraní nemělo být rozšířeno.

  3. Správné ID DISPID je důležité, pokud chcete, aby klienti Automation mohli tuto vlastnost používat. (Všimněte si, že v DISPID_NEWENUM je pouze jedno podtržítko.)

  4. Jako IDENTIFIKÁTOR DISPID Item vlastnosti můžete zadat libovolnou hodnotu. Obvykle však používá DISPID_VALUE k tomu, Item aby byla výchozí vlastností kolekce. To umožňuje klientům Automation odkazovat na vlastnost bez explicitního pojmenování.

  5. Datový typ použitý pro návratové Item hodnoty vlastnosti je typ položky uložené v kolekci, pokud jde o klienty MODELU COM. Rozhraní vrací řetězce, takže byste měli použít standardní typ řetězce MODELU COM BSTR. Data můžete ukládat interně v jiném formátu, jak uvidíte krátce.

  6. Hodnota použitá pro DISPID Count vlastnosti je zcela libovolná. Pro tuto vlastnost neexistuje standardní DISPID.

Vytváření typedef pro ukládání a vystavení

Jakmile je rozhraní kolekce definováno, musíte se rozhodnout, jak se budou data ukládat a jak budou data vystavena prostřednictvím enumerátoru.

Odpovědi na tyto otázky můžete poskytnout ve formě řady typedefs, které můžete přidat do horní části souboru záhlaví pro nově vytvořenou třídu:

// Store the data in a vector of std::strings
typedef std::vector< std::string >         ContainerType;

// The collection interface exposes the data as BSTRs
typedef BSTR                               CollectionExposedType;
typedef IWords                             CollectionInterface;

// Use IEnumVARIANT as the enumerator for VB compatibility
typedef VARIANT                            EnumeratorExposedType;
typedef IEnumVARIANT                       EnumeratorInterface;

V tomto případě uložíte data jako std::vector std ::strings. std::vector je třída kontejneru standardní knihovny C++, která se chová jako spravované pole. std::string je třída řetězců standardní knihovny jazyka C++. Tyto třídy usnadňují práci s kolekcí řetězců.

Vzhledem k tomu, že podpora jazyka Visual Basic je nezbytná pro úspěch tohoto rozhraní, enumerátor vrácený _NewEnum vlastností musí podporovat IEnumVARIANT rozhraní. Toto je jediné rozhraní enumerátoru, kterému jazyk Visual Basic rozumí.

Vytváření typedefs pro třídy zásad kopírování

Typedefs, které jste zatím vytvořili, poskytují všechny informace, které potřebujete k vytvoření dalších typedefs pro třídy kopírování, které budou používány enumerátorem a kolekcí:

// Typedef the copy classes using existing typedefs
typedef VCUE::GenericCopy<EnumeratorExposedType, ContainerType::value_type> EnumeratorCopyType;
typedef VCUE::GenericCopy<CollectionExposedType, ContainerType::value_type> CollectionCopyType;

V tomto příkladu můžete použít vlastní GenericCopy třídu definovanou v VCUE_Copy.h a VCUE_CopyString.h z ukázky ATLCollections . Tuto třídu můžete použít v jiném kódu, ale možná budete muset definovat další specializace pro podporu datových GenericCopy typů používaných ve vlastních kolekcích. Další informace naleznete v tématu ATL Copy Policy Classes.

Vytváření typedefs pro výčet a kolekci

Nyní byly všechny parametry šablony nezbytné pro specializaci CComEnumOnSTL a ICollectionOnSTLImpl třídy pro tuto situaci poskytovány ve formě typedefs. Pokud chcete zjednodušit používání specializace, vytvořte další dva typydefy, jak je znázorněno níže:

typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;

Nyní CollectionType je synonymem pro specializaci ICollectionOnSTLImpl , která implementuje IWords rozhraní definované dříve a poskytuje enumerátor, který podporuje IEnumVARIANT.

Úprava kódu generovaného průvodcem

Nyní je nutné odvodit CWords z implementace rozhraní reprezentované CollectionType typedef místo IWords, jak je znázorněno níže:

class ATL_NO_VTABLE CWords :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CWords, &CLSID_Words>,
   // 'CollectionType' replaces 'IWords' in next line
   public IDispatchImpl<CollectionType, &IID_IWords, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_WORDS)


BEGIN_COM_MAP(CWords)
   COM_INTERFACE_ENTRY(IWords)
   COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// Remainder of class declaration omitted.

Přidání kódu pro naplnění kolekce

Jedinou věcí, která zůstává, je naplnění vektoru daty. V tomto jednoduchém příkladu můžete do kolekce přidat několik slov v konstruktoru pro třídu:

CWords()
{
    m_coll.push_back("this");
    m_coll.push_back("is");
    m_coll.push_back("a");
    m_coll.push_back("test");
}

Teď můžete kód otestovat pomocí klienta podle vašeho výběru.

Viz také

Kolekce a výčty
Ukázka ATLCollections
Třídy zásady kopírování ATL