An aggregate is an object like any other object in that it implements one or
more interfaces. Internal to the aggregate, the implementation of certain
interfaces is actually provided by one or more contained objects. Users of the object
are unaware of this internal structure. They cannot tell and do not care that
the object is an aggregate: aggregation is purely an implementation technique.
The figure below shows an aggregate object consisting of a control object that
implements Interface A and Interface B, and a noncontrol object that
implements Interface C. All these interface implementations are exposed publicly, as
indicated by the line and circle extending to the outside of the aggregate.
In the aggregation model, the control object
determines how an aggregate behaves and operates, making decisions about
which interfaces are exposed outside of the object and which interfaces remain
private. The control object has a special instance of the IUnknown
interface known as the controlling unknown
. The controlling unknown must always be implemented as part of the new code
written when the aggregate is put together from other objects. However, when the
controlling unknown is passed in, it does not increment the reference count;
instead it is a non-incrementing pointer.
The other objects can be implemented at any time. These noncontrol objects can
be instantiated separately or as part of the aggregate. However, if these
objects are to be capable of aggregation, they must be written to cooperate with
the control object by forwarding their QueryInterface
, and Release
calls to the controlling unknown. A reference count for the aggregate as a
whole is maintained by the control object so that it is kept alive if there are
one or more references to any of the interfaces supported by either the control
or noncontrol objects.
It is possible for an object to call a method that may cause the object to be
released. A technique known as "artificial reference counting" can be used to
guard against this untimely release. The object calls IUnknown::AddRef
before the potentially destructive method call and IUnknown::Release
after it. If the object in question can be aggregated, it must call the
controlling unknown's implementations of AddRef
) to artificially increment the reference count rather than its own
implementations. For more information about reference counting, see Chapter 2, "The
Component Object Model."
The next figure shows how the coordination between the control and noncontrol
object works. The control object exposes the controlling unknown, Interface A
and Interface B. The noncontrol object supports IUnknown
and Interface C. All three interfaces derive from IUnknown
The control object holds a pointer to the noncontrol object's IUnknown
implementation so it can call the noncontrol methods when appropriate. The
noncontrol object holds a pointer to the controlling unknown for the same reason.
The pointer to the controlling unknown is supplied when the noncontrol object
is instantiated. When the controlling unknown pointer is saved by the
noncontrol object, AddRef
is not called to increment the reference count as you might expect. This is
because of the reference-counting cycle it would create. Instead, the noncontrol
object just keeps a copy of the pointer and delegates calls to it as described
in this section.
Referring again to the next figure, whereas the controlling unknown is
available to the outside, as is indicated by the line and circle identifying it
extending past the bounds of the aggregate, the noncontrol object's IUnknown
implementation works locally and can't be obtained from outside the
aggregate. It is called solely by the controlling unknown to obtain instances of the
noncontrol interfaces, such as Interface C, to expose to the outside.
- Software for developers
Software for Android Developers
- More information resources
Unix Manual Pages