// release it later in the object's destructor
// освобождаем здесь ссылку на внешний объект и
// НЕ ОСВОБОЖДАЕМ ее потом в деструкторе объекта
if (SUCCEEDED(hr)) m_pTruck->Release();
}
Этот способ работает, поскольку время жизни внутреннего объекта является точным подмножеством времени жизни внешнего объекта. Это означает, что
Объекты, которые агрегируют другие объекты, должны быть в курсе проблем, возникающих при запросе интерфейсных указателей внутренними объектами агрегата. В дополнение к уже сделанному предостережению относительно отделяемых интерфейсов отметим еще одну возможную опасность, связанную со стабилизацией объекта. Когда клиенты обращаются к объекту, он должен находиться в стабильном состоянии. В частности, его счетчик ссылок не должен равняться нулю. В общем случае это не является проблемой, так как клиенты могут получать интерфейсные указатели только через
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 }
Данная методика стабилизации предотвращает преждевременное разрушение, когда внутренний объект освобождает указатели, которые он, быть может, получил в свой код инициализации. Эта методика настолько общепринята, что большинство СОМ-оболочек программирования включают в себя явный метод перекрытия (
Поскольку показанные выше методики реализации агрегируемого объекта не требуют никаких дополнительных базовых классов, кроме классов C++, то альтернативная форма макроса
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);
};
Встроенное расширение макроса
Включение
Не все классы способны к агрегированию. Для того чтобы выставить неагрегируемые классы как часть индивидуальности другого объекта, необходимо, чтобы внешние объекты явно передавали вызовы методов внутренним объектам. Эта технология СОМ часто называется включением (
