3. Practical Applications and Best Practices

3.1 Complete Example: University Management System 
 #include <iostream>
#include <vector>
#include <string>
using namespace std;

// Base class
class Person {
protected:
 string name;
 int id;
 int age;
 
public:
 Person(string n, int i, int a) : name(n), id(i), age(a) {}
 
 virtual void displayInfo() {
 cout << "Name: " << name << endl;
 cout << "ID: " << id << endl;
 cout << "Age: " << age << endl;
 }
 
 virtual string getRole() = 0; // Pure virtual
 
 string getName() { return name; }
 int getId() { return id; }
 
 virtual ~Person() {}
};

// Derived class: Student
class Student : public Person {
private:
 string major;
 double gpa;
 vector<string> courses;
 
public:
 Student(string n, int i, int a, string m, double g)
 : Person(n, i, a), major(m), gpa(g) {}
 
 void enrollCourse(string course) {
 courses.push_back(course);
 cout << name << " enrolled in " << course << endl;
 }
 
 void displayInfo() override {
 cout << "=== Student Information ===" << endl;
 Person::displayInfo();
 cout << "Major: " << major << endl;
 cout << "GPA: " << gpa << endl;
 cout << "Enrolled Courses: ";
 if (courses.empty()) {
 cout << "None" << endl;
 } else {
 cout << endl;
 for (const string& course : courses) {
 cout << " - " << course << endl;
 }
 }
 }
 
 string getRole() override {
 return "Student";
 }
 
 void study() {
 cout << name << " is studying..." << endl;
 }
};

// Derived class: Faculty
class Faculty : public Person {
private:
 string department;
 double salary;
 vector<string> coursesTeaching;
 
public:
 Faculty(string n, int i, int a, string dept, double sal)
 : Person(n, i, a), department(dept), salary(sal) {}
 
 void assignCourse(string course) {
 coursesTeaching.push_back(course);
 cout << name << " assigned to teach " << course << endl;
 }
 
 void displayInfo() override {
 cout << "=== Faculty Information ===" << endl;
 Person::displayInfo();
 cout << "Department: " << department << endl;
 cout << "Salary: $" << salary << endl;
 cout << "Courses Teaching: ";
 if (coursesTeaching.empty()) {
 cout << "None" << endl;
 } else {
 cout << endl;
 for (const string& course : coursesTeaching) {
 cout << " - " << course << endl;
 }
 }
 }
 
 string getRole() override {
 return "Faculty";
 }
 
 void teach() {
 cout << name << " is teaching..." << endl;
 }
};

// Derived class: Staff
class Staff : public Person {
private:
 string position;
 string department;
 double salary;
 
public:
 Staff(string n, int i, int a, string pos, string dept, double sal)
 : Person(n, i, a), position(pos), department(dept), salary(sal) {}
 
 void displayInfo() override {
 cout << "=== Staff Information ===" << endl;
 Person::displayInfo();
 cout << "Position: " << position << endl;
 cout << "Department: " << department << endl;
 cout << "Salary: $" << salary << endl;
 }
 
 string getRole() override {
 return "Staff";
 }
 
 void work() {
 cout << name << " (" << position << ") is working..." << endl;
 }
};

// University class to manage all persons
class University {
private:
 string universityName;
 vector<Person*> members;
 
public:
 University(string name) : universityName(name) {
 cout << "University '" << universityName << "' initialized." << endl;
 }
 
 void addMember(Person* person) {
 members.push_back(person);
 cout << person->getRole() << " " << person->getName() 
 << " added to " << universityName << endl;
 }
 
 void displayAllMembers() {
 cout << "\n========== " << universityName << " - All Members ==========" << endl;
 
 for (Person* member : members) {
 member->displayInfo();
 cout << "-------------------------------------------" << endl;
 }
 }
 
 void displayByRole(string role) {
 cout << "\n========== " << role << "s at " << universityName << " ==========" << endl;
 
 bool found = false;
 for (Person* member : members) {
 if (member->getRole() == role) {
 member->displayInfo();
 cout << "-------------------------------------------" << endl;
 found = true;
 }
 }
 
 if (!found) {
 cout << "No " << role << "s found." << endl;
 }
 }
 
 Person* findMember(int id) {
 for (Person* member : members) {
 if (member->getId() == id) {
 return member;
 }
 }
 return nullptr;
 }
 
 ~University() {
 for (Person* member : members) {
 delete member;
 }
 }
};

int main() {
 University university("Tech University");
 
 cout << "\n=== Adding Members ===" << endl;
 
 // Add students
 Student* s1 = new Student("Alice Johnson", 1001, 20, "Computer Science", 3.8);
 Student* s2 = new Student("Bob Smith", 1002, 21, "Electrical Engineering", 3.6);
 
 university.addMember(s1);
 university.addMember(s2);
 
 // Add faculty
 Faculty* f1 = new Faculty("Dr. Carol White", 2001, 45, "Computer Science", 85000);
 Faculty* f2 = new Faculty("Dr. David Brown", 2002, 50, "Electrical Engineering", 90000);
 
 university.addMember(f1);
 university.addMember(f2);
 
 // Add staff
 Staff* st1 = new Staff("Eve Davis", 3001, 35, "Administrator", "Administration", 50000);
 
 university.addMember(st1);
 
 // Assign courses
 cout << "\n=== Assigning Courses ===" << endl;
 f1->assignCourse("Data Structures");
 f1->assignCourse("Algorithms");
 f2->assignCourse("Circuit Analysis");
 
 // Enroll students
 cout << "\n=== Enrolling Students ===" << endl;
 s1->enrollCourse("Data Structures");
 s1->enrollCourse("Algorithms");
 s2->enrollCourse("Circuit Analysis");
 
 // Display all members
 university.displayAllMembers();
 
 // Display by role
 university.displayByRole("Student");
 university.displayByRole("Faculty");
 
 // Polymorphic behavior
 cout << "\n=== Daily Activities ===" << endl;
 s1->study();
 f1->teach();
 st1->work();
 
 return 0;
}
 
 3.2 Best Practices 
 1. Use virtual Destructors in Base Classes 
 class Base {
public:
 virtual ~Base() {} // IMPORTANT for polymorphism
};
 
 2. Use override Keyword 
 class Derived : public Base {
public:
 void someMethod() override { // Explicit override
 // Implementation
 }
};
 
 3. Prefer Composition Over Inheritance When Appropriate 
 // Don't do: class Car : public Engine
// Do this:
class Car {
private:
 Engine engine; // Has-a relationship
public:
 Car() : engine() {}
};
 
 4. Keep Base Class Interface Stable 
 // Good: Minimal, stable base class
class Shape {
public:
 virtual double getArea() = 0;
 virtual void draw() = 0;
 virtual ~Shape() {}
};
 
 5. Use protected for Members Needed by Derived Classes 
 class Base {
protected:
 int valueNeededByDerived; // Accessible in derived classes
private:
 int internalImplementation; // Not accessible in derived classes
};
 
 3.3 Common Pitfalls and Solutions 
 Problem 1: Forgetting Virtual Destructor 
 // BAD: No virtual destructor
class Base {
public:
 ~Base() { cout << "Base destructor" << endl; }
};

class Derived : public Base {
private:
 int* data;
public:
 Derived() { data = new int[100]; }
 ~Derived() { 
 delete[] data; 
 cout << "Derived destructor" << endl; 
 }
};

int main() {
 Base* obj = new Derived();
 delete obj; // MEMORY LEAK! Only Base destructor called
 return 0;
}

// GOOD: Virtual destructor
class Base {
public:
 virtual ~Base() { cout << "Base destructor" << endl; }
};

class Derived : public Base {
private:
 int* data;
public:
 Derived() { data = new int[100]; }
 ~Derived() override { 
 delete[] data; 
 cout << "Derived destructor" << endl; 
 }
};

int main() {
 Base* obj = new Derived();
 delete obj; // Correct! Both destructors called
 return 0;
}
 
 Problem 2: Object Slicing 
 #include <iostream>
#include <string>
using namespace std;

class Animal {
public:
 string type;
 Animal() : type("Animal") {}
 virtual void makeSound() { cout << "Generic sound" << endl; }
};

class Dog : public Animal {
public:
 string breed;
 Dog() : breed("Unknown") { type = "Dog"; }
 void makeSound() override { cout << "Woof!" << endl; }
};

// BAD: Pass by value causes slicing
void processAnimal(Animal animal) {
 animal.makeSound(); // Always calls Animal::makeSound()!
}

// GOOD: Pass by reference or pointer
void processAnimalCorrect(Animal& animal) {
 animal.makeSound(); // Calls correct method
}

void processAnimalPointer(Animal* animal) {
 animal->makeSound(); // Calls correct method
}

int main() {
 Dog myDog;
 
 cout << "=== Object Slicing (BAD) ===" << endl;
 processAnimal(myDog); // Slicing occurs! Outputs: Generic sound
 
 cout << "\n=== Using Reference (GOOD) ===" << endl;
 processAnimalCorrect(myDog); // Outputs: Woof!
 
 cout << "\n=== Using Pointer (GOOD) ===" << endl;
 processAnimalPointer(&myDog); // Outputs: Woof!
 
 return 0;
}
 
 Problem 3: Calling Virtual Functions in Constructor 
 #include <iostream>
using namespace std;

class Base {
public:
 Base() {
 init(); // Calls Base::init(), not Derived::init()!
 }
 
 virtual void init() {
 cout << "Base initialization" << endl;
 }
};

class Derived : public Base {
public:
 Derived() {
 // Base constructor already called
 }
 
 void init() override {
 cout << "Derived initialization" << endl;
 }
};

int main() {
 Derived d; // Output: Base initialization (not what we want!)
 return 0;
}

// SOLUTION: Call init() explicitly after construction
class BaseSolution {
public:
 BaseSolution() {
 // Don't call virtual functions here
 }
 
 virtual void init() {
 cout << "Base initialization" << endl;
 }
};

class DerivedSolution : public BaseSolution {
public:
 DerivedSolution() {
 // Don't call init() in constructor
 }
 
 void init() override {
 cout << "Derived initialization" << endl;
 }
};

int main() {
 DerivedSolution d;
 d.init(); // Now calls Derived::init()
 return 0;
}
 
 Problem 4: Ambiguity in Multiple Inheritance 
 #include <iostream>
using namespace std;

class ClassA {
public:
 void display() { cout << "ClassA" << endl; }
};

class ClassB {
public:
 void display() { cout << "ClassB" << endl; }
};

class ClassC : public ClassA, public ClassB {
 // Now ClassC has two display() methods!
};

int main() {
 ClassC obj;
 // obj.display(); // ERROR: Ambiguous! Which display()?
 
 // SOLUTION 1: Explicitly specify which class
 obj.ClassA::display();
 obj.ClassB::display();
 
 return 0;
}

// SOLUTION 2: Override in derived class
class ClassCSolution : public ClassA, public ClassB {
public:
 void display() {
 cout << "ClassC - calling both:" << endl;
 ClassA::display();
 ClassB::display();
 }
};
 
 3.4 Real-World Example: Vehicle Rental System 
 #include <iostream>
#include <vector>
#include <string>
using namespace std;

// Base class
class Vehicle {
protected:
 string vehicleId;
 string brand;
 string model;
 double dailyRate;
 bool isRented;
 
public:
 Vehicle(string id, string b, string m, double rate)
 : vehicleId(id), brand(b), model(m), dailyRate(rate), isRented(false) {}
 
 virtual void displayInfo() {
 cout << "ID: " << vehicleId << endl;
 cout << "Brand: " << brand << endl;
 cout << "Model: " << model << endl;
 cout << "Daily Rate: $" << dailyRate << endl;
 cout << "Status: " << (isRented ? "Rented" : "Available") << endl;
 }
 
 virtual double calculateRentalCost(int days) {
 return dailyRate * days;
 }
 
 virtual string getVehicleType() = 0;
 
 void rent() {
 if (!isRented) {
 isRented = true;
 cout << "Vehicle " << vehicleId << " rented successfully." << endl;
 } else {
 cout << "Vehicle " << vehicleId << " is already rented." << endl;
 }
 }
 
 void returnVehicle() {
 if (isRented) {
 isRented = false;
 cout << "Vehicle " << vehicleId << " returned successfully." << endl;
 }
 }
 
 bool checkAvailability() { return !isRented; }
 string getId() { return vehicleId; }
 
 virtual ~Vehicle() {}
};

// Derived class: Car
class Car : public Vehicle {
private:
 int numDoors;
 string fuelType;
 
public:
 Car(string id, string b, string m, double rate, int doors, string fuel)
 : Vehicle(id, b, m, rate), numDoors(doors), fuelType(fuel) {}
 
 void displayInfo() override {
 cout << "\n=== CAR ===" << endl;
 Vehicle::displayInfo();
 cout << "Number of Doors: " << numDoors << endl;
 cout << "Fuel Type: " << fuelType << endl;
 }
 
 double calculateRentalCost(int days) override {
 double baseCost = Vehicle::calculateRentalCost(days);
 // Premium fuel adds 10% to cost
 if (fuelType == "Premium") {
 baseCost *= 1.1;
 }
 return baseCost;
 }
 
 string getVehicleType() override {
 return "Car";
 }
};

// Derived class: Motorcycle
class Motorcycle : public Vehicle {
private:
 int engineCC;
 bool hasABS;
 
public:
 Motorcycle(string id, string b, string m, double rate, int cc, bool abs)
 : Vehicle(id, b, m, rate), engineCC(cc), hasABS(abs) {}
 
 void displayInfo() override {
 cout << "\n=== MOTORCYCLE ===" << endl;
 Vehicle::displayInfo();
 cout << "Engine CC: " << engineCC << endl;
 cout << "ABS: " << (hasABS ? "Yes" : "No") << endl;
 }
 
 double calculateRentalCost(int days) override {
 double baseCost = Vehicle::calculateRentalCost(days);
 // Motorcycles get 20% discount for rentals over 7 days
 if (days > 7) {
 baseCost *= 0.8;
 }
 return baseCost;
 }
 
 string getVehicleType() override {
 return "Motorcycle";
 }
};

// Derived class: Truck
class Truck : public Vehicle {
private:
 double loadCapacity; // in tons
 bool hasLiftGate;
 
public:
 Truck(string id, string b, string m, double rate, double capacity, bool liftGate)
 : Vehicle(id, b, m, rate), loadCapacity(capacity), hasLiftGate(liftGate) {}
 
 void displayInfo() override {
 cout << "\n=== TRUCK ===" << endl;
 Vehicle::displayInfo();
 cout << "Load Capacity: " << loadCapacity << " tons" << endl;
 cout << "Lift Gate: " << (hasLiftGate ? "Yes" : "No") << endl;
 }
 
 double calculateRentalCost(int days) override {
 double baseCost = Vehicle::calculateRentalCost(days);
 // Additional charge based on capacity
 baseCost += (loadCapacity * 5 * days);
 // Lift gate adds $10 per day
 if (hasLiftGate) {
 baseCost += (10 * days);
 }
 return baseCost;
 }
 
 string getVehicleType() override {
 return "Truck";
 }
};

// Rental system manager
class RentalSystem {
private:
 string companyName;
 vector<Vehicle*> fleet;
 
public:
 RentalSystem(string name) : companyName(name) {
 cout << "=== " << companyName << " Rental System Initialized ===" << endl;
 }
 
 void addVehicle(Vehicle* vehicle) {
 fleet.push_back(vehicle);
 cout << vehicle->getVehicleType() << " " << vehicle->getId() 
 << " added to fleet." << endl;
 }
 
 void displayFleet() {
 cout << "\n========== " << companyName << " - Fleet ==========" << endl;
 for (Vehicle* vehicle : fleet) {
 vehicle->displayInfo();
 cout << "----------------------------------------" << endl;
 }
 }
 
 void displayAvailableVehicles() {
 cout << "\n========== Available Vehicles ==========" << endl;
 bool found = false;
 for (Vehicle* vehicle : fleet) {
 if (vehicle->checkAvailability()) {
 vehicle->displayInfo();
 cout << "----------------------------------------" << endl;
 found = true;
 }
 }
 if (!found) {
 cout << "No vehicles available." << endl;
 }
 }
 
 Vehicle* findVehicle(string id) {
 for (Vehicle* vehicle : fleet) {
 if (vehicle->getId() == id) {
 return vehicle;
 }
 }
 return nullptr;
 }
 
 void rentVehicle(string id, int days) {
 Vehicle* vehicle = findVehicle(id);
 if (vehicle != nullptr) {
 if (vehicle->checkAvailability()) {
 vehicle->rent();
 double cost = vehicle->calculateRentalCost(days);
 cout << "Rental Duration: " << days << " days" << endl;
 cout << "Total Cost: $" << cost << endl;
 } else {
 cout << "Vehicle is not available." << endl;
 }
 } else {
 cout << "Vehicle not found." << endl;
 }
 }
 
 void returnVehicle(string id) {
 Vehicle* vehicle = findVehicle(id);
 if (vehicle != nullptr) {
 vehicle->returnVehicle();
 } else {
 cout << "Vehicle not found." << endl;
 }
 }
 
 ~RentalSystem() {
 for (Vehicle* vehicle : fleet) {
 delete vehicle;
 }
 }
};

int main() {
 RentalSystem rental("QuickRent");
 
 cout << "\n=== Adding Vehicles to Fleet ===" << endl;
 rental.addVehicle(new Car("C001", "Toyota", "Camry", 50, 4, "Regular"));
 rental.addVehicle(new Car("C002", "BMW", "M5", 120, 4, "Premium"));
 rental.addVehicle(new Motorcycle("M001", "Harley", "Sportster", 40, 883, true));
 rental.addVehicle(new Motorcycle("M002", "Honda", "CBR", 35, 600, false));
 rental.addVehicle(new Truck("T001", "Ford", "F-150", 80, 2.5, true));
 rental.addVehicle(new Truck("T002", "Chevrolet", "Silverado", 85, 3.0, false));
 
 // Display all vehicles
 rental.displayFleet();
 
 // Rent some vehicles
 cout << "\n=== Renting Vehicles ===" << endl;
 rental.rentVehicle("C001", 3);
 cout << endl;
 rental.rentVehicle("M001", 10); // Gets discount (>7 days)
 cout << endl;
 rental.rentVehicle("T001", 5);
 
 // Display available vehicles
 rental.displayAvailableVehicles();
 
 // Try to rent already rented vehicle
 cout << "\n=== Trying to Rent Already Rented Vehicle ===" << endl;
 rental.rentVehicle("C001", 2);
 
 // Return vehicles
 cout << "\n=== Returning Vehicles ===" << endl;
 rental.returnVehicle("C001");
 rental.returnVehicle("M001");
 
 // Display available vehicles again
 rental.displayAvailableVehicles();
 
 return 0;
}