Имеется несколько возможностей обеспечить две различные реализации IUnknown от одного объекта. Самый прямой путь — это использование композиции и элемента данных для реализации неделегирующих методов IUnknown. Ниже показана реализация Car, поддающаяся агрегации:
class Car : public ICar { LONG m_cRef; IUnknown *m_pUnk0uter; public: Car(IUnknown *pUnk0uter); // non-delegating IUnknown methods // неделегирующие методы IUnknown STDMETHODIMP InternalQueryInterface(REFIID, void **); STDMETHODIMP (ULONG) InternalAddRef(void); STDMETHODIMP_(ULONG) InternalRelease(void); // delegating IUnknown methods // делегирующие методы IUnknown STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP GetMaxSpeed(*long *pn); STDMETHODIMP Brake(void); // composite to map distinguished IUnknown vptr to // non-delegating InternalXXX routines 1n main object // композит для преобразования определенного vptr IUnknown // в неделегирующие подпрограммы InternalXXX в главном // объекте
class XNDUnknown : public IUnknown { Car* This() { return (Car*)((BYTE*)this - offsetof(Car, m_innerUnknown));} STDMETHODIMP QueryInterface(REFIID r, void**p) { return This()->InternalQueryInterface(r,p); } STDMETHODIMP_(ULONG) AddRef(void) { return This()->InternalAddRef(); } STDMETHODIMP_(ULONG) Release(void) { return This()->InternalRelease(); } };
XNDUnknown m_innerUnknown; // composite instance // экземпляр композита };
Двоичное размещение этого объекта показано на рис. 4.8. Методы делегирования класса чрезвычайно просты:
STDMETHODIMP Car::QueryInterface(REFIID riid, void **ppv) { return m_pUnkOuter->QueryInterface(riid, ppv); }
STDMETHODIMP_(ULONG) Car::AddRef(void) { return m_pUnkOuter->AddRef(); }