Association, Aggregation & Composition

Association, Aggregation & Composition

Association tells about the relationship of one class with another. It generally implies "HAS-A" relationship between two classes. For example, consider two classes:

  1. Car

  2. Driver

then, there is an association between these two classes because Car has a Driver.

Consider another example:

  1. Car

  2. Engine

then, there is an association between these two classes because Car has an engine.


Association is further divided into two sub parts depending upon the type of bonds:

  1. Aggregation

  2. Composition

Aggregation implies a weak bond between two classes i.e. both the classes can exist independently. For example, classes Car and Driver can exist independently. There is no lifecycle dependency of classes on each other.

image.png

Composition implies a strong bond between two classes i.e. if one class is destroyed then other class is also destroyed. For example, if class Engine is destroyed then there is no existence of class Car. If there is no engine then alone car is of no use. There is a lifecycle dependency of one class on another.

image.png

Let us understand both concepts through code

-Aggregation

#include <iostream>
#include <string>
using namespace std;

class Driver {
  string name;
  int age;

public:
  // Constructor
  Driver(string name, int age) {
    this->name = name;
    this->age = age;
  }

  void printDriverInfo() {
    cout << "Name of Driver - " << name << endl;
    cout << "Age - " << age << endl;
  }

  // Destructor
  ~Driver() { cout << "Driver object destroyed" << endl; }
};

class Car {
  string name;
  int noOfWheels;
  Driver *driver;

public:
  // Constructor
  Car(string name, int noOfWheels, Driver *driver) {
    this->name = name;
    this->noOfWheels = noOfWheels;
    this->driver = driver;
  }

  void printCarInfo() {
    cout << "Name of Car - " << name << endl;
    cout << "No of wheels - " << noOfWheels << endl;
    cout << "\n";
    driver->printDriverInfo();
    cout << "\n";
  }

  // Destructor
  ~Car() { cout << "Car object destroyed" << endl; }
};

int main() {

  // initializing Driver object
  Driver *driver = new Driver("Rahul", 26);

  /* Created the Car object inside a block so that it
  is destroyed as soon as the block exits */
  {
    Car car("Verna", 4, driver);
    car.printCarInfo();
  } // Car object destroyed here

  // Driver object still exists even after Car object is destroyed
  cout << "\nDriver object still exists -\n";
  driver->printDriverInfo();

  return 0;
}

In the above example, when the Car object is destroyed, the Driver object still exists and we can access the Driver class member variables.

OUTPUT-


-Composition

#include <iostream>
#include <string>
using namespace std;

class Engine {
  string type;
  int id;

public:
  // Constructor
  Engine(string type, int id) {
    this->type = type;
    this->id = id;
  }

  void printEngineInfo() {
    cout << "Engine Type - " << type << endl;
    cout << "Engine ID - " << id << endl;
  }

  // Destructor
  ~Engine() { cout << "Engine object destroyed" << endl; }
};

class Car {
  string name;
  int noOfWheels;
  // Engine object is created as a member variable
  Engine engine;

public:
  // Constructor
  Car(string name, int noOfWheels) : engine("Diesel", 142) {
    this->name = name;
    this->noOfWheels = noOfWheels;
  }

  void printCarInfo() {
    cout << "Name of Car - " << name << endl;
    cout << "No of wheels - " << noOfWheels << endl;
    cout << "\n";
    cout << "Engine Info - " << endl;
    // can access Engine member variables from within Car class only
    engine.printEngineInfo();
  }

  // Destructor
  ~Car() { cout << "Car object destroyed" << endl; }
};

int main() {
  /* Created the Car object inside a block so that it
    is destroyed as soon as the block exits */
  {
    Car car("Verna", 4);
    car.printCarInfo();
    cout << "\n";
  } // Both Car and Engine objects are destroyed simultaneously

  // printing a message to see if both Engine and Car objects are destroyed
  // before this
  cout << "Both objects destroyed" << endl;

  return 0;
}

In the above example, when the Car object is destroyed, the Engine object is also destroyed which depicts that when the engine is no more the car is of no use.

OUTPUT-