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

ОглавлениеДобавить в закладки К обложке

QI(IBoat)->ICar

пройдет успешно, а запрос

QI(QI(IBoat)->ICar)->IBoat

потерпит неудачу, так как полученная QueryInterface будет несимметричной. Вдобавок запросы QueryInterface о IUnknown через интерфейсные указатели ICar и IBoat вернут различные значения, а это означает, что будет идентифицировано два различных объекта. Из подобных нарушений протокола IUnknown следует, что объекты CarBoat попросту не являются действительными объектами СОМ.

Идея составления объекта из двоичных композитов звучит красиво. Действительно, Спецификация СОМ четко и подробно указывает, как реализовать эту идею в стандартной и предсказуемой манере. Технология выставления клиенту двоичного подкомпонента непосредственно через QueryInterface называется СОМ-агрегированием. СОМ-агрегирование является лишь набором правил, определяющих отношения между внешним объектом (агрегирующим) и внутренним (агрегируемым). СОМ-агрегирование – это просто набор правил IUnknown, позволяющих более чем одному двоичному компоненту фигурировать в качестве идентификационной единицы (identity) СОМ.

Агрегирование СОМ несомненно является главной движущей силой для повторного использования в СОМ. Намного проще приписывать объекту значения и использовать его методы в реализации методов других объектов. Только в редких случаях кто-то захочет выставлять интерфейсы другого объекта непосредственно клиенту как часть той же самой идентификационной единицы. Рассмотрим следующий сценарий:

class Handlebar : public IHandlebar { … };

class Wheel : public IWheel {};

class Bicycle : public IBicycle

{

IHandlebar * m_pHandlebar;

IWheel *m_pFrontWheel;

IWheel *m_pBackWheel;

}

Было бы опрометчиво для класса Вicycle объявлять интерфейсы IHandlebar (велосипедный руль) или IWheel (колесо) в собственном методе QueryInterface. QueryInterface зарезервирован для выражения отношений «является» (is-a), а велосипед (bicycle) очевидно не является колесом (wheel) или рулем (handlebar). Если разработчик Bicycle хотел бы обеспечить прямой доступ к этим сторонам объекта, то интерфейс IBicycle должен был бы иметь для этой цели аксессоры определенных свойств:

[object, uuid(753A8A60-A7FF-11d0-8C30-0080C73925BA)] interface IBicycle : IVehicle

{

HRESULT GetHandlebar([out,retval] IHandlebar **pph);

HRESULT GetWheels([out] IWheel **ppwFront, [out] IWheel **ppwBack);

}

Реализация Bicycle могла бы тогда просто возвращать указатели на свои подобъекты:

STDMETHODIMP Bicycle::GetHandlebar(IHandlebar **pph)

{

if (*pph = m_pHandlebar) (*pph)->AddRef();

return S_OK;

}

STDMETHODIMP Bicycle::GetWheels(IWheel **ppwFront, IWheel **ppwBack)

{

if (*ppwFront = m_pFrontWheel) (*ppwFront)->AddRef();

if (*ppwBack = m_pBackWheel) (*ppwBack)->AddRef();

return S_OK;

}

При использовании данной технологии клиент по-прежнему получает прямой доступ к подобъектам. Однако поскольку указатели получены через явные методы, а не через QueryInterface, то между различными компонентами не существует никаких идентификационных отношений.

Несмотря на этот пример, все же остаются сценарии, где желательно обеспечить реализацию интерфейса, которая могла бы быть внедрена в идентификационную единицу другого объекта. Чтобы осуществить это, в СОМ-агрегировании требуется, чтобы внутренний объект (агрегируемый) уведомлялся во время его создания, что он создается как часть идентификационной единицы другого объекта. Это означает, что создающая функция (creation function), обычно используемая для создания объекта, требует один дополнительный параметр: указатель IUnknown на идентификационную единицу, которой агрегирующий объект должен передать функции в ее методы QueryInterface, AddRef и Release. Покажем определение метода CreateInstance интерфейса IClassFactory:


Логин
Пароль
Запомнить меня