cpp

exercises

exercises.cpp⚙️
/**
 * Inheritance in C++ - Exercises
 * 
 * Practice problems for understanding inheritance concepts.
 * 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 <vector>
#include <cmath>

using namespace std;

// ============================================================
// Exercise 1: Basic Inheritance ⭐
// ============================================================
/**
 * Create a Dog class that inherits from Animal.
 */

class Animal {
protected:
    string name;
    int age;
    
public:
    Animal(const string& n, int a) : name(n), age(a) {}
    
    void eat() const {
        cout << "  " << name << " is eating" << endl;
    }
    
    void sleep() const {
        cout << "  " << name << " is sleeping" << endl;
    }
    
    string getName() const { return name; }
};

// TODO: Create Dog class that inherits from Animal
// Add: breed member, bark() method, displayInfo() method

void exercise1() {
    // TODO: Uncomment when Dog is implemented
    /*
    Dog dog("Buddy", 3, "Labrador");
    dog.eat();       // Inherited
    dog.sleep();     // Inherited
    dog.bark();      // Dog-specific
    dog.displayInfo();
    */
    cout << "(Implement Dog class)" << endl;
}

// ============================================================
// Exercise 2: Constructor Chaining ⭐⭐
// ============================================================
/**
 * Create a hierarchy: Person -> Student -> GraduateStudent
 * Each constructor should call the parent constructor.
 */

class Person2 {
protected:
    string name;
    int age;
    
public:
    Person2(const string& n, int a) : name(n), age(a) {
        cout << "  Person2 constructor" << endl;
    }
    
    virtual ~Person2() {
        cout << "  Person2 destructor" << endl;
    }
    
    virtual void introduce() const {
        cout << "  I am " << name << ", " << age << " years old" << endl;
    }
};

// TODO: Create Student2 class with studentId
class Student2 : public Person2 {
    // Add: studentId member
    // Constructor should call Person2 constructor
    
public:
    Student2(const string& n, int a, const string& id) 
        : Person2(n, a) {  // Fix: add studentId initialization
        cout << "  Student2 constructor" << endl;
    }
    
    ~Student2() override {
        cout << "  Student2 destructor" << endl;
    }
};

// TODO: Create GraduateStudent class with thesis topic
class GraduateStudent : public Student2 {
public:
    GraduateStudent(const string& n, int a, const string& id, const string& thesis)
        : Student2(n, a, id) {  // Fix: add thesis initialization
        cout << "  GraduateStudent constructor" << endl;
    }
    
    ~GraduateStudent() override {
        cout << "  GraduateStudent destructor" << endl;
    }
};

void exercise2() {
    cout << "Creating GraduateStudent:" << endl;
    {
        GraduateStudent gs("Alice", 25, "G12345", "Machine Learning");
        gs.introduce();
    }
    cout << "After scope" << endl;
}

// ============================================================
// Exercise 3: Method Overriding ⭐⭐
// ============================================================
/**
 * Override the speak() method in different animal classes.
 */

class AnimalBase {
public:
    virtual void speak() const {
        cout << "  Animal makes a sound" << endl;
    }
    
    virtual ~AnimalBase() = default;
};

// TODO: Create Cat class that overrides speak() to say "Meow!"
class Cat : public AnimalBase {
public:
    // Override speak()
};

// TODO: Create Cow class that overrides speak() to say "Moo!"
class Cow : public AnimalBase {
public:
    // Override speak()
};

// TODO: Create Duck class that overrides speak() to say "Quack!"
class Duck : public AnimalBase {
public:
    // Override speak()
};

void exercise3() {
    vector<AnimalBase*> animals;
    
    // TODO: Uncomment when classes are implemented
    /*
    animals.push_back(new Cat());
    animals.push_back(new Cow());
    animals.push_back(new Duck());
    
    for (AnimalBase* a : animals) {
        a->speak();
    }
    
    for (AnimalBase* a : animals) {
        delete a;
    }
    */
    cout << "(Implement Cat, Cow, Duck classes)" << endl;
}

// ============================================================
// Exercise 4: Calling Base Class Method ⭐⭐
// ============================================================
/**
 * Create derived classes that extend (not replace) base functionality.
 */

class Printer {
public:
    virtual void print(const string& text) const {
        cout << text << endl;
    }
    
    virtual ~Printer() = default;
};

// TODO: Create DecoratedPrinter that adds "*** " before and " ***" after
class DecoratedPrinter : public Printer {
public:
    void print(const string& text) const override {
        // Call base print with decorated text
        cout << "(Implement decorated print)" << endl;
    }
};

// TODO: Create UppercasePrinter that converts to uppercase
// Hint: Use toupper() in a loop
class UppercasePrinter : public Printer {
public:
    void print(const string& text) const override {
        // Convert to uppercase and call base print
        cout << "(Implement uppercase print)" << endl;
    }
};

void exercise4() {
    Printer basic;
    DecoratedPrinter decorated;
    UppercasePrinter upper;
    
    cout << "Basic: ";
    basic.print("Hello World");
    
    cout << "Decorated: ";
    decorated.print("Hello World");
    
    cout << "Uppercase: ";
    upper.print("Hello World");
}

// ============================================================
// Exercise 5: Shape Hierarchy ⭐⭐⭐
// ============================================================
/**
 * Create a shape hierarchy with area() and perimeter() methods.
 */

class Shape {
public:
    virtual double area() const = 0;
    virtual double perimeter() const = 0;
    virtual string getName() const = 0;
    
    void display() const {
        cout << "  " << getName() << ": Area = " << area() 
             << ", Perimeter = " << perimeter() << endl;
    }
    
    virtual ~Shape() = default;
};

// TODO: Implement Rectangle
class Rectangle : public Shape {
private:
    double width, height;
    
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    // TODO: Implement area(), perimeter(), getName()
    double area() const override { return 0; }
    double perimeter() const override { return 0; }
    string getName() const override { return "Rectangle"; }
};

// TODO: Implement Circle
class Circle : public Shape {
private:
    double radius;
    
public:
    static constexpr double PI = 3.14159;
    
    Circle(double r) : radius(r) {}
    
    // TODO: Implement area(), perimeter(), getName()
    double area() const override { return 0; }
    double perimeter() const override { return 0; }
    string getName() const override { return "Circle"; }
};

// TODO: Implement Triangle
class Triangle : public Shape {
private:
    double a, b, c;  // Three sides
    
public:
    Triangle(double a, double b, double c) : a(a), b(b), c(c) {}
    
    // TODO: Implement area() using Heron's formula, perimeter(), getName()
    // Heron's: s = (a+b+c)/2, area = sqrt(s*(s-a)*(s-b)*(s-c))
    double area() const override { return 0; }
    double perimeter() const override { return 0; }
    string getName() const override { return "Triangle"; }
};

void exercise5() {
    vector<Shape*> shapes;
    shapes.push_back(new Rectangle(5, 3));
    shapes.push_back(new Circle(4));
    shapes.push_back(new Triangle(3, 4, 5));
    
    for (Shape* s : shapes) {
        s->display();
    }
    
    for (Shape* s : shapes) {
        delete s;
    }
}

// ============================================================
// Exercise 6: Protected Members ⭐⭐
// ============================================================
/**
 * Use protected members to share data with derived classes.
 */

class BankAccount {
protected:
    double balance;
    string accountNumber;
    
public:
    BankAccount(const string& accNum, double initial)
        : balance(initial), accountNumber(accNum) {}
    
    double getBalance() const { return balance; }
    
    virtual void display() const {
        cout << "  Account " << accountNumber << ": $" << balance << endl;
    }
    
    virtual ~BankAccount() = default;
};

// TODO: Create SavingsAccount with interest rate
// Add: applyInterest() method that adds interest to balance
class SavingsAccount : public BankAccount {
private:
    double interestRate;
    
public:
    SavingsAccount(const string& accNum, double initial, double rate)
        : BankAccount(accNum, initial), interestRate(rate) {}
    
    void applyInterest() {
        // TODO: Add interest to balance (balance is protected)
    }
    
    void display() const override {
        // TODO: Show account info plus interest rate
    }
};

// TODO: Create CheckingAccount with overdraft limit
class CheckingAccount : public BankAccount {
private:
    double overdraftLimit;
    
public:
    CheckingAccount(const string& accNum, double initial, double limit)
        : BankAccount(accNum, initial), overdraftLimit(limit) {}
    
    bool withdraw(double amount) {
        // TODO: Allow withdrawal up to balance + overdraftLimit
        return false;
    }
    
    void display() const override {
        // TODO: Show account info plus available credit
    }
};

void exercise6() {
    SavingsAccount savings("SAV001", 1000, 0.05);
    CheckingAccount checking("CHK001", 500, 200);
    
    cout << "Initial state:" << endl;
    savings.display();
    checking.display();
    
    cout << "\nAfter applying 5% interest:" << endl;
    savings.applyInterest();
    savings.display();
    
    cout << "\nWithdrawing $600 from checking (overdraft):" << endl;
    if (checking.withdraw(600)) {
        cout << "  Withdrawal successful" << endl;
    }
    checking.display();
}

// ============================================================
// Exercise 7: Multiple Inheritance ⭐⭐⭐
// ============================================================
/**
 * Create a class that inherits from multiple interfaces.
 */

class Drawable {
public:
    virtual void draw() const = 0;
    virtual ~Drawable() = default;
};

class Moveable {
public:
    virtual void move(int dx, int dy) = 0;
    virtual ~Moveable() = default;
};

class Resizable {
public:
    virtual void resize(double factor) = 0;
    virtual ~Resizable() = default;
};

// TODO: Create Sprite class that implements all three interfaces
class Sprite : public Drawable, public Moveable, public Resizable {
private:
    int x, y;
    int width, height;
    string name;
    
public:
    Sprite(const string& n, int x, int y, int w, int h)
        : x(x), y(y), width(w), height(h), name(n) {}
    
    // TODO: Implement draw(), move(), resize()
    void draw() const override {
        cout << "(Implement draw)" << endl;
    }
    
    void move(int dx, int dy) override {
        // Update x and y
    }
    
    void resize(double factor) override {
        // Scale width and height
    }
};

void exercise7() {
    Sprite sprite("Player", 100, 100, 32, 32);
    
    sprite.draw();
    sprite.move(10, 5);
    sprite.draw();
    sprite.resize(2.0);
    sprite.draw();
}

// ============================================================
// Exercise 8: Virtual Destructor ⭐⭐
// ============================================================
/**
 * Demonstrate why virtual destructors are important.
 */

class Resource {
protected:
    string name;
    
public:
    Resource(const string& n) : name(n) {
        cout << "  Resource '" << name << "' acquired" << endl;
    }
    
    // TODO: Make this virtual
    ~Resource() {
        cout << "  Resource '" << name << "' released" << endl;
    }
};

class FileResource : public Resource {
private:
    string filename;
    
public:
    FileResource(const string& n, const string& f) 
        : Resource(n), filename(f) {
        cout << "  FileResource opened: " << filename << endl;
    }
    
    ~FileResource() {
        cout << "  FileResource closed: " << filename << endl;
    }
};

void exercise8() {
    cout << "Creating through base pointer:" << endl;
    Resource* res = new FileResource("MyFile", "data.txt");
    
    cout << "\nDeleting through base pointer:" << endl;
    delete res;
    
    cout << "\n(Without virtual destructor, FileResource destructor won't be called!)" << endl;
    cout << "(Add 'virtual' to Resource::~Resource() to fix)" << endl;
}

// ============================================================
// Exercise 9: Abstract Class ⭐⭐⭐
// ============================================================
/**
 * Create an abstract Employee class and concrete implementations.
 */

class Employee {
protected:
    string name;
    int id;
    
public:
    Employee(const string& n, int i) : name(n), id(i) {}
    
    // TODO: Make these pure virtual
    virtual double calculatePay() const { return 0; }
    virtual string getType() const { return "Employee"; }
    
    void display() const {
        cout << "  " << getType() << " #" << id << ": " << name 
             << " - Pay: $" << calculatePay() << endl;
    }
    
    virtual ~Employee() = default;
};

// TODO: Create HourlyEmployee with hoursWorked and hourlyRate
class HourlyEmployee : public Employee {
public:
    HourlyEmployee(const string& n, int i, double hours, double rate)
        : Employee(n, i) {}
    
    // Pay = hours * rate
    double calculatePay() const override { return 0; }
    string getType() const override { return "Hourly"; }
};

// TODO: Create SalariedEmployee with annual salary
class SalariedEmployee : public Employee {
public:
    SalariedEmployee(const string& n, int i, double annual)
        : Employee(n, i) {}
    
    // Pay = annual / 12 (monthly)
    double calculatePay() const override { return 0; }
    string getType() const override { return "Salaried"; }
};

// TODO: Create CommissionEmployee with sales and commission rate
class CommissionEmployee : public Employee {
public:
    CommissionEmployee(const string& n, int i, double sales, double rate)
        : Employee(n, i) {}
    
    // Pay = sales * rate
    double calculatePay() const override { return 0; }
    string getType() const override { return "Commission"; }
};

void exercise9() {
    vector<Employee*> employees;
    employees.push_back(new HourlyEmployee("Alice", 101, 40, 25));
    employees.push_back(new SalariedEmployee("Bob", 102, 60000));
    employees.push_back(new CommissionEmployee("Charlie", 103, 50000, 0.1));
    
    cout << "Employee payroll:" << endl;
    double total = 0;
    for (Employee* e : employees) {
        e->display();
        total += e->calculatePay();
    }
    cout << "  Total payroll: $" << total << endl;
    
    for (Employee* e : employees) {
        delete e;
    }
}

// ============================================================
// Exercise 10: Final Keyword ⭐⭐
// ============================================================
/**
 * Use final to prevent further inheritance or overriding.
 */

class Base10 {
public:
    virtual void method1() {
        cout << "  Base10::method1" << endl;
    }
    
    virtual void method2() {
        cout << "  Base10::method2" << endl;
    }
    
    virtual ~Base10() = default;
};

// TODO: Create Derived10 that makes method1 final
class Derived10 : public Base10 {
public:
    // Make this final so it can't be overridden further
    void method1() override {
        cout << "  Derived10::method1" << endl;
    }
    
    void method2() override {
        cout << "  Derived10::method2" << endl;
    }
};

// TODO: Create FinalClass that cannot be inherited from
// Hint: class FinalClass final : public Base10 { }

void exercise10() {
    Derived10 d;
    d.method1();
    d.method2();
    
    cout << "\n(Try creating a class that inherits from FinalClass - it should fail)" << endl;
    cout << "(Try overriding method1 in a class derived from Derived10 - it should fail)" << endl;
}

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

int main() {
    cout << "╔════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                  INHERITANCE - EXERCISES                   ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════╝" << endl;
    
    cout << "\n=== Exercise 1: Basic Inheritance ===" << endl;
    exercise1();
    
    cout << "\n=== Exercise 2: Constructor Chaining ===" << endl;
    exercise2();
    
    cout << "\n=== Exercise 3: Method Overriding ===" << endl;
    exercise3();
    
    cout << "\n=== Exercise 4: Calling Base Method ===" << endl;
    exercise4();
    
    cout << "\n=== Exercise 5: Shape Hierarchy ===" << endl;
    exercise5();
    
    cout << "\n=== Exercise 6: Protected Members ===" << endl;
    exercise6();
    
    cout << "\n=== Exercise 7: Multiple Inheritance ===" << endl;
    exercise7();
    
    cout << "\n=== Exercise 8: Virtual Destructor ===" << endl;
    exercise8();
    
    cout << "\n=== Exercise 9: Abstract Class ===" << endl;
    exercise9();
    
    cout << "\n=== Exercise 10: Final Keyword ===" << endl;
    exercise10();
    
    cout << "\n╔════════════════════════════════════════════════════════════╗" << endl;
    cout << "║         Complete the TODO sections and re-run!             ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════╝" << endl;
    
    return 0;
}

// ============================================================
// ANSWER KEY
// ============================================================
/*
// Exercise 1: Dog
class Dog : public Animal {
    string breed;
public:
    Dog(const string& n, int a, const string& b) : Animal(n, a), breed(b) {}
    void bark() const { cout << "  " << name << " says: Woof!" << endl; }
    void displayInfo() const { 
        cout << "  " << name << " is a " << age << " year old " << breed << endl; 
    }
};

// Exercise 3: Cat, Cow, Duck
void speak() const override { cout << "  Meow!" << endl; }
void speak() const override { cout << "  Moo!" << endl; }
void speak() const override { cout << "  Quack!" << endl; }

// Exercise 4: DecoratedPrinter, UppercasePrinter
void print(const string& text) const override {
    Printer::print("*** " + text + " ***");
}
void print(const string& text) const override {
    string upper = text;
    for (char& c : upper) c = toupper(c);
    Printer::print(upper);
}

// Exercise 5: Shape implementations
// Rectangle
double area() const override { return width * height; }
double perimeter() const override { return 2 * (width + height); }

// Circle
double area() const override { return PI * radius * radius; }
double perimeter() const override { return 2 * PI * radius; }

// Triangle
double area() const override {
    double s = (a + b + c) / 2;
    return sqrt(s * (s-a) * (s-b) * (s-c));
}
double perimeter() const override { return a + b + c; }

// Exercise 6: SavingsAccount, CheckingAccount
void applyInterest() { balance += balance * interestRate; }
void display() const override {
    BankAccount::display();
    cout << "    Interest rate: " << (interestRate * 100) << "%" << endl;
}
bool withdraw(double amount) {
    if (amount <= balance + overdraftLimit) {
        balance -= amount;
        return true;
    }
    return false;
}

// Exercise 7: Sprite
void draw() const override {
    cout << "  Drawing " << name << " at (" << x << ", " << y 
         << ") size " << width << "x" << height << endl;
}
void move(int dx, int dy) override { x += dx; y += dy; }
void resize(double factor) override {
    width = static_cast<int>(width * factor);
    height = static_cast<int>(height * factor);
}

// Exercise 8: Add 'virtual' to ~Resource()

// Exercise 9: Employee subclasses
class HourlyEmployee : public Employee {
    double hours, rate;
public:
    HourlyEmployee(const string& n, int i, double h, double r)
        : Employee(n, i), hours(h), rate(r) {}
    double calculatePay() const override { return hours * rate; }
};
// Similar for Salaried (annual/12) and Commission (sales*rate)

// Exercise 10: Final
void method1() final { ... }
class FinalClass final : public Base10 { ... };
*/
Exercises - C++ Tutorial | DeepML