cpp
exercises
exercises.cpp⚙️cpp
/**
* Virtual Inheritance - Exercises
* Compile: g++ -std=c++17 -Wall exercises.cpp -o exercises
*/
#include <iostream>
#include <string>
using namespace std;
// ============================================================
// Exercise 1: Fix the Diamond ⭐
// ============================================================
// TODO: Fix using virtual inheritance
class Person {
public:
string name;
Person(const string& n = "") : name(n) {}
};
class Student : public Person { // Add virtual
public:
int studentId;
Student(const string& n = "", int id = 0) : Person(n), studentId(id) {}
};
class Employee : public Person { // Add virtual
public:
int employeeId;
Employee(const string& n = "", int id = 0) : Person(n), employeeId(id) {}
};
class TeachingAssistant : public Student, public Employee {
public:
TeachingAssistant(const string& n, int sid, int eid)
: Student(n, sid), Employee(n, eid) {} // Fix constructor
};
void exercise1() {
TeachingAssistant ta("Alice", 1001, 2001);
// cout << ta.name << endl; // Should work without ambiguity
cout << "(Fix diamond problem)" << endl;
}
// ============================================================
// Exercise 2: Constructor Order ⭐⭐
// ============================================================
// Predict and verify the constructor order
class A {
public:
A() { cout << "A "; }
};
class B : virtual public A {
public:
B() { cout << "B "; }
};
class C : virtual public A {
public:
C() { cout << "C "; }
};
class D : public B, public C {
public:
D() { cout << "D "; }
};
void exercise2() {
cout << "Constructor order: ";
D d;
cout << endl;
// What is the output?
}
// ============================================================
// Exercise 3: Initialize Virtual Base ⭐⭐
// ============================================================
class Device {
protected:
string model;
public:
Device(const string& m) : model(m) {
cout << " Device(" << m << ")" << endl;
}
};
class Phone : virtual public Device {
public:
Phone() : Device("DefaultPhone") {
cout << " Phone()" << endl;
}
};
class Camera : virtual public Device {
public:
Camera() : Device("DefaultCamera") {
cout << " Camera()" << endl;
}
};
// TODO: Create Smartphone that properly initializes Device with "Smartphone"
class Smartphone : public Phone, public Camera {
public:
// ⚠️ LEARNING NOTE: With virtual inheritance, the MOST DERIVED class
// must call the virtual base constructor directly!
//
// Why? Because Device is shared (virtual), if Phone and Camera both
// tried to initialize it, we'd have a conflict. So C++ requires the
// final derived class (Smartphone) to do it.
//
// FIX: Add Device("Smartphone") to the initializer list
Smartphone() : Device("Smartphone") {
cout << " Smartphone()" << endl;
}
};
void exercise3() {
cout << "Creating Smartphone:" << endl;
Smartphone s;
// Should print "Device(Smartphone)" not "Device(DefaultPhone)"
}
// ============================================================
// Exercise 4: Interface Hierarchy ⭐⭐⭐
// ============================================================
// TODO: Create interface hierarchy using virtual inheritance
// IEntity (base with id)
// ├── IMoveable (with move())
// └── IDrawable (with draw())
// GameObject implements both
void exercise4() {
// GameObject obj(1);
// obj.move(10, 20);
// obj.draw();
// cout << "ID: " << obj.getId() << endl;
cout << "(Create interface hierarchy)" << endl;
}
// ============================================================
// Exercise 5: Mixin Pattern ⭐⭐⭐
// ============================================================
// Use virtual inheritance for mixins
class Named {
protected:
string name_;
public:
Named(const string& n = "") : name_(n) {}
string getName() const { return name_; }
};
// TODO: Create mixins that virtually inherit from Named
// - Printable (adds print())
// - Saveable (adds save())
// - Document that combines both
void exercise5() {
// Document doc("Report");
// doc.print();
// doc.save();
cout << "(Implement mixin pattern)" << endl;
}
// ============================================================
// MAIN
// ============================================================
int main() {
cout << "=== Virtual Inheritance Exercises ===" << endl;
cout << "\nEx1: Fix Diamond" << endl;
exercise1();
cout << "\nEx2: Constructor Order" << endl;
exercise2();
cout << "\nEx3: Initialize Virtual Base" << endl;
exercise3();
cout << "\nEx4: Interface Hierarchy" << endl;
exercise4();
cout << "\nEx5: Mixin Pattern" << endl;
exercise5();
return 0;
}
// ============================================================
// ANSWERS
// ============================================================
/*
Ex1:
class Student : virtual public Person { ... };
class Employee : virtual public Person { ... };
class TeachingAssistant : public Student, public Employee {
TeachingAssistant(const string& n, int sid, int eid)
: Person(n), Student(n, sid), Employee(n, eid) {}
};
Ex2: Output is "A B C D"
- Virtual base A constructed first (once)
- Then B, C in declaration order
- Finally D
Ex3:
class Smartphone : public Phone, public Camera {
public:
Smartphone() : Device("Smartphone"), Phone(), Camera() {
cout << " Smartphone()" << endl;
}
};
Ex4:
class IEntity {
int id;
public:
IEntity(int i) : id(i) {}
int getId() const { return id; }
virtual ~IEntity() = default;
};
class IMoveable : virtual public IEntity {
public:
virtual void move(int x, int y) = 0;
};
class IDrawable : virtual public IEntity {
public:
virtual void draw() = 0;
};
class GameObject : public IMoveable, public IDrawable {
public:
GameObject(int id) : IEntity(id) {}
void move(int x, int y) override { cout << "Moving to " << x << "," << y << endl; }
void draw() override { cout << "Drawing" << endl; }
};
Ex5:
class Printable : virtual public Named {
public:
void print() { cout << "Printing: " << name_ << endl; }
};
class Saveable : virtual public Named {
public:
void save() { cout << "Saving: " << name_ << endl; }
};
class Document : public Printable, public Saveable {
public:
Document(const string& n) : Named(n) {}
};
*/