IUnknown не имеет реализации по умолчанию, которая являлась бы частью интерфейса системного вызова СОМ. Заголовочные файлы SDK не содержат базовых классов, макросов или шаблонов, предусматривающих реализации QueryInterface, AddRef и Release, которые должны использоваться во всех программах на С или C++. Вместо этого Спецификация СОМ (Component Object Model Specification) предоставляет очень точные правила относительно допущений, которые клиенты и объекты могут делать относительно этих трех методов. Этот набор правил формирует протокол IUnknown и позволяет каждому разработчику объекта преобразовать три указанных метода IUnknown во все, что имеет смысл для его или ее объекта.
В главе 2 представлены фактические С++-реализации трех упомянутых методов, но СОМ никоим образом не обязывает объекты использовать их. Все, что требует СОМ, — это чтобы каждая реализация придерживалась базовых правил IUnknown. Как это достигается, не имеет ни малейшего отношения к СОМ. Это делает СОМ совершенно ненавязчивой, так как эта модель не требует, чтобы объект делал системные вызовы, наследовал системным реализациям, а все, что от него требуется, — это объявлять совместимые с СОМ указатели vptr. На самом деле, как будет показано далее в этой главе, можно выставлять наследующие IUnknown указатели vptr из классов, которые не наследуют ни одному интерфейсу СОМ.
Правила IUnknown в совокупности определяют, что значит быть объектом СОМ. Чтобы понять правила IUnknown, полезно начать с конкретного примера. Рассмотрим следующую иерархию интерфейсов:
import "unknwn.idl"; [object, uuid(CD538340-A56D-11d0-8C2F-0080C73925BA)] interface IVehicle : IUnknown { HRESULT GetMaxSpeed([out, retval] long *pMax); }
[object, uuid(CD53834l-A56D-11d0-8C2F-0080C73925BA)] interface ICar : IVehicle { HRESULT Brake(void); }
[object, uuid(CD538342-A56D-11d0-8C2F-0080C73925BA)] interface IPlane : IVehicle { HRESULT TakeOff(void); }
[object, uuid(CD538343-A56D-11d0-8C2F-0080C73925BA)] interface IBoat : IVehicle { HRESULT Sink(void); }