cpp

exercises

exercises.cpp⚙️
/**
 * Classes in C++ - Exercises
 * 
 * Practice problems for understanding classes and OOP basics.
 * Each exercise includes TODO sections to complete.
 * 
 * Compile: g++ -std=c++17 -Wall -Wextra exercises.cpp -o exercises
 * Run: ./exercises
 */

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

// ============================================================
// Exercise 1: Create a Simple Class ⭐
// ============================================================
/**
 * Create a Rectangle class with width and height,
 * and methods to calculate area and perimeter.
 */

// TODO: Define the Rectangle class here
class Rectangle {
    // TODO: Add private members: width, height (both double)
    
public:
    // TODO: Add constructor that takes width and height
    
    // TODO: Add getArea() method
    
    // TODO: Add getPerimeter() method
    
    // TODO: Add print() method to display dimensions
    
};

void exercise1() {
    // TODO: Uncomment when Rectangle is implemented
    /*
    Rectangle r(5.0, 3.0);
    r.print();
    cout << "Area: " << r.getArea() << " (expected: 15)" << endl;
    cout << "Perimeter: " << r.getPerimeter() << " (expected: 16)" << endl;
    */
    cout << "(Implement Rectangle class to see results)" << endl;
}

// ============================================================
// Exercise 2: Constructors and Destructors ⭐⭐
// ============================================================
/**
 * Create a Message class that prints when it's created/destroyed.
 */

class Message {
private:
    string text;
    int id;
    static int nextId;
    
public:
    // TODO: Constructor that takes text, assigns unique id
    // Should print: "Message X created: <text>"
    Message(const string& t) : text(t), id(0) {
        // Fix this
    }
    
    // TODO: Destructor
    // Should print: "Message X destroyed: <text>"
    ~Message() {
        // Add code
    }
    
    void display() const {
        cout << "[" << id << "] " << text << endl;
    }
};

int Message::nextId = 1;

void exercise2() {
    cout << "Creating messages:" << endl;
    {
        Message m1("Hello");
        Message m2("World");
        m1.display();
        m2.display();
        cout << "Leaving scope:" << endl;
    }
    cout << "After scope" << endl;
}

// ============================================================
// Exercise 3: Copy Constructor ⭐⭐
// ============================================================
/**
 * Implement a proper copy constructor for a class with dynamic memory.
 */

class IntArray {
private:
    int* data;
    int size;
    
public:
    IntArray(int s) : size(s) {
        data = new int[size];
        for (int i = 0; i < size; i++) {
            data[i] = 0;
        }
    }
    
    // TODO: Implement copy constructor (deep copy)
    IntArray(const IntArray& other) : size(0), data(nullptr) {
        // Deep copy: allocate new array and copy values
    }
    
    ~IntArray() {
        delete[] data;
    }
    
    void set(int index, int value) {
        if (index >= 0 && index < size) {
            data[index] = value;
        }
    }
    
    int get(int index) const {
        if (index >= 0 && index < size) {
            return data[index];
        }
        return 0;
    }
    
    int getSize() const { return size; }
    
    void print() const {
        cout << "[";
        for (int i = 0; i < size; i++) {
            cout << data[i];
            if (i < size - 1) cout << ", ";
        }
        cout << "]" << endl;
    }
};

void exercise3() {
    IntArray arr1(5);
    arr1.set(0, 10);
    arr1.set(1, 20);
    arr1.set(2, 30);
    
    cout << "Original array: ";
    arr1.print();
    
    // Copy
    IntArray arr2 = arr1;
    cout << "Copied array: ";
    arr2.print();
    
    // Modify original
    arr1.set(0, 999);
    
    cout << "\nAfter modifying original:" << endl;
    cout << "Original: ";
    arr1.print();
    cout << "Copy: ";
    arr2.print();
    cout << "(Copy should be unchanged if deep copy works)" << endl;
}

// ============================================================
// Exercise 4: Static Members ⭐⭐
// ============================================================
/**
 * Create a class that tracks how many instances exist.
 */

class Counter {
private:
    int value;
    // TODO: Add static member to count instances
    
public:
    Counter(int v = 0) : value(v) {
        // TODO: Increment instance count
    }
    
    ~Counter() {
        // TODO: Decrement instance count
    }
    
    // TODO: Add static method getInstanceCount()
    
    int getValue() const { return value; }
};

// TODO: Define static member outside class

void exercise4() {
    cout << "Initial count: " << 0 << " (expected: 0)" << endl;  // Fix
    
    {
        Counter c1(10);
        Counter c2(20);
        cout << "After creating 2: " << 0 << " (expected: 2)" << endl;  // Fix
        
        Counter c3 = c1;
        cout << "After copying: " << 0 << " (expected: 3)" << endl;  // Fix
    }
    
    cout << "After scope: " << 0 << " (expected: 0)" << endl;  // Fix
}

// ============================================================
// Exercise 5: Method Chaining ⭐⭐
// ============================================================
/**
 * Implement a StringBuilder class with method chaining.
 */

class StringBuilder {
private:
    string content;
    
public:
    StringBuilder() : content("") {}
    
    // TODO: Implement append() that returns *this
    StringBuilder& append(const string& str) {
        // Add str to content
        return *this;  // Fix if needed
    }
    
    // TODO: Implement appendLine() that appends with newline
    StringBuilder& appendLine(const string& str) {
        return *this;  // Fix
    }
    
    // TODO: Implement clear()
    StringBuilder& clear() {
        return *this;  // Fix
    }
    
    string toString() const { return content; }
    int length() const { return content.length(); }
};

void exercise5() {
    StringBuilder sb;
    
    sb.append("Hello")
      .append(" ")
      .append("World")
      .appendLine("!")
      .append("This is a new line.");
    
    cout << "Result:" << endl;
    cout << sb.toString() << endl;
    cout << "Length: " << sb.length() << endl;
}

// ============================================================
// Exercise 6: Const Correctness ⭐⭐
// ============================================================
/**
 * Fix the const-correctness issues in this class.
 */

class Temperature {
private:
    double celsius;
    
public:
    Temperature(double c) : celsius(c) {}
    
    // TODO: Fix these methods - add 'const' where appropriate
    
    double getCelsius() { return celsius; }  // Should be const?
    
    double getFahrenheit() { return celsius * 9.0 / 5.0 + 32; }  // Should be const?
    
    double getKelvin() { return celsius + 273.15; }  // Should be const?
    
    void setCelsius(double c) { celsius = c; }  // Should be const?
    
    void display() {  // Should be const?
        cout << celsius << "°C = " << getFahrenheit() << "°F = " << getKelvin() << "K" << endl;
    }
};

void exercise6() {
    Temperature t(25.0);
    t.display();
    
    // This should work with proper const methods:
    const Temperature freezing(0.0);
    // TODO: Uncomment these when const-correctness is fixed
    // cout << "Freezing in F: " << freezing.getFahrenheit() << endl;
    // freezing.display();
}

// ============================================================
// Exercise 7: Bank Account Class ⭐⭐⭐
// ============================================================
/**
 * Create a complete BankAccount class.
 */

class BankAccount {
private:
    string accountNumber;
    string ownerName;
    double balance;
    // TODO: Add static member for next account number
    
public:
    // TODO: Constructor - auto-generate account number
    BankAccount(const string& owner, double initial = 0.0) 
        : accountNumber("000000"), ownerName(owner), balance(initial) {
        // Generate account number like "ACC001", "ACC002", etc.
    }
    
    // TODO: Implement deposit (validate positive amount)
    bool deposit(double amount) {
        return false;  // Fix
    }
    
    // TODO: Implement withdraw (validate sufficient balance)
    bool withdraw(double amount) {
        return false;  // Fix
    }
    
    // TODO: Implement transfer to another account
    bool transfer(BankAccount& other, double amount) {
        return false;  // Fix
    }
    
    // Getters
    string getAccountNumber() const { return accountNumber; }
    string getOwnerName() const { return ownerName; }
    double getBalance() const { return balance; }
    
    void display() const {
        cout << "Account: " << accountNumber << endl;
        cout << "Owner: " << ownerName << endl;
        cout << "Balance: $" << balance << endl;
    }
};

// TODO: Initialize static member

void exercise7() {
    BankAccount acc1("Alice", 1000.0);
    BankAccount acc2("Bob", 500.0);
    
    cout << "Initial state:" << endl;
    acc1.display();
    cout << endl;
    acc2.display();
    
    cout << "\nAlice deposits $200:" << endl;
    acc1.deposit(200);
    cout << "Alice's balance: $" << acc1.getBalance() << endl;
    
    cout << "\nBob withdraws $100:" << endl;
    acc2.withdraw(100);
    cout << "Bob's balance: $" << acc2.getBalance() << endl;
    
    cout << "\nAlice transfers $300 to Bob:" << endl;
    acc1.transfer(acc2, 300);
    cout << "Alice's balance: $" << acc1.getBalance() << endl;
    cout << "Bob's balance: $" << acc2.getBalance() << endl;
}

// ============================================================
// Exercise 8: Circle Class ⭐⭐
// ============================================================
/**
 * Create a Circle class with proper encapsulation.
 */

class Circle {
    // TODO: Add private radius member
    
public:
    // TODO: Static constant for PI
    
    // TODO: Constructor with default radius of 1.0
    
    // TODO: Getter and setter for radius (validate positive)
    
    // TODO: getArea() method
    
    // TODO: getCircumference() method
    
    // TODO: scale() method that multiplies radius by factor
    
};

void exercise8() {
    // TODO: Uncomment when Circle is implemented
    /*
    Circle c1;  // Default radius
    cout << "Default circle area: " << c1.getArea() << endl;
    
    Circle c2(5.0);
    cout << "Circle (r=5) area: " << c2.getArea() << endl;
    cout << "Circle (r=5) circumference: " << c2.getCircumference() << endl;
    
    c2.scale(2.0);
    cout << "After scaling by 2, area: " << c2.getArea() << endl;
    */
    cout << "(Implement Circle class to see results)" << endl;
}

// ============================================================
// Exercise 9: Date Class ⭐⭐⭐
// ============================================================
/**
 * Create a Date class with validation.
 */

class Date {
private:
    int day, month, year;
    
    // TODO: Static method to check if year is leap year
    static bool isLeapYear(int y) {
        return false;  // Fix
    }
    
    // TODO: Static method to get days in month
    static int daysInMonth(int m, int y) {
        return 30;  // Fix
    }
    
    // TODO: Method to validate date
    bool isValid() const {
        return true;  // Fix
    }
    
public:
    Date(int d, int m, int y) : day(d), month(m), year(y) {
        if (!isValid()) {
            cout << "Invalid date! Setting to 1/1/2000" << endl;
            day = 1; month = 1; year = 2000;
        }
    }
    
    void display() const {
        cout << day << "/" << month << "/" << year << endl;
    }
    
    // TODO: Implement addDays() method
    void addDays(int days) {
        // Add 'days' to the date, handling month/year overflow
    }
};

void exercise9() {
    Date d1(15, 6, 2024);
    cout << "Date 1: ";
    d1.display();
    
    Date d2(31, 2, 2024);  // Invalid - Feb doesn't have 31 days
    cout << "Date 2: ";
    d2.display();
    
    Date d3(29, 2, 2024);  // Valid - 2024 is leap year
    cout << "Date 3: ";
    d3.display();
}

// ============================================================
// Exercise 10: Student Class ⭐⭐⭐
// ============================================================
/**
 * Create a Student class with grades management.
 */

class Student {
private:
    string name;
    int id;
    double grades[10];  // Fixed size for simplicity
    int gradeCount;
    static int nextId;
    
public:
    // TODO: Constructor
    Student(const string& n) : name(n), id(0), gradeCount(0) {
        // Initialize grades array
    }
    
    // TODO: Add a grade (validate 0-100 range)
    bool addGrade(double grade) {
        return false;  // Fix
    }
    
    // TODO: Calculate average
    double getAverage() const {
        return 0.0;  // Fix
    }
    
    // TODO: Get letter grade based on average
    char getLetterGrade() const {
        // A: 90+, B: 80-89, C: 70-79, D: 60-69, F: <60
        return 'F';  // Fix
    }
    
    void display() const {
        cout << "Student: " << name << " (ID: " << id << ")" << endl;
        cout << "Grades: ";
        for (int i = 0; i < gradeCount; i++) {
            cout << grades[i] << " ";
        }
        cout << endl;
        cout << "Average: " << getAverage() << " (" << getLetterGrade() << ")" << endl;
    }
};

int Student::nextId = 1000;

void exercise10() {
    Student s("John Doe");
    s.addGrade(85);
    s.addGrade(92);
    s.addGrade(78);
    s.addGrade(88);
    s.addGrade(95);
    
    s.display();
}

// ============================================================
// Exercise 11: Time Class ⭐⭐
// ============================================================
/**
 * Create a Time class with hours, minutes, seconds.
 */

class Time {
private:
    int hours, minutes, seconds;
    
    // Helper to normalize time
    void normalize() {
        // TODO: Handle overflow (e.g., 90 seconds -> 1 min 30 sec)
    }
    
public:
    Time(int h = 0, int m = 0, int s = 0) 
        : hours(h), minutes(m), seconds(s) {
        normalize();
    }
    
    // TODO: Add seconds to time
    void addSeconds(int s) {
        // Add seconds and normalize
    }
    
    // TODO: Add minutes to time
    void addMinutes(int m) {
        // Add minutes and normalize
    }
    
    // TODO: Convert to total seconds
    int toSeconds() const {
        return 0;  // Fix
    }
    
    void display() const {
        cout << (hours < 10 ? "0" : "") << hours << ":"
             << (minutes < 10 ? "0" : "") << minutes << ":"
             << (seconds < 10 ? "0" : "") << seconds << endl;
    }
};

void exercise11() {
    Time t(1, 30, 45);
    cout << "Initial time: ";
    t.display();
    
    t.addSeconds(30);
    cout << "After adding 30 seconds: ";
    t.display();
    
    t.addMinutes(45);
    cout << "After adding 45 minutes: ";
    t.display();
    
    cout << "Total seconds: " << t.toSeconds() << endl;
}

// ============================================================
// Exercise 12: Car Class ⭐⭐
// ============================================================
/**
 * Create a Car class with fuel management.
 */

class Car {
    // TODO: Add private members: make, model, fuelLevel, tankCapacity, mpg
    
public:
    // TODO: Constructor
    
    // TODO: refuel(gallons) - add fuel, don't exceed tank capacity
    
    // TODO: drive(miles) - consume fuel, return actual miles driven
    
    // TODO: getFuelLevel() and getRange() methods
    
    // TODO: display() method
};

void exercise12() {
    // TODO: Uncomment when Car is implemented
    /*
    Car car("Toyota", "Camry", 15.0, 30.0);  // 15 gal tank, 30 mpg
    car.display();
    
    car.refuel(10.0);  // Add 10 gallons
    cout << "After refueling: " << car.getFuelLevel() << " gallons" << endl;
    cout << "Range: " << car.getRange() << " miles" << endl;
    
    double driven = car.drive(150);  // Try to drive 150 miles
    cout << "Actually drove: " << driven << " miles" << endl;
    cout << "Fuel remaining: " << car.getFuelLevel() << " gallons" << endl;
    */
    cout << "(Implement Car class to see results)" << endl;
}

// ============================================================
// TEST RUNNER
// ============================================================

int main() {
    cout << "╔════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                    CLASSES - EXERCISES                     ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════╝" << endl;
    
    cout << "\n=== Exercise 1: Simple Class ===" << endl;
    exercise1();
    
    cout << "\n=== Exercise 2: Constructors/Destructors ===" << endl;
    exercise2();
    
    cout << "\n=== Exercise 3: Copy Constructor ===" << endl;
    exercise3();
    
    cout << "\n=== Exercise 4: Static Members ===" << endl;
    exercise4();
    
    cout << "\n=== Exercise 5: Method Chaining ===" << endl;
    exercise5();
    
    cout << "\n=== Exercise 6: Const Correctness ===" << endl;
    exercise6();
    
    cout << "\n=== Exercise 7: Bank Account ===" << endl;
    exercise7();
    
    cout << "\n=== Exercise 8: Circle Class ===" << endl;
    exercise8();
    
    cout << "\n=== Exercise 9: Date Class ===" << endl;
    exercise9();
    
    cout << "\n=== Exercise 10: Student Class ===" << endl;
    exercise10();
    
    cout << "\n=== Exercise 11: Time Class ===" << endl;
    exercise11();
    
    cout << "\n=== Exercise 12: Car Class ===" << endl;
    exercise12();
    
    cout << "\n╔════════════════════════════════════════════════════════════╗" << endl;
    cout << "║         Complete the TODO sections and re-run!             ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════╝" << endl;
    
    return 0;
}

// ============================================================
// ANSWER KEY
// ============================================================
/*
// Exercise 1: Rectangle
class Rectangle {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double getArea() const { return width * height; }
    double getPerimeter() const { return 2 * (width + height); }
    void print() const { cout << "Rectangle: " << width << " x " << height << endl; }
};

// Exercise 2: Message
Message(const string& t) : text(t), id(nextId++) {
    cout << "Message " << id << " created: " << text << endl;
}
~Message() {
    cout << "Message " << id << " destroyed: " << text << endl;
}

// Exercise 3: Copy Constructor
IntArray(const IntArray& other) : size(other.size) {
    data = new int[size];
    for (int i = 0; i < size; i++) {
        data[i] = other.data[i];
    }
}

// Exercise 4: Static Members
private:
    static int instanceCount;
Counter(int v = 0) : value(v) { instanceCount++; }
~Counter() { instanceCount--; }
static int getInstanceCount() { return instanceCount; }
int Counter::instanceCount = 0;

// Exercise 5: StringBuilder
StringBuilder& append(const string& str) { content += str; return *this; }
StringBuilder& appendLine(const string& str) { content += str + "\n"; return *this; }
StringBuilder& clear() { content = ""; return *this; }

// Exercise 6: Add 'const' to getCelsius, getFahrenheit, getKelvin, display

// Exercise 7: BankAccount
static int nextAccNum;
BankAccount(...) : accountNumber("ACC" + to_string(nextAccNum++)), ...
bool deposit(double amount) {
    if (amount > 0) { balance += amount; return true; }
    return false;
}
bool withdraw(double amount) {
    if (amount > 0 && amount <= balance) { balance -= amount; return true; }
    return false;
}
bool transfer(BankAccount& other, double amount) {
    if (withdraw(amount)) { other.deposit(amount); return true; }
    return false;
}

// Exercise 8: Circle
private:
    double radius;
public:
    static constexpr double PI = 3.14159265359;
    Circle(double r = 1.0) : radius(r > 0 ? r : 1.0) {}
    double getRadius() const { return radius; }
    void setRadius(double r) { if (r > 0) radius = r; }
    double getArea() const { return PI * radius * radius; }
    double getCircumference() const { return 2 * PI * radius; }
    void scale(double factor) { if (factor > 0) radius *= factor; }

// Exercise 9: Date
static bool isLeapYear(int y) {
    return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
static int daysInMonth(int m, int y) {
    int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
    if (m == 2 && isLeapYear(y)) return 29;
    return days[m-1];
}
bool isValid() const {
    if (month < 1 || month > 12) return false;
    if (day < 1 || day > daysInMonth(month, year)) return false;
    return true;
}

// Exercise 10: Student
Student(const string& n) : name(n), id(nextId++), gradeCount(0) {
    for (int i = 0; i < 10; i++) grades[i] = 0;
}
bool addGrade(double grade) {
    if (gradeCount < 10 && grade >= 0 && grade <= 100) {
        grades[gradeCount++] = grade;
        return true;
    }
    return false;
}
double getAverage() const {
    if (gradeCount == 0) return 0;
    double sum = 0;
    for (int i = 0; i < gradeCount; i++) sum += grades[i];
    return sum / gradeCount;
}
char getLetterGrade() const {
    double avg = getAverage();
    if (avg >= 90) return 'A';
    if (avg >= 80) return 'B';
    if (avg >= 70) return 'C';
    if (avg >= 60) return 'D';
    return 'F';
}

// Exercise 11: Time
void normalize() {
    minutes += seconds / 60;
    seconds %= 60;
    hours += minutes / 60;
    minutes %= 60;
}
void addSeconds(int s) { seconds += s; normalize(); }
void addMinutes(int m) { minutes += m; normalize(); }
int toSeconds() const { return hours * 3600 + minutes * 60 + seconds; }

// Exercise 12: Car
class Car {
    string make, model;
    double fuelLevel, tankCapacity, mpg;
public:
    Car(string mk, string md, double tank, double m)
        : make(mk), model(md), fuelLevel(0), tankCapacity(tank), mpg(m) {}
    void refuel(double gallons) {
        fuelLevel = min(fuelLevel + gallons, tankCapacity);
    }
    double drive(double miles) {
        double fuelNeeded = miles / mpg;
        if (fuelNeeded > fuelLevel) {
            double actualMiles = fuelLevel * mpg;
            fuelLevel = 0;
            return actualMiles;
        }
        fuelLevel -= fuelNeeded;
        return miles;
    }
    double getFuelLevel() const { return fuelLevel; }
    double getRange() const { return fuelLevel * mpg; }
};
*/
Exercises - C++ Tutorial | DeepML