An earlier example demonstrated how the inheritance relationship between two classes, a Car and a Sedan, could be described as an "is-a" relationship: a Sedan is-a Car. The example further suggested that it "didn't sound right" to say that a sedan "has-a" Car or that a Car "has-a" Sedan. Nevertheless, the "has-a" phrase is useful in many problem solutions, suggesting a constructive relationship between the two classes. But, unlike inheritance, which is fundamental to object orientation and implemented with dedicated syntax, constructive relationships are implemented with class-scope or member variables. We can create three different relationships depending on how we define and where we place the variables.
Composition
Aggregation
Association
Constructive or "has-a" relationships. The constructive relationships connect classes - they help construct object-oriented programs. Aggregation and composition represent whole-part relationships in C++ programs and UML class diagrams. The UML composition and aggregation symbols are similar, suggesting that the relationships are similar. In C++, we implement aggregation with a pointer member variable and composition with a non-pointer variable. In English, we can read both relationships as a Car "has-an" Engine or a Car "has-a" Transmission. We can read the relationships in the opposite directions as "part of:" an Engine is part of a Car or a Transmission is part of a Car. Notice that it doesn't sound right in English (but the phrase may not work in other languages) to say that an Engine "is-a" Car or a Car "is-an" Engine, suggesting that the classes aren't naturally connected by inheritance.
Association is also a "has-a" relationship, but unlike composition and aggregation, it reads well in either direction: a contractor has-a project or a project has-a contractor. Although association is more general than the other constructive relationships, it's more difficult to implement. Furthermore, in some cases, composition or aggregation may better reflect the "real world" relationship between classes.
Contrasting Composition, Aggregation, and Association
Grouping three relationships and labeling them as "constructive" suggests they are similar in many ways. But if there isn't at least one difference, we wouldn't include three individually named relationships in our taxonomy. As you fill in the class relationship tables, look for the similarities and differences between these relationships.
Composition
Implements the parts as non-pointer member variables in the whole class
A unidirectional relationship
Binds the part objects strongly or tightly to the whole object - the compiler embeds the parts inside the whole
The program creates and destroys the parts and the relationship when it creates and destroys the whole
Once created, the parts can't be changed
The parts are not shared with any other object in the program
Aggregation
Implements the parts as pointer member variables in the whole class
A unidirectional relationship
Binds the part objects weakly or loosely to the whole object - the parts exist outside the whole
The parts and the whole may be created and destroyed at different times
The parts can be changed or replaced whenever it is convenient
The parts may be shared with other objects in the program, making ownership of the part an important issue
Association
Implements the connection as two pointer member variables, one in each class
A bidirectional relationship
Binds the two peers together weakly or loosely
The peers may be created and destroyed at different times
The program can change or destroy the relationship whenever it is convenient
The program can share the peers with other program objects
Modeling With Library Classes
In an often referenced1 1976 Saturday Night Live sketch, Gilda Radner and Dan Aykroyd argue over "Shimmer." Is it a dessert topping or a floor wax? Chevy Chase settles the argument, explaining that it's both! (You can see how often people use the sketch to introduce concepts with a dual nature by Googling "dessert topping or floor wax.") We see the same conflict when we model problems using library or API classes, especially strings.