Figure 1    C++ Stack Class

const int MAXSTACK = 1000;

class Stack
{
protected:
    int* const m_pItems;
    int m_nTop;

public:
    enum { FullStack = MAXSTACK, EmptyStack = -1 };

    Stack()
    : m_pItems(new int[MAXSTACK])
    {
        m_nTop = EmptyStack;
    }

    ~Stack()
    {
        delete [] m_pItems;
    }

    void Push(int nValue)
    {
        if (!IsFull())
            m_pItems[++m_nTop] = nValue;
    }

    int Pop(void)
    {
        int nValue = m_pItems[m_nTop];
        if (!IsEmpty())
            m_nTop--;

        return nValue;
    }

    bool IsEmpty()  { return m_nTop == EmptyStack; }
    bool IsFull()   { return m_nTop == FullStack - 1; }
};

Figure 2    Collection Class Methods and Properties

Collection
Method/Property
Required? Description
Count Yes This property returns the number of items in the collection. Its DISPID can be any number.
_NewEnum Yes This property returns a generic interface pointer to an IEnumVARIANT enumerator. Its DISPID is unique and must be set to DISPID_NEWENUM (–4), meaning that the name of this method need not be localized. It should be declared in IDL using the restricted keyword so that it is not visible to macro programming languages like VBScript.
Item Yes This method returns the indicated item in the collection or NULL if the requested item does not exist. It must be the default member of the class, so its DISPID must be set to DISPID_VALUE (0).
Add No This method adds the indicated item to the collection. If an object is created as a result of the addition, a pointer to that object should be returned.
Remove No This method removes an item from the collection. It supports the same indexing as the Item method. The Remove method should not attempt to force deletion of the object; rather, it should release its reference to the object and remove it from the collection.


Figure 3   Collection Class IDL


interface IAnimals : IDispatch
{
    [propget, restricted, id(DISPID_NEWENUM),
    helpstring("property _NewEnum")]
    HRESULT _NewEnum([out, retval] IUnknown** pVal);

    [id(DISPID_VALUE), helpstring("method Item")]
    HRESULT Item([in] VARIANT index, [out, retval] IDispatch** ppItem);

    [propget, id(1), helpstring("property Count")]
    HRESULT Count([out, retval] long *pVal);

// Optional Add and Remove methods. These signatures are
// implementation-dependent.

    [id(2), helpstring("method Add")]
    HRESULT Add([in] BSTR name, [out, retval] IDispatch** ppItem);

    [id(3), helpstring("method Remove")]
    HRESULT Remove([in] VARIANT index);
};

Figure 4   Enumerator Interface Methods

IEnumXxxx Methods Description
Next Retrieves a specified number of items in the enumeration sequence. The data type of the items returned depends on the collection being enumerated.
Skip Skips over a specified number of items in the enumeration sequence.
Reset Resets the enumeration sequence to the beginning.
Clone Creates another enumerator that contains the same enumeration state as the current one.


Figure 5   Implementing the Item Method


 STDMETHODIMP CAnimals::Item(VARIANT index, IDispatch** ppItem)
 {
     switch(index.vt)
     {
 
         // If the VARIANT is a BSTR, let's look up the Animal
         // by name!
 
         case VT_BSTR:
         {
             bstr_t bstrName(index.bstrVal);
             std::vector<IAnimal*>::iterator item = m_itemList.begin();
             
             for (; item != m_itemList.end(); item++)
             {
                 CComBSTR bstrItem;
                 (*item)->get_Name(&bstrItem);
                 if (bstrName == bstr_t(bstrItem))
                 {
                     return (*item)->QueryInterface(IID_IDispatch,
                                                    (void**)ppItem);
                 }
             }
             return E_FAIL;
         }
 
         // If the VARIANT is a long integer, let's look up the Animal
         // by offset!
 
         case VT_I4:
         {
             if (index.lVal < 0 || index.lVal >= m_itemList.size())
                 return E_FAIL;
             
             return m_itemList[index.lVal]->QueryInterface(
                 IID_IDispatch, (void**)ppItem);
         }
 
         // If the VARIANT is neither of those, we'll punt!!
 
         default:
             return E_FAIL;
     }
 }

Figure 6   Strongly typed Collection Interfaces

Interface Methods Description
ICollectXxxx Item Returns a pointer to the desired IXxxx interface
Count Returns the number of objects in the collection
EnumCollection Returns a pointer to IEnumXxxx interface
ICollectOwnerXxxx Add Adds an item to the collection
Remove Removes an item from the collection
IEnumXxxx Next Retrieves the specified number of items
Skip Skips over the specified number of items
Reset Resets the enumeration sequence to the beginning
Clone Creates another enumerator with same state