class CarBoat : public ICar

{

LONG m_cRef;

CarBoat (void): m_cRef(0) {}

public:

// IUnknown methods

// методы IUnknown

STDMETHODIMP QueryInterface(REFIID, void**);

STDMETHODIMP_(ULONG) AddRef(void);

STDMETHODIMP_(ULONG) Release(void);

// IVehicle methods

// методы IVehicle

STDMETHODIMP GetMaxSpeed(long *pMax);

// ICar methods

// методы ICar

STDMETHODIMP Brake(void);

// define nested class that implements IBoat

// определяем вложенный класс, реализующий IBoat

struct XBoat : public IBoat

{

LONG m_cBoatRef;

// back pointer to main object is explicit member

// обратный указатель на главный объект – явный член

CarBoat *m_pThis;

inline CarBoat* This()

{

return m_pThis;

}

XBoat(CarBoat *pThis);

~XBoat(void);

STDMETHODIMP QueryInterface(REFIID, void**);

STDMETHODIMP_(ULONG) AddRef(void);

STDMETHODIMP_(ULONG) Release(void);

STDMETHODIMP GetMaxSpeed(long *pval);

STDMETHODIMP Sink(void);

};

// note: no data member of type Xboat

// заметим: нет элементов данных типа Xboat

};

Для QueryInterface главного объекта необходимо динамически разместить новый отделяемый интерфейс – каждый раз, когда запрашивается IBoat:

STDMETHODIMP CarBoat::QueryInterface(REFIID riid, void **ppv)

{

if (riid == IID_IBoat)

*ppv = static_cast<IBoat*>(new XBoat(this));

else if (riid == IID_IUnknown)

*ppv = static_cast<IUnknown*>(this);

:

:

Каждый раз при получении запроса на интерфейс IBoat размещается новый отделяемый интерфейс. Согласно стандартной практике QueryInterface вызова AddRef посредством результирующего указателя: ((IUnknown*)*ppv)- >AddRef();

AddRef будет обрабатывать непосредственно из QueryInterface только отделяемый интерфейс. Важно то, что главный объект остается в памяти столько времени, сколько существует отделяемый интерфейс. Простейший путь обеспечить это – заставить сам отделяемый интерфейс представлять неосвобожденную ссылку. Это можно реализовать в разработчике и деструкторе отделяемого интерфейса:

CarBoat::XBoat::XBoat(CarBoat *pThis) : m_cBoatRef(0), m_pThis(pThis)

{

m_pThis->AddRef();

}

CarBoat::XBoat::~XBoat(void)

{

m_pThis->Release();

}

Как и в случае с композицией, методу QueryInterface отделяемого интерфейса требуется идентифицировать объект, делегируя освобождение функции главного объекта. Однако отделяемый интерфейс может выявлять запросы на тот интерфейс (интерфейсы), который он сам реализует, и просто возвращать указатель, обработанный AddRef, себе самому:

STDMETHODIMP CarBoat::XBoat::QueryInterface(REFIID riid, void**ppv)

{

if (riid != IID_IBoat) return This()->QueryInterface(riid, ppv);

*ppv = static_cast<IBoat*>(this);

reinterpret_cast<IUnknown*>(*ppv)->AddRef();

return S_OK;

}

Ввиду того, что отделяемый интерфейс должен самоуничтожаться, когда он больше не нужен, он должен поддерживать свой собственный счетчик ссылок и уничтожать себя, когда этот счетчик достигнет нуля. Как отмечалось ранее, деструктор отделяемого интерфейса освободит главный объект до того, как сам исчезнет из памяти:

STDMETHODIMP_(ULONG) CarBoat::XBoat::AddRef (void)

{

return InterlockedIncrement(&m_cRef);

}

STDMETHODIMP_(ULONG) CarBoat::XBoat::Release(void)

{

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату