cpp

exercises

exercises.cpp⚙️
/**
 * Polymorphism - Exercises
 * Compile: g++ -std=c++17 -Wall exercises.cpp -o exercises
 */

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

// ============================================================
// Exercise 1: Basic Virtual Functions ⭐
// ============================================================

class Instrument {
public:
    virtual void play() const { cout << "  Playing instrument" << endl; }
    virtual ~Instrument() = default;
};

// TODO: Create Guitar class that plays "Strumming guitar"
// TODO: Create Piano class that plays "Playing piano keys"

void exercise1() {
    // Uncomment when done:
    // Guitar g; Piano p;
    // Instrument* instruments[] = {&g, &p};
    // for (auto* i : instruments) i->play();
    cout << "(Implement Guitar and Piano)" << endl;
}

// ============================================================
// Exercise 2: Abstract Shape Class ⭐⭐
// ============================================================

class Shape2D {
public:
    virtual double area() const = 0;
    virtual double perimeter() const = 0;
    virtual ~Shape2D() = default;
};

// TODO: Implement Square (side)
// TODO: Implement Triangle (base, height, side1, side2, side3)

void exercise2() {
    // Uncomment:
    // Square sq(5);
    // cout << "Square area: " << sq.area() << ", perimeter: " << sq.perimeter() << endl;
    cout << "(Implement Square and Triangle)" << endl;
}

// ============================================================
// Exercise 3: Virtual Destructor ⭐⭐
// ============================================================

class Connection {
public:
    Connection() { cout << "  Connection opened" << endl; }
    // TODO: Make this virtual
    ~Connection() { cout << "  Connection closed" << endl; }
};

class DatabaseConnection : public Connection {
public:
    DatabaseConnection() { cout << "  DB connected" << endl; }
    ~DatabaseConnection() { cout << "  DB disconnected" << endl; }
};

void exercise3() {
    Connection* c = new DatabaseConnection();
    delete c;  // Check if both destructors are called
}

// ============================================================
// Exercise 4: Interface Implementation ⭐⭐
// ============================================================

class Printable {
public:
    virtual void print() const = 0;
    virtual ~Printable() = default;
};

class Saveable {
public:
    virtual void save(const string& filename) const = 0;
    virtual ~Saveable() = default;
};

// TODO: Create Document class implementing both interfaces

void exercise4() {
    // Document doc("My Doc", "Content here");
    // doc.print();
    // doc.save("file.txt");
    cout << "(Implement Document class)" << endl;
}

// ============================================================
// Exercise 5: Dynamic Cast ⭐⭐⭐
// ============================================================

class Employee {
protected:
    string name;
public:
    Employee(const string& n) : name(n) {}
    virtual void work() const = 0;
    virtual ~Employee() = default;
};

class Developer : public Employee {
public:
    Developer(const string& n) : Employee(n) {}
    void work() const override { cout << "  " << name << " is coding" << endl; }
    void debug() const { cout << "  " << name << " is debugging" << endl; }
};

class Manager : public Employee {
public:
    Manager(const string& n) : Employee(n) {}
    void work() const override { cout << "  " << name << " is managing" << endl; }
    void meeting() const { cout << "  " << name << " is in a meeting" << endl; }
};

// TODO: Implement processEmployee that uses dynamic_cast
// If Developer, call debug(). If Manager, call meeting().
void processEmployee(Employee* e) {
    e->work();
    // TODO: Add dynamic_cast logic
}

void exercise5() {
    Developer dev("Alice");
    Manager mgr("Bob");
    processEmployee(&dev);
    processEmployee(&mgr);
}

// ============================================================
// Exercise 6: Polymorphic Container ⭐⭐
// ============================================================

// TODO: Create a zoo with different animals using unique_ptr
// Make all animals speak

void exercise6() {
    // vector<unique_ptr<Animal>> zoo;
    // Add animals, make them all speak
    cout << "(Create polymorphic zoo)" << endl;
}

// ============================================================
// Exercise 7: Pure Virtual with Default ⭐⭐⭐
// ============================================================

class Logger {
public:
    virtual void log(const string& msg) = 0;
    virtual string getPrefix() const { return "[LOG]"; }  // Virtual with default
    virtual ~Logger() = default;
};

// TODO: Create ConsoleLogger (prefix: [CONSOLE])
// TODO: Create FileLogger (prefix: [FILE])

void exercise7() {
    // ConsoleLogger cl;
    // FileLogger fl;
    // cl.log("Hello");
    // fl.log("World");
    cout << "(Implement Logger subclasses)" << endl;
}

// ============================================================
// Exercise 8: Final Class ⭐⭐
// ============================================================

class Singleton {
    // TODO: Make this class final so it cannot be inherited
public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }
private:
    Singleton() {}
};

void exercise8() {
    // Singleton& s = Singleton::getInstance();
    // Try to inherit from Singleton - should fail
    cout << "(Make Singleton final)" << endl;
}

// ============================================================
// MAIN
// ============================================================

int main() {
    cout << "=== Polymorphism Exercises ===" << endl;
    
    cout << "\nEx1: Virtual Functions" << endl;
    exercise1();
    
    cout << "\nEx2: Abstract Shape" << endl;
    exercise2();
    
    cout << "\nEx3: Virtual Destructor" << endl;
    exercise3();
    
    cout << "\nEx4: Interfaces" << endl;
    exercise4();
    
    cout << "\nEx5: Dynamic Cast" << endl;
    exercise5();
    
    cout << "\nEx6: Polymorphic Container" << endl;
    exercise6();
    
    cout << "\nEx7: Pure Virtual" << endl;
    exercise7();
    
    cout << "\nEx8: Final Class" << endl;
    exercise8();
    
    return 0;
}

// ============================================================
// ANSWERS
// ============================================================
/*
Ex1:
class Guitar : public Instrument { void play() const override { cout << "  Strumming guitar" << endl; } };
class Piano : public Instrument { void play() const override { cout << "  Playing piano keys" << endl; } };

Ex2:
class Square : public Shape2D {
    double side;
public:
    Square(double s) : side(s) {}
    double area() const override { return side * side; }
    double perimeter() const override { return 4 * side; }
};

Ex3: Add 'virtual' before ~Connection()

Ex4:
class Document : public Printable, public Saveable {
    string title, content;
public:
    Document(const string& t, const string& c) : title(t), content(c) {}
    void print() const override { cout << title << ": " << content << endl; }
    void save(const string& f) const override { cout << "Saved to " << f << endl; }
};

Ex5:
if (auto* dev = dynamic_cast<Developer*>(e)) dev->debug();
else if (auto* mgr = dynamic_cast<Manager*>(e)) mgr->meeting();

Ex7:
class ConsoleLogger : public Logger {
    string getPrefix() const override { return "[CONSOLE]"; }
    void log(const string& msg) override { cout << getPrefix() << " " << msg << endl; }
};

Ex8: class Singleton final { ... };
*/
Exercises - C++ Tutorial | DeepML