cpp

examples

examples.cpp⚙️
/**
 * Encapsulation in C++ - Comprehensive Examples
 * 
 * Demonstrates:
 * - Access modifiers
 * - Getters and setters
 * - Data validation
 * - Friend functions and classes
 * 
 * Compile: g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
 * Run: ./examples
 */

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

using namespace std;

// ============================================================
// SECTION 1: BASIC ENCAPSULATION
// ============================================================

// Without encapsulation (vulnerable)
struct UnsafeBankAccount {
    double balance;  // Anyone can modify!
};

// With encapsulation (protected)
class SafeBankAccount {
private:
    double balance;
    string accountNumber;
    
public:
    SafeBankAccount(const string& accNum, double initial = 0.0) 
        : balance(initial >= 0 ? initial : 0), accountNumber(accNum) {}
    
    // Controlled access
    double getBalance() const { return balance; }
    string getAccountNumber() const { return accountNumber; }
    
    // Validated operations
    bool deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            return true;
        }
        return false;
    }
    
    bool withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            return true;
        }
        return false;
    }
};

void demonstrateBasicEncapsulation() {
    cout << "--- Basic Encapsulation ---\n" << endl;
    
    // Unsafe version
    UnsafeBankAccount unsafe;
    unsafe.balance = 1000;
    unsafe.balance = -5000;  // No protection!
    cout << "Unsafe account balance: $" << unsafe.balance << " (invalid!)" << endl;
    
    // Safe version
    SafeBankAccount safe("ACC001", 1000);
    cout << "\nSafe account: " << safe.getAccountNumber() << endl;
    cout << "Initial balance: $" << safe.getBalance() << endl;
    
    safe.deposit(500);
    cout << "After deposit $500: $" << safe.getBalance() << endl;
    
    if (!safe.withdraw(2000)) {
        cout << "Cannot withdraw $2000 - insufficient funds" << endl;
    }
    
    safe.withdraw(300);
    cout << "After withdraw $300: $" << safe.getBalance() << endl;
    
    // Cannot directly modify:
    // safe.balance = -5000;  // ERROR! private member
}

// ============================================================
// SECTION 2: ACCESS MODIFIERS IN ACTION
// ============================================================

class Vehicle {
public:
    string brand;     // Accessible everywhere
    
protected:
    int year;         // Accessible in Vehicle and derived classes
    
private:
    string vin;       // Only accessible in Vehicle
    
public:
    Vehicle(const string& b, int y, const string& v) 
        : brand(b), year(y), vin(v) {}
    
    // Public method to access private member
    string getVIN() const { return vin; }
    
    void displayInfo() const {
        cout << "Brand: " << brand << endl;
        cout << "Year: " << year << endl;
        cout << "VIN: " << vin << endl;
    }
};

class Car : public Vehicle {
public:
    Car(const string& b, int y, const string& v) : Vehicle(b, y, v) {}
    
    void showDetails() const {
        cout << "Brand: " << brand << endl;  // OK: public
        cout << "Year: " << year << endl;    // OK: protected
        // cout << "VIN: " << vin << endl;   // ERROR: private
        cout << "VIN: " << getVIN() << endl; // OK: through public method
    }
};

void demonstrateAccessModifiers() {
    cout << "\n--- Access Modifiers ---\n" << endl;
    
    Vehicle v("Toyota", 2023, "ABC123XYZ");
    cout << "Accessing from outside:" << endl;
    cout << "  Brand (public): " << v.brand << endl;
    // cout << v.year;  // ERROR: protected
    // cout << v.vin;   // ERROR: private
    cout << "  VIN (via getter): " << v.getVIN() << endl;
    
    cout << "\nCar (derived class) accessing parent:" << endl;
    Car c("Honda", 2022, "DEF456UVW");
    c.showDetails();
}

// ============================================================
// SECTION 3: GETTERS AND SETTERS
// ============================================================

class Person {
private:
    string firstName;
    string lastName;
    int age;
    
public:
    Person(const string& fn, const string& ln, int a)
        : firstName(fn), lastName(ln) {
        setAge(a);  // Use setter for validation
    }
    
    // Simple getters
    string getFirstName() const { return firstName; }
    string getLastName() const { return lastName; }
    int getAge() const { return age; }
    
    // Computed property (getter only)
    string getFullName() const {
        return firstName + " " + lastName;
    }
    
    // Setter with validation
    void setAge(int a) {
        if (a >= 0 && a <= 150) {
            age = a;
        } else {
            cout << "  Invalid age: " << a << " (keeping current: " << age << ")" << endl;
        }
    }
    
    void setFirstName(const string& fn) {
        if (!fn.empty()) {
            firstName = fn;
        }
    }
    
    void setLastName(const string& ln) {
        if (!ln.empty()) {
            lastName = ln;
        }
    }
};

void demonstrateGettersSetters() {
    cout << "\n--- Getters and Setters ---\n" << endl;
    
    Person p("John", "Doe", 30);
    
    cout << "Person: " << p.getFullName() << ", Age: " << p.getAge() << endl;
    
    // Valid update
    p.setAge(31);
    cout << "After setAge(31): " << p.getAge() << endl;
    
    // Invalid update - rejected
    p.setAge(-5);
    cout << "After setAge(-5): " << p.getAge() << " (unchanged)" << endl;
    
    p.setAge(200);
    cout << "After setAge(200): " << p.getAge() << " (unchanged)" << endl;
    
    // Update name
    p.setFirstName("Jane");
    cout << "After setFirstName(\"Jane\"): " << p.getFullName() << endl;
}

// ============================================================
// SECTION 4: REFERENCE GETTERS
// ============================================================

class DataContainer {
private:
    vector<int> data;
    string label;
    
public:
    DataContainer(const string& lbl) : label(lbl) {}
    
    // Add data
    void add(int value) {
        data.push_back(value);
    }
    
    // Const reference getter - efficient, read-only
    const vector<int>& getData() const {
        return data;
    }
    
    // Non-const reference getter - allows modification
    vector<int>& getDataMutable() {
        return data;
    }
    
    // Copy getter - less efficient but safer
    vector<int> getDataCopy() const {
        return data;  // Returns a copy
    }
    
    const string& getLabel() const {
        return label;
    }
};

void demonstrateReferenceGetters() {
    cout << "\n--- Reference Getters ---\n" << endl;
    
    DataContainer container("My Data");
    container.add(10);
    container.add(20);
    container.add(30);
    
    // Read via const reference (efficient)
    cout << "Data (const ref): ";
    for (int val : container.getData()) {
        cout << val << " ";
    }
    cout << endl;
    
    // Modify via mutable reference
    container.getDataMutable().push_back(40);
    container.getDataMutable()[0] = 100;
    
    cout << "After modification: ";
    for (int val : container.getData()) {
        cout << val << " ";
    }
    cout << endl;
    
    // Copy - modifications don't affect original
    vector<int> copy = container.getDataCopy();
    copy.push_back(999);
    
    cout << "Copy has: " << copy.size() << " elements" << endl;
    cout << "Original has: " << container.getData().size() << " elements" << endl;
}

// ============================================================
// SECTION 5: VALIDATION AND INVARIANTS
// ============================================================

class Rectangle {
private:
    double width;
    double height;
    
    // Invariant: width and height are always positive
    void validateDimension(double& dim, double value, const string& name) {
        if (value > 0) {
            dim = value;
        } else {
            cout << "  Invalid " << name << ": " << value << " (must be positive)" << endl;
        }
    }
    
public:
    Rectangle(double w, double h) : width(1), height(1) {
        setWidth(w);
        setHeight(h);
    }
    
    double getWidth() const { return width; }
    double getHeight() const { return height; }
    
    void setWidth(double w) { validateDimension(width, w, "width"); }
    void setHeight(double h) { validateDimension(height, h, "height"); }
    
    double getArea() const { return width * height; }
    double getPerimeter() const { return 2 * (width + height); }
};

class Fraction {
private:
    int numerator;
    int denominator;
    
    static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    
    // Invariant: denominator > 0, fraction is reduced
    void normalize() {
        if (denominator < 0) {
            numerator = -numerator;
            denominator = -denominator;
        }
        int g = gcd(abs(numerator), denominator);
        if (g > 0) {
            numerator /= g;
            denominator /= g;
        }
    }
    
public:
    Fraction(int num, int den) : numerator(num), denominator(1) {
        if (den == 0) {
            throw invalid_argument("Denominator cannot be zero");
        }
        denominator = den;
        normalize();
    }
    
    int getNumerator() const { return numerator; }
    int getDenominator() const { return denominator; }
    
    double toDouble() const {
        return static_cast<double>(numerator) / denominator;
    }
    
    void display() const {
        cout << numerator << "/" << denominator;
    }
};

void demonstrateValidation() {
    cout << "\n--- Validation and Invariants ---\n" << endl;
    
    cout << "Rectangle with validation:" << endl;
    Rectangle r(5.0, 3.0);
    cout << "Rectangle: " << r.getWidth() << " x " << r.getHeight() << endl;
    
    r.setWidth(-10);  // Invalid
    r.setHeight(0);   // Invalid
    cout << "After invalid setters: " << r.getWidth() << " x " << r.getHeight() << endl;
    
    cout << "\nFraction with invariant (always reduced):" << endl;
    Fraction f1(4, 8);
    cout << "4/8 normalized: ";
    f1.display();
    cout << " = " << f1.toDouble() << endl;
    
    Fraction f2(-3, -9);
    cout << "-3/-9 normalized: ";
    f2.display();
    cout << endl;
    
    Fraction f3(5, -10);
    cout << "5/-10 normalized: ";
    f3.display();
    cout << endl;
    
    try {
        Fraction bad(1, 0);  // Will throw
    } catch (const invalid_argument& e) {
        cout << "Exception: " << e.what() << endl;
    }
}

// ============================================================
// SECTION 6: FRIEND FUNCTIONS
// ============================================================

class Vector2D {
private:
    double x, y;
    
public:
    Vector2D(double xVal = 0, double yVal = 0) : x(xVal), y(yVal) {}
    
    double getX() const { return x; }
    double getY() const { return y; }
    
    // Friend function for dot product
    friend double dotProduct(const Vector2D& a, const Vector2D& b);
    
    // Friend for operator<<
    friend ostream& operator<<(ostream& os, const Vector2D& v);
};

// Friend function implementation
double dotProduct(const Vector2D& a, const Vector2D& b) {
    return a.x * b.x + a.y * b.y;  // Direct access to private members
}

ostream& operator<<(ostream& os, const Vector2D& v) {
    os << "(" << v.x << ", " << v.y << ")";
    return os;
}

void demonstrateFriendFunctions() {
    cout << "\n--- Friend Functions ---\n" << endl;
    
    Vector2D v1(3, 4);
    Vector2D v2(1, 2);
    
    cout << "v1 = " << v1 << endl;
    cout << "v2 = " << v2 << endl;
    cout << "Dot product: " << dotProduct(v1, v2) << endl;
}

// ============================================================
// SECTION 7: FRIEND CLASSES
// ============================================================

class Engine {
private:
    int horsepower;
    int rpm;
    bool running;
    
    friend class Mechanic;  // Mechanic can access everything
    
public:
    Engine(int hp) : horsepower(hp), rpm(0), running(false) {}
    
    bool isRunning() const { return running; }
    int getRPM() const { return rpm; }
    
    void start() {
        if (!running) {
            running = true;
            rpm = 800;  // Idle
            cout << "Engine started (idle at " << rpm << " RPM)" << endl;
        }
    }
    
    void stop() {
        running = false;
        rpm = 0;
        cout << "Engine stopped" << endl;
    }
};

class Mechanic {
public:
    // Can access Engine's private members
    void diagnose(const Engine& e) {
        cout << "Mechanic diagnosis:" << endl;
        cout << "  Horsepower: " << e.horsepower << endl;
        cout << "  RPM: " << e.rpm << endl;
        cout << "  Running: " << (e.running ? "Yes" : "No") << endl;
    }
    
    void repair(Engine& e, int newHP) {
        cout << "Mechanic upgrading engine from " << e.horsepower 
             << "hp to " << newHP << "hp" << endl;
        e.horsepower = newHP;  // Direct access
    }
};

void demonstrateFriendClasses() {
    cout << "\n--- Friend Classes ---\n" << endl;
    
    Engine engine(200);
    Mechanic mechanic;
    
    mechanic.diagnose(engine);
    
    cout << endl;
    engine.start();
    mechanic.diagnose(engine);
    
    cout << endl;
    mechanic.repair(engine, 250);
    mechanic.diagnose(engine);
}

// ============================================================
// SECTION 8: IMMUTABLE CLASS
// ============================================================

class ImmutablePoint {
private:
    const double x;
    const double y;
    
public:
    ImmutablePoint(double xVal, double yVal) : x(xVal), y(yVal) {}
    
    double getX() const { return x; }
    double getY() const { return y; }
    
    // Cannot modify - return new object instead
    ImmutablePoint translate(double dx, double dy) const {
        return ImmutablePoint(x + dx, y + dy);
    }
    
    ImmutablePoint scale(double factor) const {
        return ImmutablePoint(x * factor, y * factor);
    }
    
    double distanceTo(const ImmutablePoint& other) const {
        double dx = x - other.x;
        double dy = y - other.y;
        return sqrt(dx * dx + dy * dy);
    }
    
    friend ostream& operator<<(ostream& os, const ImmutablePoint& p) {
        return os << "(" << p.x << ", " << p.y << ")";
    }
};

void demonstrateImmutability() {
    cout << "\n--- Immutable Class ---\n" << endl;
    
    ImmutablePoint p1(3, 4);
    cout << "Original point: " << p1 << endl;
    
    // Operations return new objects
    ImmutablePoint p2 = p1.translate(1, 2);
    cout << "After translate(1, 2): " << p2 << endl;
    cout << "Original unchanged: " << p1 << endl;
    
    ImmutablePoint p3 = p1.scale(2);
    cout << "After scale(2): " << p3 << endl;
    
    cout << "Distance from p1 to p2: " << p1.distanceTo(p2) << endl;
}

// ============================================================
// SECTION 9: COMPLETE ENCAPSULATED CLASS
// ============================================================

class Employee {
private:
    static int nextId;
    
    const int id;
    string name;
    string department;
    double salary;
    
    // Private validation
    bool isValidSalary(double s) const {
        return s >= 0;
    }
    
public:
    Employee(const string& n, const string& dept, double sal)
        : id(nextId++), name(n), department(dept), salary(0) {
        setSalary(sal);
    }
    
    // Getters
    int getId() const { return id; }
    const string& getName() const { return name; }
    const string& getDepartment() const { return department; }
    double getSalary() const { return salary; }
    
    // Setters with validation
    void setName(const string& n) {
        if (!n.empty()) name = n;
    }
    
    void setDepartment(const string& dept) {
        if (!dept.empty()) department = dept;
    }
    
    void setSalary(double s) {
        if (isValidSalary(s)) {
            salary = s;
        } else {
            cout << "Invalid salary for " << name << endl;
        }
    }
    
    // Operations
    void giveRaise(double percent) {
        if (percent > 0) {
            salary *= (1 + percent / 100);
            cout << name << " received " << percent << "% raise" << endl;
        }
    }
    
    // Display
    friend ostream& operator<<(ostream& os, const Employee& e) {
        os << "Employee #" << e.id << ": " << e.name 
           << " (" << e.department << ") - $" << e.salary;
        return os;
    }
};

int Employee::nextId = 1000;

void demonstrateCompleteExample() {
    cout << "\n--- Complete Encapsulated Class ---\n" << endl;
    
    Employee emp1("Alice Smith", "Engineering", 75000);
    Employee emp2("Bob Johnson", "Marketing", 65000);
    
    cout << emp1 << endl;
    cout << emp2 << endl;
    
    cout << endl;
    emp1.giveRaise(10);
    cout << emp1 << endl;
    
    emp2.setDepartment("Sales");
    cout << emp2 << endl;
    
    emp1.setSalary(-1000);  // Invalid - will be rejected
}

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

int main() {
    cout << "╔════════════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                  C++ ENCAPSULATION - EXAMPLES                      ║" << endl;
    cout << "║                Data Protection and Access Control                  ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 1: Basic Encapsulation                  ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateBasicEncapsulation();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 2: Access Modifiers                     ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateAccessModifiers();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 3: Getters and Setters                  ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateGettersSetters();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 4: Reference Getters                    ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateReferenceGetters();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 5: Validation and Invariants            ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateValidation();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 6: Friend Functions                     ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateFriendFunctions();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 7: Friend Classes                       ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateFriendClasses();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 8: Immutable Class                      ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateImmutability();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 9: Complete Example                     ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateCompleteExample();
    
    cout << "\n╔════════════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                       Examples Complete!                           ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
    
    return 0;
}
Examples - C++ Tutorial | DeepML