Association and Modern C++ Integration
Table of Contents
- Association: The
Has-ARelationship - Weak vs Strong Lifecycle (Aggregation vs Composition)
- Implementing Association in C++
- Modern C++ Smart Pointers
1. Association: The Has-A Relationship
While Inheritance defines an Is-A relationship (Monkey is-an Animal), Association defines a Has-A relationship.
A Has-A relationship occurs when a class uses an instance of another class as one of its own attributes.
For example, if you have a Library class, it will contain a collection of Book objects. The library has books. A Car has an Engine.
Depending on how tightly bound these two objects are to each other's lifecycles, the "Has-A" relationship is split into two distinct types: Aggregation and Composition.
2. Weak vs Strong Lifecycle (Aggregation vs Composition)
| Feature | Aggregation (Weak) | Composition (Strong) |
|---|---|---|
| Relationship Type | "Has-A" (Loose ownership) | "Has-A" (Strict death-do-us-part ownership) |
| Lifecycle Dependency | Independent. Child survives parent's deletion. | Dependent. Child dies automatically with parent. |
| C++ Implementation | Uses pointers or references (Base* or Base&) pointing to external objects. | Uses direct member objects (Base obj) or allocates internally on creation. |
| Cardinality | Often Many-to-Many (A professor can belong to multiple departments). | Strictly One-to-One or One-to-Many (A room cannot belong to two separate houses). |
3. Implementing Association in C++
Aggregation Example (Weak)
class Professor {
public:
string name;
Professor(string n) : name(n) {}
};
class Department {
private:
// Aggregation: The Department holds a POINTER to the Professor.
// It does NOT own the Professor.
Professor* prof;
public:
Department(Professor* p) : prof(p) {}
~Department() {
// Notice we DO NOT delete the prof here!
// The professor survives the closure of the department.
}
};
int main() {
Professor* drSmith = new Professor("Dr. Smith");
Department* mathDept = new Department(drSmith);
delete mathDept; // Math dept closes.
// drSmith is STILL ALIVE and can join another department!
delete drSmith;
}Composition Example (Strong)
class Engine {
public:
Engine() { cout << "Engine created\n"; }
~Engine() { cout << "Engine destroyed\n"; }
};
class Car {
private:
// Composition: The Car DIRECTLY owns the Engine.
Engine engine;
public:
Car() { cout << "Car created\n"; }
~Car() { cout << "Car destroyed\n"; }
};
int main() {
Car* myCar = new Car();
delete myCar; // When the car is deleted, the engine is AUTOMATICALLY destroyed.
}4. Modern C++ Smart Pointers
Raw pointers (*) cause massive headaches (memory leaks, dangling pointers) if you forget to delete them. Modern C++ (C++11 and up) solves this using Smart Pointers, which map perfectly to Association concepts!
1. std::unique_ptr (Perfect for Composition)
An exclusive ownership pointer. When the pointer goes out of scope, the object is automatically deleted. It cannot be copied.
#include <memory>
class Car {
private:
// The Car exclusively owns the engine. Composition!
std::unique_ptr<Engine> engine;
public:
Car() : engine(std::make_unique<Engine>()) {}
// No need to manually delete engine in destructor!
};2. std::shared_ptr (Perfect for Aggregation)
Shared ownership. Multiple pointers can point to the same object. It uses a Reference Count. When the count drops to 0 (all departments are deleted), the professor is finally deleted.
#include <memory>
class Department {
private:
std::shared_ptr<Professor> prof;
public:
Department(std::shared_ptr<Professor> p) : prof(p) {}
};
int main() {
std::shared_ptr<Professor> drSmith = std::make_shared<Professor>("Dr. Smith");
// Both Math and Physics share ownership of Dr. Smith
Department math(drSmith);
Department physics(drSmith);
}