Compositions

The primary means for handling complexity in object‑based systems is through object decomposition. An object can be composed of other objects or subobjects (nested objects). A subobject is an object defined within a parent object. The parent object (or owner) can delegate requests to be handled by its subobjects, and the subobjects can communicate back to their parent object.

Each of the subobjects knows the HomeHeatingSystem as its parent, and the HomeHeatingSystem can access each of its subobjects by name. This view of the HomeHeatingSystem is called an object structure view, because it shows the internal structure of the object. The subobjects can be linked to each other or not, depending on the nature of the system.

With compositions, the parent object holds the subobjects by value rather than by pointer. The parent object is responsible for initializing and cleaning up after the subobjects. See Constructors and destructors for more information.

By default, a subobject designates a single instance and is implemented as a member of the structure of the parent object. The name of a member and type are the same as the name and type of the subobject. In other words, subobjects are embedded by value in the parent object, rather than as pointers to objects.

When a multiplicity of a subobject is specified as a number greater than one, the subobjects are implemented as an array by default. For example, theFurnace and theRooms are implemented as members of the HomeHeatingSystem structure. The object theFurnace is implemented as a single instance of type Furnace, and theRooms are implemented as an array of three Rooms:


typedef struct HomeHeatingSystem HomeHeatingSystem;
struct HomeHeatingSystem {
    RiCReactive ric_reactive;
    /***    User implicit entries    ***/
    struct Furnace theFurnace;
    struct Room theRooms[3];
};

If a multiplicity of a subobject is not known in advance, it is implemented as a linked list. For example, if you specified multiplicity of theRooms as * rather than 3, it would be implemented as an RiCList as follows:


struct HomeHeatingSystem {
    RiCReactive ric_reactive;
    /***    User implicit entries    ***/
    struct Furnace theFurnace;
    RiCList theRooms;
};

You can also implement subobjects using other types of dynamic containers (such as collections). You specify how to implement concrete relations using the CG::Relation::Implementation property. For example, setting the Implementation property for theRooms to UnboundedUnordered would implement theRooms as an RiCCollection rather than as an RiCList or array.

The properties under the subject RiCContainers determine how functions are generated for various kinds of containers used to implement relations. See the definitions provided for the properties on the applicable Properties tab of the Features window.