Introduction to C++ | Aggregation

C++ Aggregation

Aggregation is a type of association in object-oriented programming (OOP) where one object contains another object, but both objects can exist independently. Aggregation represents a "has-a" relationship between two classes. It is a weaker form of association compared to composition, where the lifetime of the contained object depends on the containing object.

What is Aggregation?

In aggregation, the child object can exist independently of the parent object. For example, a "Department" class can have many "Employee" objects, but the employee objects can exist independently of the department. If the department object is destroyed, the employee objects will still exist.

Characteristics of Aggregation

  • It represents a "has-a" relationship.
  • The lifetime of the contained object does not depend on the container object.
  • Aggregation is used when objects are related but can exist independently.

Aggregation vs Composition

Aggregation and composition are both forms of association, but there is a key difference between them:

  • Aggregation: The contained object can exist independently of the container object.
  • Composition: The contained object’s lifetime is tied to the lifetime of the container object. If the container object is destroyed, the contained object is also destroyed.

Syntax of Aggregation

In aggregation, one class has an object of another class as a data member. Here’s the syntax:

Syntax of Aggregation


            class ClassA {
                // ClassA members
            };
            
            class ClassB {
                ClassA objectA;  // ClassB "has-a" ClassA
                // ClassB members
            };
                        

Example of Aggregation

Here’s an example where an object of class Employee is part of another object of class Department, but can exist independently:

Code Example: Aggregation


            #include <iostream>
            using namespace std;
            
            // Class Employee
            class Employee {
            public:
                string name;
                int id;
                
                Employee(string n, int i) : name(n), id(i) {}
                
                void display() {
                    cout << "Employee Name: " << name << ", ID: " << id << endl;
                }
            };
            
            // Class Department
            class Department {
            public:
                string deptName;
                Employee* emp;  // Aggregation: Department has an Employee
            
                Department(string dName, Employee* e) : deptName(dName), emp(e) {}
            
                void display() {
                    cout << "Department: " << deptName << endl;
                    emp->display();
                }
            };
            
            int main() {
                Employee emp1("John Doe", 1001);  // Employee object is independent
                Department dept("IT", &emp1);     // Department aggregates Employee
                
                dept.display();
            
                return 0;
            }
                        

Output:

Department: IT
Employee Name: John Doe, ID: 1001

Explanation:

In this example, we have two classes: Employee and Department. The Department class contains an object of the Employee class, which represents the aggregation relationship. The Employee object can exist independently of the Department object, and the employee details are displayed by the department.

Real-World Example of Aggregation

A real-world example of aggregation is the relationship between a Library and Books. A library can have many books, but books can exist independently, as they can be placed in multiple libraries or be outside of a library.

Code Example: Real-World Aggregation


            #include <iostream>
            #include <vector>
            using namespace std;
            
            // Class Book
            class Book {
            public:
                string title;
                int bookId;
            
                Book(string t, int id) : title(t), bookId(id) {}
            
                void display() {
                    cout << "Book Title: " << title << ", Book ID: " << bookId << endl;
                }
            };
            
            // Class Library
            class Library {
            public:
                string name;
                vector<Book> books;  // Aggregation: Library has many Books
            
                Library(string n) : name(n) {}
            
                void addBook(Book b) {
                    books.push_back(b);
                }
            
                void display() {
                    cout << "Library: " << name << endl;
                    for (auto& book : books) {
                        book.display();
                    }
                }
            };
            
            int main() {
                Book b1("C++ Programming", 101);
                Book b2("Data Structures", 102);
            
                Library lib("Central Library");
                lib.addBook(b1);
                lib.addBook(b2);
            
                lib.display();
            
                return 0;
            }
                        

Output:

Library: Central Library
Book Title: C++ Programming, Book ID: 101
Book Title: Data Structures, Book ID: 102

Explanation:

In this example, a Library contains multiple Book objects. Books can exist independently of the library. Even if the library is destroyed, the books remain intact.

Pro Tip:

💡 Pro Tip

Aggregation is useful when the relationship between objects is one of ownership but not dependency. It allows flexibility, as objects in an aggregation can exist independently. However, be cautious when designing relationships between classes—ensure that the "has-a" relationship is the best fit for the problem you're trying to solve. If objects depend on each other’s lifecycle, consider using composition instead.