Сущность технологии СОМ. Библиотека программиста | страница 58



, так как известно, что они надежны во всех ситуациях и освобождают разработчика от необходимости сохранять две версии практически одинакового кода.

Показанные выше реализации AddRef и Release предполагают, что объект может размещаться только в динамически распределяемой области памяти (в «куче») с использованием С++-оператора new. В определении класса деструктор сделан защищенной операцией для обеспечения того, чтобы ни один экземпляр класса не был определен никаким другим способом. Однако иногда желательно иметь объекты, не размещенные в «куче». Для этих объектов вызов delete в последнем вызове Release был бы гибельным. Так как единственной причиной для того, чтобы объект в первую очередь поддерживал счетчик ссылок, была необходимость вызова delete this, допустимо оптимизировать счетчик ссылок для объектов, не содержащихся в динамически распределяемой области памяти:


STDMETHODIMP(ULONG) GlobalVar::AddRef(void)

{

return 2;

// any non-zero value is legal

// допустима любая ненулевая величина

}

STDMETHODIMP(ULONG) GlobalVar::Release (void)

{

return 1;

// any non-zero value is legal

// допустима любая ненулевая величина

}


Эта реализация использует тот факт, что результаты AddRef и Release служат только для сведения и не обязаны быть точными.

При наличии реализации AddRef и Release единственным еще не реализованным методом из IUnknown остается QueryInterface. Его реализации должны отслеживать иерархию типов объекта и использовать статические приведения типов для возврата правильного типа указателя для всех поддерживаемых интерфейсов. Для определения класса PugCat, рассмотренного ранее, следующий код является корректной реализацией QueryInterface : STDMETHODIMP


PugCat::QueryInterface(REFIID riid, void **ppv)

{

assert(ppv != 0);

// or return EPOINTER in production

// или возвращаем EPOINTER в реальный продукт

if (riid == IIDIPug) *ppv = staticcast(this);

else if (riid == IIDIDog) *ppv = staticcast(this);

else if (riid == IIDIAnimal)

// cat or pug?

// кот или мопс?

*ppv == staticcast(this);

else if (riid == IIDIUnknown)

// cat or pug?

// кот или мопс?

*ppv = staticcast(this);

else if (riid == IIDICat) *ppv = staticcast(this);

else

{

// unsupported interface

// неподдерживаемый интерфейс

*ppv = 0;

return ENOINTERFACE;

}

// if we reach this point, *ppv is non-null

// and must be AddRef'ed (guideline A2)

// если мы дошли до этого места, то *ppv ненулевой