Выбрать главу

Outer::Outer(void)

{

++m_cRef;

// protect against delete this

// защищаем против удаления this

CoCreateInstance(CLSID_Inner, this, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkInner);

–m_cRef;

// allow delete this

// позволяем удалить this }

Данная методика стабилизации предотвращает преждевременное разрушение, когда внутренний объект освобождает указатели, которые он, быть может, получил в свой код инициализации. Эта методика настолько общепринята, что большинство СОМ-оболочек программирования включают в себя явный метод перекрытия (overridable), который работает внутри области действия пары инкремент/декремент. В MFC (Microsoft Foundation Classes – библиотека базовых классов Microsoft) этот метод называется CreateAggregates, в ATL – FinalConstruct.

Поскольку показанные выше методики реализации агрегируемого объекта не требуют никаких дополнительных базовых классов, кроме классов C++, то альтернативная форма макроса IMPLEMENT_UNKNOWN может прозрачно реализовать раздвоенную реализацию IUnknown. Определение исходного класса:

class Car : public ICar

{

Car(void);

IMPLEMENT_UNKNOWN(Car)

BEGIN_INTERFACE_TABLE(Car)

IMPLEMENTS_INTERFACE(ICar)

IMPLEMENTS_INTERFACE(IVehicle)

END_INTERFACE()

// IVehicle methods

// методы IVehicle

STDMETHODIMP GetMaxSpeed(long *pn);

// ICar methods

// методы ICar

STDMETHODIMP Brake(void);

};

просто переводится в следующее:

class Car : public ICar

{

Car(void);

//indicate that aggregation is required

// показываем, что требуется агрегирование

IMPLEMENT_AGGREGATABLE_UNKNOWN(Car)

BEGIN_INTERFACE_TABLE(Car)

IMPLEMENTS_INTERFACE(ICar)

IMPLEMENTS_INTERFACE(IVehicle)

END_INTERFACE()

// IVehicle methods

// методы IVehicle

STDMETHODIMP GetMaxSpeed(long *pn);

// ICar methods

// методы ICar

STDMETHODIMP Brake(void);

};

Встроенное расширение макроса IMPLEMENT_AGGREGATABLE_UNKNOWN включено в код, приложенный к этой книге.

Включение

Не все классы способны к агрегированию. Для того чтобы выставить неагрегируемые классы как часть индивидуальности другого объекта, необходимо, чтобы внешние объекты явно передавали вызовы методов внутренним объектам. Эта технология СОМ часто называется включением (containment).

Как показано на рис. 4.9, включение не требует никакого участия со стороны внутреннего объекта. В то же время требуется, чтобы во внешнем объекте производились реализации каждого интерфейса, выставляемого внутренним объектом. Эти внешние реализации просто передают клиентские запросы внутреннему объекту. Включение СОМ не требует никаких особых забот касательно правил идентификации СОМ, так как внутренний объект никогда не доступен клиенту впрямую и поэтому никогда непосредственно не внедряется в иерархию типов внешнего объекта. Хотя СОМ-включение входит в терминологию СОМ, оно не требует никаких особых программистских ухищрений. Фактически включаемый объект не может обнаружить, что внешний объект переадресовывает запросы его методов от действующего клиента.

Где мы находимся?

В данной главе обсуждались законы идентификации в СОМ. В этих законах определено, что означает быть объектом СОМ. Законы идентификации СОМ предоставляют разработчику объекта потрясающую гибкость при разделении реализации объекта. В качестве технологии для освобождения подсчета ссылок для каждого интерфейса была представлена композиция. Для сокращения размножения vptr, а также для более эффективного управления состоянием объекта были описаны отделяемые интерфейсы. Затем было показано агрегирование в качестве способа создания одной идентификационной единицы (identity ) из двух или более двоичных компонентов. Каждая из этих технологий позволяет более чем одному объекту выступать в качестве одной идентификационной единицы СОМ. Каждая технология имеет свои преимущества, и использование любой из них или всех вместе полностью скрыто от клиентов объекта.

Глава 5. Апартаменты

STDMETHODIMP CMyClass::MethodX(void) {

EnterCr1t1calSect1on(&m_cs);

if (TryToPerformX() == false)

return E_UNEXPECTED:

LeaveCriticalSect1on(&m_cs);

return S_OK; }

Аноним, 1996

В предыдущей главе обсуждались основы идентификации в СОМ и было формально определено, что именно отличает объекты СОМ от объектов памяти с произвольной организацией. Были представлены правила IUnknown и способы использования этих правил для придания разработчику объектов максимальной гибкости. В данной главе уточняется понятие идентификации в СОМ с учетом базисных элементов (примитивов) операционной системы (например, потоков, процессов), а также распределенного доступа. Этот альянс базисных элементов системы и распределения формируют основу архитектуры удаленного доступа СОМ.

Снова интерфейс и реализация

Некоторые разработчики всесторонне используют многопоточные программные технологии и способны написать удивительно изощренный программный продукт с использованием примитивов синхронизации потоков, доступных из операционной системы. Другие разработчики больше сконцентрированы на решении вопросов, специфических для их области, и не утруждают себя написанием нудного потоко-безопасного кода. Третьи разработчики имеют особые ограничения по организации потоков, связанные с тем, что многие системы с управлением окнами (включая Windows) имеют очень строгие правила взаимодействия потоков и оконных примитивов. Еще один класс разработчиков может широко использовать старую библиотеку классов, которая неприязненно относится к потокам и не может допустить какого бы то ни было многопоточного обращения. У всех четырех типов разработчиков должна быть возможность использования объектов друг друга без перестраивания их потоковой стратегии, чтобы приспособиться ко всем возможным сценариям. Чтобы облегчить прозрачное использование объекта безотносительно к его осведомленности о потоках, СОМ рассматривает ограничения на параллелизм объектов как еще одну деталь реализации, о которой клиенту не нужно беспокоиться. Чтобы освободить клиента от ограничений параллелизма и реентерабельности (повторной входимости), в СОМ имеется весьма формальная абстракция, которая моделирует связь объектов с процессами и потоками. Эта абстракция носит название апартамент (apartment)[1] . Апартаменты определяют логическое группирование объектов, имеющих общий набор ограничений по параллелизму и реентерабельности. Каждый объект СОМ принадлежит к ровно одному апартаменту: один апартамент, однако, может быть общим для многих объектов. Апартамент, к которому относится объект, безоговорочно является частью идентификационной уникальности объекта.

вернуться

1 Апартаменты являются более современным названием того, что в спецификации СОМ изначально именовалось контекстом исполнения (execution context).