cpp

Advanced OOP

06_Advanced_OOP⚙️
/**
 * ============================================================
 * C++ ABSTRACT CLASSES & PURE VIRTUAL FUNCTIONS
 * ============================================================
 * 
 * This file covers:
 * - Abstract classes definition
 * - Pure virtual functions
 * - Interface vs abstract class
 * - Abstract class hierarchies
 * - Factory pattern with abstract classes
 * 
 * Compile: g++ -std=c++17 -Wall 01_abstract_classes.cpp -o abstract
 * Run: ./abstract
 * 
 * ============================================================
 */

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <cmath>

using namespace std;

// ============================================================
// PART 1: BASIC ABSTRACT CLASS
// ============================================================

// Abstract class - has at least one pure virtual function
class Shape {
protected:
    string name;
    string color;
    
public:
    Shape(const string& n, const string& c = "black") 
        : name(n), color(c) {
        cout << "  Shape constructor: " << name << endl;
    }
    
    virtual ~Shape() {
        cout << "  Shape destructor: " << name << endl;
    }
    
    // Pure virtual functions - MUST be implemented by derived classes
    virtual double area() const = 0;
    virtual double perimeter() const = 0;
    virtual void draw() const = 0;
    
    // Regular virtual function - CAN be overridden
    virtual void describe() const {
        cout << "A " << color << " " << name << endl;
    }
    
    // Non-virtual function
    string getName() const { return name; }
    string getColor() const { return color; }
    void setColor(const string& c) { color = c; }
};

// Concrete class - implements all pure virtual functions
class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r, const string& c = "red") 
        : Shape("Circle", c), radius(r) {
        cout << "  Circle constructor, radius=" << radius << endl;
    }
    
    ~Circle() {
        cout << "  Circle destructor" << endl;
    }
    
    // Implementing pure virtual functions
    double area() const override {
        return M_PI * radius * radius;
    }
    
    double perimeter() const override {
        return 2 * M_PI * radius;
    }
    
    void draw() const override {
        cout << "Drawing " << color << " circle with radius " << radius << endl;
    }
    
    // Additional methods specific to Circle
    double getRadius() const { return radius; }
};

class Rectangle : public Shape {
private:
    double width, height;
    
public:
    Rectangle(double w, double h, const string& c = "blue")
        : Shape("Rectangle", c), width(w), height(h) {
        cout << "  Rectangle constructor, " << width << "x" << height << endl;
    }
    
    ~Rectangle() {
        cout << "  Rectangle destructor" << endl;
    }
    
    double area() const override {
        return width * height;
    }
    
    double perimeter() const override {
        return 2 * (width + height);
    }
    
    void draw() const override {
        cout << "Drawing " << color << " rectangle " << width << "x" << height << endl;
    }
};

// ============================================================
// PART 2: ABSTRACT CLASS HIERARCHY
// ============================================================

// Abstract base
class Employee {
protected:
    string name;
    int id;
    
public:
    Employee(const string& n, int i) : name(n), id(i) {}
    virtual ~Employee() = default;
    
    // Pure virtual - different employees calculate salary differently
    virtual double calculateSalary() const = 0;
    virtual string getRole() const = 0;
    
    string getName() const { return name; }
    int getId() const { return id; }
    
    virtual void displayInfo() const {
        cout << "ID: " << id << ", Name: " << name 
             << ", Role: " << getRole() 
             << ", Salary: $" << calculateSalary() << endl;
    }
};

// Still abstract - doesn't implement all pure virtuals
class HourlyEmployee : public Employee {
protected:
    double hourlyRate;
    int hoursWorked;
    
public:
    HourlyEmployee(const string& n, int i, double rate, int hours)
        : Employee(n, i), hourlyRate(rate), hoursWorked(hours) {}
    
    double calculateSalary() const override {
        return hourlyRate * hoursWorked;
    }
    
    // getRole() still pure virtual - makes this class abstract
};

// Concrete classes
class Developer : public HourlyEmployee {
public:
    Developer(const string& n, int i, double rate, int hours)
        : HourlyEmployee(n, i, rate, hours) {}
    
    string getRole() const override {
        return "Developer";
    }
};

class Designer : public HourlyEmployee {
public:
    Designer(const string& n, int i, double rate, int hours)
        : HourlyEmployee(n, i, rate, hours) {}
    
    string getRole() const override {
        return "Designer";
    }
};

class Manager : public Employee {
private:
    double baseSalary;
    double bonus;
    
public:
    Manager(const string& n, int i, double salary, double b)
        : Employee(n, i), baseSalary(salary), bonus(b) {}
    
    double calculateSalary() const override {
        return baseSalary + bonus;
    }
    
    string getRole() const override {
        return "Manager";
    }
};

// ============================================================
// PART 3: PURE INTERFACE (ALL PURE VIRTUAL)
// ============================================================

// Pure interface - no data members, all pure virtual
class Drawable {
public:
    virtual ~Drawable() = default;
    
    virtual void draw() const = 0;
    virtual void erase() const = 0;
    virtual void moveTo(int x, int y) = 0;
};

class Clickable {
public:
    virtual ~Clickable() = default;
    
    virtual void onClick() = 0;
    virtual void onDoubleClick() = 0;
    virtual bool isClickable() const = 0;
};

class Resizable {
public:
    virtual ~Resizable() = default;
    
    virtual void resize(double factor) = 0;
    virtual void setSize(int w, int h) = 0;
};

// Class implementing multiple interfaces
class Button : public Drawable, public Clickable, public Resizable {
private:
    string label;
    int x, y;
    int width, height;
    bool enabled;
    
public:
    Button(const string& lbl, int x, int y, int w, int h)
        : label(lbl), x(x), y(y), width(w), height(h), enabled(true) {}
    
    // Drawable interface
    void draw() const override {
        cout << "Drawing button '" << label << "' at (" << x << "," << y 
             << ") size " << width << "x" << height << endl;
    }
    
    void erase() const override {
        cout << "Erasing button '" << label << "'" << endl;
    }
    
    void moveTo(int newX, int newY) override {
        x = newX;
        y = newY;
        cout << "Moved button to (" << x << "," << y << ")" << endl;
    }
    
    // Clickable interface
    void onClick() override {
        if (enabled) {
            cout << "Button '" << label << "' clicked!" << endl;
        }
    }
    
    void onDoubleClick() override {
        if (enabled) {
            cout << "Button '" << label << "' double-clicked!" << endl;
        }
    }
    
    bool isClickable() const override {
        return enabled;
    }
    
    // Resizable interface
    void resize(double factor) override {
        width = static_cast<int>(width * factor);
        height = static_cast<int>(height * factor);
        cout << "Resized to " << width << "x" << height << endl;
    }
    
    void setSize(int w, int h) override {
        width = w;
        height = h;
    }
    
    // Button-specific methods
    void setEnabled(bool e) { enabled = e; }
    string getLabel() const { return label; }
};

// ============================================================
// PART 4: FACTORY PATTERN WITH ABSTRACT CLASSES
// ============================================================

// Abstract product
class Document {
public:
    virtual ~Document() = default;
    virtual void open() = 0;
    virtual void save() = 0;
    virtual void close() = 0;
    virtual string getType() const = 0;
};

class TextDocument : public Document {
private:
    string content;
public:
    void open() override { cout << "Opening text document..." << endl; }
    void save() override { cout << "Saving as .txt file..." << endl; }
    void close() override { cout << "Closing text document..." << endl; }
    string getType() const override { return "Text"; }
};

class PDFDocument : public Document {
public:
    void open() override { cout << "Opening PDF document..." << endl; }
    void save() override { cout << "Saving as .pdf file..." << endl; }
    void close() override { cout << "Closing PDF document..." << endl; }
    string getType() const override { return "PDF"; }
};

class SpreadsheetDocument : public Document {
public:
    void open() override { cout << "Opening spreadsheet..." << endl; }
    void save() override { cout << "Saving as .xlsx file..." << endl; }
    void close() override { cout << "Closing spreadsheet..." << endl; }
    string getType() const override { return "Spreadsheet"; }
};

// Factory class
class DocumentFactory {
public:
    static unique_ptr<Document> createDocument(const string& type) {
        if (type == "text") return make_unique<TextDocument>();
        if (type == "pdf") return make_unique<PDFDocument>();
        if (type == "spreadsheet") return make_unique<SpreadsheetDocument>();
        return nullptr;
    }
};

// ============================================================
// MAIN FUNCTION
// ============================================================

int main() {
    cout << "============================================" << endl;
    cout << "     C++ ABSTRACT CLASSES" << endl;
    cout << "============================================" << endl << endl;

    // ========================================================
    // DEMO 1: Basic Abstract Class
    // ========================================================
    
    cout << "--- DEMO 1: BASIC ABSTRACT CLASS ---" << endl << endl;
    
    // Shape shape("Test", "red");  // ERROR: cannot instantiate abstract class
    
    cout << "Creating shapes:" << endl;
    Circle circle(5.0, "red");
    Rectangle rect(4.0, 3.0, "blue");
    
    cout << "\nUsing shapes through base pointer:" << endl;
    vector<Shape*> shapes = {&circle, &rect};
    
    for (const Shape* s : shapes) {
        s->describe();
        s->draw();
        cout << "  Area: " << s->area() << endl;
        cout << "  Perimeter: " << s->perimeter() << endl;
        cout << endl;
    }
    
    cout << endl;

    // ========================================================
    // DEMO 2: Abstract Class Hierarchy
    // ========================================================
    
    cout << "--- DEMO 2: ABSTRACT HIERARCHY ---" << endl << endl;
    
    // HourlyEmployee emp("Test", 1, 50, 40);  // ERROR: still abstract
    
    vector<unique_ptr<Employee>> employees;
    employees.push_back(make_unique<Developer>("Alice", 101, 75.0, 160));
    employees.push_back(make_unique<Designer>("Bob", 102, 65.0, 150));
    employees.push_back(make_unique<Manager>("Charlie", 103, 8000.0, 2000.0));
    
    cout << "Employee list:" << endl;
    double totalPayroll = 0;
    for (const auto& emp : employees) {
        emp->displayInfo();
        totalPayroll += emp->calculateSalary();
    }
    cout << "\nTotal payroll: $" << totalPayroll << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 3: Multiple Interfaces
    // ========================================================
    
    cout << "--- DEMO 3: MULTIPLE INTERFACES ---" << endl << endl;
    
    Button okButton("OK", 100, 200, 80, 30);
    
    // Use as Drawable
    Drawable* drawable = &okButton;
    drawable->draw();
    drawable->moveTo(150, 250);
    
    // Use as Clickable
    Clickable* clickable = &okButton;
    clickable->onClick();
    clickable->onDoubleClick();
    
    // Use as Resizable
    Resizable* resizable = &okButton;
    resizable->resize(1.5);
    
    cout << endl;

    // ========================================================
    // DEMO 4: Factory Pattern
    // ========================================================
    
    cout << "--- DEMO 4: FACTORY PATTERN ---" << endl << endl;
    
    vector<string> docTypes = {"text", "pdf", "spreadsheet"};
    
    for (const auto& type : docTypes) {
        auto doc = DocumentFactory::createDocument(type);
        if (doc) {
            cout << "Created " << doc->getType() << " document:" << endl;
            doc->open();
            doc->save();
            doc->close();
            cout << endl;
        }
    }
    
    cout << endl;

    // ========================================================
    // ABSTRACT CLASS CONCEPTS
    // ========================================================
    
    cout << "--- ABSTRACT CLASS CONCEPTS ---" << endl << endl;
    
    cout << "Abstract Class:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Has at least one pure virtual function" << endl;
    cout << "• Cannot be instantiated directly" << endl;
    cout << "• Can have data members" << endl;
    cout << "• Can have non-virtual functions" << endl;
    cout << "• Can have constructor/destructor" << endl;
    
    cout << "\nPure Virtual Function:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Declared with = 0" << endl;
    cout << "• virtual void func() = 0;" << endl;
    cout << "• Must be overridden in derived class" << endl;
    cout << "• Makes the class abstract" << endl;
    
    cout << "\nInterface (C++ convention):" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• All functions are pure virtual" << endl;
    cout << "• No data members (except maybe static)" << endl;
    cout << "• Only virtual destructor" << endl;
    cout << "• Defines a contract for classes" << endl;
    
    cout << "\nWhen to Use:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Define common interface for family" << endl;
    cout << "• Force derived classes to implement" << endl;
    cout << "• Enable polymorphic behavior" << endl;
    cout << "• Decouple interface from implementation" << endl;
    
    cout << endl;

    cout << "============================================" << endl;
    cout << "ABSTRACT CLASSES COMPLETE!" << endl;
    cout << "============================================" << endl;

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Create an abstract Vehicle class:
 *    - Pure virtual: start(), stop(), accelerate(), brake()
 *    - Derived: Car, Motorcycle, Truck
 *    - Each with unique implementations
 * 
 * 2. Create an abstract DataSource:
 *    - Pure virtual: connect(), read(), write(), close()
 *    - Derived: FileSource, DatabaseSource, NetworkSource
 *    - Use factory to create sources
 * 
 * 3. Create a game character system:
 *    - Interface: Attackable, Movable, Damageable
 *    - Classes: Player, Enemy, NPC implementing interfaces
 *    - Demonstrate polymorphic behavior
 * 
 * 4. Create an abstract Logger:
 *    - Pure virtual: log(), setLevel(), getLevel()
 *    - Derived: ConsoleLogger, FileLogger, NetworkLogger
 *    - Support log levels (Debug, Info, Warning, Error)
 */
Advanced OOP - C++ Tutorial | DeepML