Expert C++
上QQ阅读APP看书,第一时间看更新

Aggregation and composition

We encountered aggregation in the example of the Warehouse class. The Warehouse class stores an array of Products. In more general terms, it can be called an association, but to strongly emphasize the exact containment, we use the term aggregation or composition. In the case of aggregation, the class that contains an instance or instances of other classes could be instantiated without the aggregate. This means that we can create and use a Warehouse object without necessarily creating Product objects contained in the Warehouse.

Another example of aggregation is the Car and the Person. A Car can contain a Person object (as a driver or passenger) since they are associated with each other, but the containment is not strong. We can create a Car object without a Driver in it, as follows:

class Person; // forward declaration
class Engine { /* code omitted for brevity */ };
class Car {
public:
Car();
// ...
private:
Person* driver_; // aggregation
std::vector<Person*> passengers_; // aggregation
Engine engine_; // composition
// ...
};

The strong containment is expressed by composition. For the Car example, an object of the Engine class is required to make a complete Car object. In this physical representation, the Engine member is automatically created when a Car is created. 

The following is the UML representation of aggregation and composition:

When designing classes, we have to decide on their relationship. The best way to define the composition between the two classes is the has-a relationship test. A Car has-a Engine, because a car has an engine. Any time you can't decide whether the relationship should be expressed in terms of composition, ask the has-a question. Aggregation and composition are somewhat similar; they just describe the strength of the connection. For aggregation, the proper question would be can have a; for example, a Car can have a driver (of the Person type); that is, the containment is weak.