Поэтому правильной концовкой QueryInterface будет
Поэтому правильной концовкой QueryInterface будет следующая:
((IUnknown*)(*ppv))->AddRef(); // use exact ptr // используем точный указатель return S_OK;
вместо такого:
AddRef(); // just call this->AddRef // только вызов this->AddRef return S_OK;
Первый вариант гарантирует, что если клиент пишет следующий правильный код
IBoat *pBoat = 0; HRESULT hr = pUnk->QueryInterface(IID_IBoat, (void**)&pBoat); if (SUCCEEDED(hr)) { hr = pBoat->Sink(); pBoat->Release(); }
то для AddRef и для Release обязательно будет использовано одно и то же значение указателя.
Можно осуществлять композицию в контексте управляемой таблицами реализации QueryInterface. При наличии семейства макросов препроцессора, показанного в предыдущей главе, достаточно всего одного дополнительного макроса, чтобы определить, что вместо базового класса используется элемент данных, и второго макроса, чтобы реализовать методы IUnknown в композите:
class CarBoatPlane : public ICar, public IPlane { public: struct XBoat : public IBoat { // composite QI/AddRef/Release/This() // композит из QI/AddRef/Release/This() IMPLEMENT_COMPOSITE_UNKNOWN(CarBoatPlane, XBoat, m_xBoat) STDMETHODIMP GetMaxSpeed(long *pval); STDMETHODIMP Sink(void); };
XBoat m_xBoat;
// IVehicle methods // методы IVehicle STDMETHODIMP GetMaxSpeed(long *pMax);
// ICar methods // методы ICar STDMETHODIMP Brake(void);
// IPlane methods // методы IPlane STDMETHODIMP TakeOff(void);
// standard heap-based QI/AddRef/Release // стандартные расположенные в "куче" QI/AddRef/Release
IMPLEMENT_UNKNOWN(CarBoatPlane) BEGIN_INTERFACE_TABLE(CarBoatPlane) IMPLEMENTS_INTERFACE_AS(IVehicle, ICar) IMPLEMENTS_INTERFACE(ICar) IMPLEMENTS_INTERFACE(IPlane) // macro that calculates offset of data member // макрос, вычисляющий смещение элемента данных IMPLEMENTS_INTERFACE_WITH_COMPOSITE(IBoat, XBoat, m_xBoat) END_INTERFACE_TABLE() };
В приведенном выше определении класса опущены только определения методов объекта вне QueryInterfасе, AddRef и Release.
Содержание Назад Вперед