cpp
exercises
exercises.cpp⚙️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 { ... };
*/