cpp

relationships

01_relationships.cpp⚙️
/**
 * ============================================================
 * C++ OBJECT RELATIONSHIPS
 * ============================================================
 * 
 * This file covers:
 * - Association (uses-a)
 * - Aggregation (has-a, weak)
 * - Composition (has-a, strong)
 * - Dependency (depends-on)
 * - Comparison of relationships
 * 
 * Compile: g++ -std=c++17 -Wall 01_relationships.cpp -o relationships
 * Run: ./relationships
 * 
 * ============================================================
 */

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <algorithm>  // ⚠️ LEARNING NOTE: This was missing!
                     // std::find() is in <algorithm>, not automatically available.
                     // Common STL algorithms need this header:
                     // find, sort, count, copy, transform, etc.

using namespace std;

// ============================================================
// PART 1: ASSOCIATION (USES-A)
// ============================================================
// - Objects are independent
// - Can exist without each other
// - Usually implemented via pointer/reference

class Course;  // Forward declaration

class Student {
private:
    string name;
    int id;
    vector<Course*> enrolledCourses;  // Association - doesn't own courses
    
public:
    Student(const string& n, int i) : name(n), id(i) {}
    
    void enroll(Course* course) {
        enrolledCourses.push_back(course);
    }
    
    void unenroll(Course* course) {
        auto it = find(enrolledCourses.begin(), enrolledCourses.end(), course);
        if (it != enrolledCourses.end()) {
            enrolledCourses.erase(it);
        }
    }
    
    string getName() const { return name; }
    int getId() const { return id; }
    size_t getCourseCount() const { return enrolledCourses.size(); }
    
    void listCourses() const;  // Defined after Course
};

class Course {
private:
    string code;
    string title;
    vector<Student*> students;  // Association - doesn't own students
    
public:
    Course(const string& c, const string& t) : code(c), title(t) {}
    
    void addStudent(Student* student) {
        students.push_back(student);
    }
    
    void removeStudent(Student* student) {
        auto it = find(students.begin(), students.end(), student);
        if (it != students.end()) {
            students.erase(it);
        }
    }
    
    string getCode() const { return code; }
    string getTitle() const { return title; }
    size_t getStudentCount() const { return students.size(); }
    
    void listStudents() const {
        cout << "Course " << code << ": " << title << endl;
        cout << "Students enrolled: " << students.size() << endl;
        for (const auto* s : students) {
            cout << "  - " << s->getName() << " (" << s->getId() << ")" << endl;
        }
    }
};

void Student::listCourses() const {
    cout << "Student: " << name << " (ID: " << id << ")" << endl;
    cout << "Enrolled in " << enrolledCourses.size() << " courses:" << endl;
    for (const auto* c : enrolledCourses) {
        cout << "  - " << c->getCode() << ": " << c->getTitle() << endl;
    }
}

// ============================================================
// PART 2: AGGREGATION (HAS-A, WEAK OWNERSHIP)
// ============================================================
// - Container has parts but doesn't own them
// - Parts can exist independently
// - Parts can be shared between containers

class Employee {
private:
    string name;
    int id;
    
public:
    Employee(const string& n, int i) : name(n), id(i) {
        cout << "  Employee created: " << name << endl;
    }
    
    ~Employee() {
        cout << "  Employee destroyed: " << name << endl;
    }
    
    string getName() const { return name; }
    int getId() const { return id; }
};

class Department {
private:
    string name;
    vector<Employee*> employees;  // Aggregation - doesn't own employees
    
public:
    Department(const string& n) : name(n) {
        cout << "Department created: " << name << endl;
    }
    
    ~Department() {
        cout << "Department destroyed: " << name << endl;
        // Does NOT delete employees - they exist independently
    }
    
    void addEmployee(Employee* emp) {
        employees.push_back(emp);
        cout << "  Added " << emp->getName() << " to " << name << endl;
    }
    
    void removeEmployee(Employee* emp) {
        auto it = find(employees.begin(), employees.end(), emp);
        if (it != employees.end()) {
            employees.erase(it);
            cout << "  Removed " << emp->getName() << " from " << name << endl;
        }
    }
    
    void listEmployees() const {
        cout << "Department: " << name << endl;
        for (const auto* e : employees) {
            cout << "  - " << e->getName() << " (" << e->getId() << ")" << endl;
        }
    }
    
    string getName_() const { return name; }
};

// ============================================================
// PART 3: COMPOSITION (HAS-A, STRONG OWNERSHIP)
// ============================================================
// - Container owns its parts
// - Parts cannot exist independently
// - Parts destroyed when container destroyed

class Engine {
private:
    string type;
    int horsepower;
    
public:
    Engine(const string& t, int hp) : type(t), horsepower(hp) {
        cout << "    Engine created: " << type << ", " << hp << "hp" << endl;
    }
    
    ~Engine() {
        cout << "    Engine destroyed: " << type << endl;
    }
    
    void start() const { cout << "Engine starting: " << type << endl; }
    void stop() const { cout << "Engine stopping: " << type << endl; }
    string getType() const { return type; }
    int getHorsepower() const { return horsepower; }
};

class Wheel {
private:
    string brand;
    int size;
    
public:
    Wheel(const string& b, int s) : brand(b), size(s) {
        cout << "    Wheel created: " << brand << " " << s << "\"" << endl;
    }
    
    ~Wheel() {
        cout << "    Wheel destroyed: " << brand << endl;
    }
    
    void rotate() const { cout << "Wheel rotating" << endl; }
    string getBrand() const { return brand; }
};

class Car {
private:
    string model;
    Engine engine;          // Composition - owns the engine
    vector<Wheel> wheels;   // Composition - owns the wheels
    
public:
    Car(const string& m, const string& engineType, int hp,
        const string& wheelBrand, int wheelSize)
        : model(m), engine(engineType, hp) {
        cout << "  Creating Car: " << model << endl;
        
        // Create 4 wheels
        for (int i = 0; i < 4; i++) {
            wheels.emplace_back(wheelBrand, wheelSize);
        }
    }
    
    ~Car() {
        cout << "  Destroying Car: " << model << endl;
        // Engine and wheels automatically destroyed
    }
    
    void start() {
        cout << model << " starting..." << endl;
        engine.start();
    }
    
    void stop() {
        cout << model << " stopping..." << endl;
        engine.stop();
    }
    
    void displayInfo() const {
        cout << "Car: " << model << endl;
        cout << "  Engine: " << engine.getType() 
             << " (" << engine.getHorsepower() << "hp)" << endl;
        cout << "  Wheels: " << wheels.size() << " x " 
             << wheels[0].getBrand() << endl;
    }
};

// ============================================================
// PART 4: COMPOSITION WITH SMART POINTERS
// ============================================================

class Room {
private:
    string name;
    int area;
    
public:
    Room(const string& n, int a) : name(n), area(a) {
        cout << "      Room created: " << name << " (" << area << " sqft)" << endl;
    }
    
    ~Room() {
        cout << "      Room destroyed: " << name << endl;
    }
    
    string getName() const { return name; }
    int getArea() const { return area; }
};

class House {
private:
    string address;
    vector<unique_ptr<Room>> rooms;  // Composition with smart pointers
    
public:
    House(const string& addr) : address(addr) {
        cout << "    House created: " << address << endl;
    }
    
    ~House() {
        cout << "    House destroyed: " << address << endl;
        // Rooms automatically destroyed by unique_ptr
    }
    
    void addRoom(const string& name, int area) {
        rooms.push_back(make_unique<Room>(name, area));
    }
    
    void displayInfo() const {
        cout << "House at: " << address << endl;
        int totalArea = 0;
        for (const auto& room : rooms) {
            cout << "  - " << room->getName() << ": " << room->getArea() << " sqft" << endl;
            totalArea += room->getArea();
        }
        cout << "  Total area: " << totalArea << " sqft" << endl;
    }
};

// ============================================================
// PART 5: DEPENDENCY (DEPENDS-ON)
// ============================================================
// - Weakest relationship
// - Object uses another temporarily
// - Usually as function parameter

class Logger {
public:
    static void log(const string& message) {
        cout << "[LOG] " << message << endl;
    }
};

class Database {
public:
    bool connect(const string& connectionString) {
        Logger::log("Connecting to: " + connectionString);  // Dependency on Logger
        return true;
    }
    
    void query(const string& sql) {
        Logger::log("Executing: " + sql);  // Dependency on Logger
    }
};

class Formatter {
public:
    static string formatCurrency(double amount) {
        return "$" + to_string(amount);
    }
};

class Invoice {
public:
    void print(double amount) {
        // Dependency on Formatter - uses it but doesn't store
        cout << "Amount due: " << Formatter::formatCurrency(amount) << endl;
    }
};

// ============================================================
// MAIN FUNCTION
// ============================================================

int main() {
    cout << "============================================" << endl;
    cout << "     C++ OBJECT RELATIONSHIPS" << endl;
    cout << "============================================" << endl << endl;

    // ========================================================
    // DEMO 1: Association
    // ========================================================
    
    cout << "--- DEMO 1: ASSOCIATION ---" << endl << endl;
    
    Student alice("Alice", 1001);
    Student bob("Bob", 1002);
    
    Course cpp("CS101", "C++ Programming");
    Course db("CS201", "Database Systems");
    
    // Establish associations
    alice.enroll(&cpp);
    alice.enroll(&db);
    bob.enroll(&cpp);
    
    cpp.addStudent(&alice);
    cpp.addStudent(&bob);
    db.addStudent(&alice);
    
    alice.listCourses();
    cout << endl;
    cpp.listStudents();
    
    // Both can exist independently
    cout << "\n💡 Students and Courses exist independently" << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 2: Aggregation
    // ========================================================
    
    cout << "--- DEMO 2: AGGREGATION ---" << endl << endl;
    
    cout << "Creating employees:" << endl;
    Employee* emp1 = new Employee("John", 101);
    Employee* emp2 = new Employee("Jane", 102);
    Employee* emp3 = new Employee("Mike", 103);
    
    cout << "\nCreating departments:" << endl;
    {
        Department engineering("Engineering");
        Department marketing("Marketing");
        
        engineering.addEmployee(emp1);
        engineering.addEmployee(emp2);
        marketing.addEmployee(emp2);  // Jane works in both!
        marketing.addEmployee(emp3);
        
        cout << endl;
        engineering.listEmployees();
        cout << endl;
        marketing.listEmployees();
        
        cout << "\nDepartments going out of scope..." << endl;
    }
    
    cout << "\n💡 Employees still exist after departments are destroyed!" << endl;
    cout << "emp1 name: " << emp1->getName() << endl;
    
    // Clean up (in real code, would use smart pointers)
    delete emp1;
    delete emp2;
    delete emp3;
    
    cout << endl;

    // ========================================================
    // DEMO 3: Composition
    // ========================================================
    
    cout << "--- DEMO 3: COMPOSITION ---" << endl << endl;
    
    cout << "Creating a car (parts created with it):" << endl;
    {
        Car myCar("Tesla Model 3", "Electric Motor", 450, "Michelin", 18);
        
        cout << endl;
        myCar.displayInfo();
        cout << endl;
        myCar.start();
        myCar.stop();
        
        cout << "\nCar going out of scope..." << endl;
    }
    
    cout << "\n💡 Engine and wheels destroyed WITH the car!" << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 4: Composition with Smart Pointers
    // ========================================================
    
    cout << "--- DEMO 4: SMART POINTER COMPOSITION ---" << endl << endl;
    
    cout << "Creating a house:" << endl;
    {
        House myHouse("123 Main Street");
        myHouse.addRoom("Living Room", 400);
        myHouse.addRoom("Kitchen", 200);
        myHouse.addRoom("Bedroom", 250);
        myHouse.addRoom("Bathroom", 100);
        
        cout << endl;
        myHouse.displayInfo();
        
        cout << "\nHouse going out of scope..." << endl;
    }
    
    cout << "\n💡 Rooms destroyed automatically with house!" << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 5: Dependency
    // ========================================================
    
    cout << "--- DEMO 5: DEPENDENCY ---" << endl << endl;
    
    Database db2;
    db2.connect("localhost:5432/mydb");
    db2.query("SELECT * FROM users");
    
    Invoice invoice;
    invoice.print(199.99);
    
    cout << "\n💡 Database uses Logger, Invoice uses Formatter" << endl;
    cout << "   but neither stores or owns them!" << endl;
    
    cout << endl;

    // ========================================================
    // RELATIONSHIP COMPARISON
    // ========================================================
    
    cout << "--- RELATIONSHIP COMPARISON ---" << endl << endl;
    
    cout << "┌────────────┬───────────────────────────────────────────┐" << endl;
    cout << "│ Relation   │ Description                               │" << endl;
    cout << "├────────────┼───────────────────────────────────────────┤" << endl;
    cout << "│ Dependency │ Uses temporarily (function parameter)     │" << endl;
    cout << "│ Association│ Uses (pointer/ref, no ownership)          │" << endl;
    cout << "│ Aggregation│ Has-a, weak (parts can exist alone)       │" << endl;
    cout << "│ Composition│ Has-a, strong (parts die with whole)      │" << endl;
    cout << "│ Inheritance│ Is-a (derived from base)                  │" << endl;
    cout << "└────────────┴───────────────────────────────────────────┘" << endl;
    
    cout << "\nImplementation Patterns:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Dependency:   Parameter, local variable" << endl;
    cout << "• Association:  Raw pointer, reference" << endl;
    cout << "• Aggregation:  shared_ptr, raw pointer" << endl;
    cout << "• Composition:  Value, unique_ptr" << endl;
    
    cout << endl;

    cout << "============================================" << endl;
    cout << "OBJECT RELATIONSHIPS COMPLETE!" << endl;
    cout << "============================================" << endl;

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Design a Library System:
 *    - Association: Library ↔ Member
 *    - Aggregation: Library → Book (books can exist without library)
 *    - Composition: Book → Chapter (chapters die with book)
 * 
 * 2. Design a Computer:
 *    - Composition: Computer → CPU, RAM, Motherboard
 *    - Aggregation: Computer → Peripherals (keyboard, mouse)
 *    - Show proper lifetime management
 * 
 * 3. Design a Music Playlist:
 *    - Association: Playlist ↔ Song
 *    - A song can be in multiple playlists
 *    - Deleting playlist doesn't delete songs
 * 
 * 4. Design an Order System:
 *    - Composition: Order → OrderItem
 *    - Association: Order ↔ Customer
 *    - Dependency: Order uses PaymentProcessor
 */
Relationships - C++ Tutorial | DeepML