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