Этот метод (и соответствующие API-функции
Имея прототип функции, приведенный выше, класс
CarBoat::CarBoat(void) : m_cRef(0)
{
// need to pass identity of self to Create routine
// to notify car object it 1s an aggregate
// нужно передать свою идентификацию подпрограмме
// Create для уведомления объекта car, что он – агрегат
HRESULT hr = CoCreateInstance(CLSID_Car, this, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkCar);
assert(SUCCEEDED(hr));
}
Реализация
STDMETHODIMP CarBoat::QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IUnknown) *ppv = static_cast
else if (riid == IID_ICar)
// forward request…
// переадресовываем запрос…
return m_pUnkCar->QueryInterface(riid, ppv);
else if (riid == IID_IBoat)
:
:
:
Теоретически это должно работать, так как агрегат будет всегда переадресовывать любые последующие запросы
В предыдущем сценарии метод
Для решения этой проблемы необходимо сделать так, чтобы начальный интерфейсный указатель, который возвращается внешнему объекту, не делегировал вызовы реализации
Имеется несколько возможностей обеспечить две различные реализации
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 in 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(); }