Menu

System Programming Topic

C++ Object-Oriented Programming

1. Classes & Objects

Classes - Blueprint/template for creating objects

cpp

#include <iostream>
#include <string>
using namespace std;

// CLASS DEFINITION: Blueprint for objects
class Student {
private:    // Access specifier - only class members can access
    string name;
    int age;
    double gpa;
    
public:     // Access specifier - accessible from outside
    // Member functions (methods)
    void displayInfo() {
        cout << "Name: " << name << endl;
        cout << "Age: " << age << endl;
        cout << "GPA: " << gpa << endl;
    }
    
    // Setter functions (mutators)
    void setName(string n) {
        name = n;
    }
    
    void setAge(int a) {
        if (a > 0) age = a;
    }
    
    void setGPA(double g) {
        if (g >= 0.0 && g <= 4.0) gpa = g;
    }
    
    // Getter functions (accessors)
    string getName() { return name; }
    int getAge() { return age; }
    double getGPA() { return gpa; }
};

// OBJECT CREATION - Instance of a class
int main() {
    // Creating objects
    Student student1;           // Object creation using default constructor
    Student student2;           // Another independent object
    
    // Accessing member functions using dot operator
    student1.setName("Alice");
    student1.setAge(20);
    student1.setGPA(3.8);
    
    student2.setName("Bob");
    student2.setAge(22);
    student2.setGPA(3.5);
    
    // Display information
    cout << "Student 1:" << endl;
    student1.displayInfo();
    
    cout << "\nStudent 2:" << endl;
    student2.displayInfo();
    
    // Accessing data through getters
    cout << "\nStudent 1's GPA: " << student1.getGPA() << endl;
    
    return 0;
}

Access Specifiers & Member Functions

cpp

#include <iostream>
using namespace std;

class BankAccount {
private:        // Encapsulation: Data hiding
    double balance;
    string accountNumber;
    
protected:      // Accessible in this class and derived classes
    string bankName;
    
public:         // Public interface
    // Member function types:
    
    // 1. Accessor (getter) - const member function
    double getBalance() const {
        return balance;
    }
    
    // 2. Mutator (setter)
    void setAccountNumber(string accNum) {
        accountNumber = accNum;
    }
    
    // 3. Utility function
    void displayAccountInfo() const {
        cout << "Account: " << accountNumber << endl;
        cout << "Balance: $" << balance << endl;
        cout << "Bank: " << bankName << endl;
    }
    
    // 4. Operation function
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "Deposited: $" << amount << endl;
        }
    }
    
    bool withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            cout << "Withdrawn: $" << amount << endl;
            return true;
        }
        cout << "Insufficient funds!" << endl;
        return false;
    }
};

int main() {
    BankAccount account;
    // account.balance = 1000;  // Error: private member
    account.deposit(1000);
    account.displayAccountInfo();
    
    return 0;
}

2. Constructors & Destructors

Constructors - Special functions called when object is created

cpp

#include <iostream>
#include <string>
using namespace std;

class Book {
private:
    string title;
    string author;
    double price;
    int pages;
    
public:
    // 1. DEFAULT CONSTRUCTOR - No parameters
    Book() {
        title = "Unknown";
        author = "Unknown";
        price = 0.0;
        pages = 0;
        cout << "Default constructor called!" << endl;
    }
    
    // 2. PARAMETERIZED CONSTRUCTOR - Takes parameters
    Book(string t, string a, double p, int pg) {
        title = t;
        author = a;
        price = p;
        pages = pg;
        cout << "Parameterized constructor called!" << endl;
    }
    
    // 3. COPY CONSTRUCTOR - Creates copy of another object
    Book(const Book& other) {
        title = other.title;
        author = other.author;
        price = other.price;
        pages = other.pages;
        cout << "Copy constructor called!" << endl;
    }
    
    // 4. CONSTRUCTOR WITH DEFAULT ARGUMENTS
    Book(string t, string a = "Anonymous", double p = 0.0) {
        title = t;
        author = a;
        price = p;
        pages = 100;
    }
    
    // 5. DESTRUCTOR - Called when object is destroyed
    ~Book() {
        cout << "Destructor called for: " << title << endl;
    }
    
    // Member function
    void display() {
        cout << "Title: " << title << endl;
        cout << "Author: " << author << endl;
        cout << "Price: $" << price << endl;
        cout << "Pages: " << pages << endl;
    }
    
    // Setter for copy demonstration
    void setTitle(string t) { title = t; }
};

int main() {
    cout << "=== CONSTRUCTORS DEMO ===\n" << endl;
    
    // 1. Default constructor
    Book book1;
    book1.display();
    
    // 2. Parameterized constructor
    Book book2("C++ Programming", "Bjarne Stroustrup", 49.99, 500);
    book2.display();
    
    // 3. Constructor with default arguments
    Book book3("Learn Python");
    book3.display();
    
    // 4. Copy constructor (3 ways it's called)
    cout << "\n=== COPY CONSTRUCTOR SCENARIOS ===" << endl;
    
    // a) Explicit copy
    Book book4 = book2;          // Copy constructor
    book4.setTitle("Copy of C++");
    book4.display();
    
    // b) Passing object by value to function
    // (Destructor shows when copies are destroyed)
    
    // c) Returning object from function
    
    // 5. Dynamic object creation
    cout << "\n=== DYNAMIC OBJECTS ===" << endl;
    Book* ptrBook = new Book("Dynamic Book", "Author", 29.99, 300);
    ptrBook->display();
    delete ptrBook;  // Destructor called
    
    cout << "\n=== END OF MAIN - Destructors will be called ===" << endl;
    return 0;
}
// Destructors for book1, book2, book3, book4 called here

3. Inheritance

Inheritance - Creating new classes from existing ones (IS-A relationship)

cpp

#include <iostream>
#include <string>
using namespace std;

// BASE CLASS (Parent/Super class)
class Vehicle {
protected:  // Accessible in derived classes
    string brand;
    string model;
    int year;
    
public:
    Vehicle(string b, string m, int y) : brand(b), model(m), year(y) {
        cout << "Vehicle constructor called" << endl;
    }
    
    void displayInfo() {
        cout << "Brand: " << brand << endl;
        cout << "Model: " << model << endl;
        cout << "Year: " << year << endl;
    }
    
    void honk() {
        cout << "Beep beep!" << endl;
    }
};

// 1. SINGLE INHERITANCE - One base class
class Car : public Vehicle {  // Derived class (Child/Sub class)
private:
    int doors;
    string fuelType;
    
public:
    // Constructor with initialization list
    Car(string b, string m, int y, int d, string f) 
        : Vehicle(b, m, y), doors(d), fuelType(f) {
        cout << "Car constructor called" << endl;
    }
    
    void displayCarInfo() {
        displayInfo();  // Call base class function
        cout << "Doors: " << doors << endl;
        cout << "Fuel: " << fuelType << endl;
    }
};

// 2. MULTILEVEL INHERITANCE - Chain of inheritance
class SportsCar : public Car {
private:
    double topSpeed;
    
public:
    SportsCar(string b, string m, int y, int d, string f, double ts)
        : Car(b, m, y, d, f), topSpeed(ts) {
        cout << "SportsCar constructor called" << endl;
    }
    
    void displaySportsInfo() {
        displayCarInfo();
        cout << "Top Speed: " << topSpeed << " mph" << endl;
    }
    
    void race() {
        cout << "Racing at high speed!" << endl;
    }
};

// 3. MULTIPLE INHERITANCE - Inheriting from multiple base classes
class Engine {
protected:
    int horsepower;
    
public:
    Engine(int hp) : horsepower(hp) {}
    
    void startEngine() {
        cout << "Engine started with " << horsepower << " HP" << endl;
    }
};

class Electric {
protected:
    int batteryCapacity;
    
public:
    Electric(int cap) : batteryCapacity(cap) {}
    
    void charge() {
        cout << "Charging battery: " << batteryCapacity << " kWh" << endl;
    }
};

// Multiple inheritance
class ElectricCar : public Car, public Electric {
public:
    ElectricCar(string b, string m, int y, int d, string f, int cap)
        : Car(b, m, y, d, f), Electric(cap) {
        cout << "ElectricCar constructor called" << endl;
    }
    
    void displayElectricInfo() {
        displayCarInfo();
        charge();
    }
};

// ACCESS CONTROL in inheritance
class Base {
private:    // Only Base can access
    int privateVar = 1;
    
protected:  // Base and derived classes can access
    int protectedVar = 2;
    
public:     // Anyone can access
    int publicVar = 3;
    
    void show() {
        cout << "Private: " << privateVar << endl;  // OK
    }
};

// Different types of inheritance
class DerivedPublic : public Base {
    // publicVar stays public
    // protectedVar stays protected
    // privateVar is inaccessible
};

class DerivedPrivate : private Base {
    // publicVar becomes private
    // protectedVar becomes private
    // privateVar is inaccessible
};

class DerivedProtected : protected Base {
    // publicVar becomes protected
    // protectedVar stays protected
    // privateVar is inaccessible
};

int main() {
    cout << "=== SINGLE INHERITANCE ===" << endl;
    Car myCar("Toyota", "Camry", 2022, 4, "Gasoline");
    myCar.displayCarInfo();
    myCar.honk();  // Inherited from Vehicle
    
    cout << "\n=== MULTILEVEL INHERITANCE ===" << endl;
    SportsCar ferrari("Ferrari", "F8", 2023, 2, "Gasoline", 211);
    ferrari.displaySportsInfo();
    ferrari.race();
    
    cout << "\n=== MULTIPLE INHERITANCE ===" << endl;
    ElectricCar tesla("Tesla", "Model 3", 2023, 4, "Electric", 75);
    tesla.displayElectricInfo();
    tesla.startEngine();  // If Engine was also inherited
    
    cout << "\n=== ACCESS CONTROL ===" << endl;
    DerivedPublic dp;
    cout << "Public var: " << dp.publicVar << endl;  // OK
    // cout << dp.protectedVar;  // Error: protected
    // cout << dp.privateVar;    // Error: private
    
    return 0;
}

4. Polymorphism

Polymorphism - "Many forms", same interface, different implementations

cpp

#include <iostream>
using namespace std;

// BASE CLASS with virtual function
class Shape {
protected:
    string color;
    
public:
    Shape(string c) : color(c) {}
    
    // VIRTUAL FUNCTION - Enables runtime polymorphism
    virtual double calculateArea() const {
        cout << "Shape area calculation" << endl;
        return 0.0;
    }
    
    // PURE VIRTUAL FUNCTION - Makes class abstract
    virtual void draw() const = 0;  // Abstract class
    
    virtual ~Shape() {  // Virtual destructor
        cout << "Shape destructor" << endl;
    }
    
    void setColor(string c) { color = c; }
    string getColor() const { return color; }
};

// DERIVED CLASS 1
class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(string c, double r) : Shape(c), radius(r) {}
    
    // FUNCTION OVERRIDING - Same signature, different implementation
    double calculateArea() const override {  // override keyword ensures correct override
        return 3.14159 * radius * radius;
    }
    
    void draw() const override {
        cout << "Drawing a " << color << " circle" << endl;
    }
    
    ~Circle() {
        cout << "Circle destructor" << endl;
    }
};

// DERIVED CLASS 2
class Rectangle : public Shape {
private:
    double length, width;
    
public:
    Rectangle(string c, double l, double w) : Shape(c), length(l), width(w) {}
    
    double calculateArea() const override {
        return length * width;
    }
    
    void draw() const override {
        cout << "Drawing a " << color << " rectangle" << endl;
    }
    
    ~Rectangle() {
        cout << "Rectangle destructor" << endl;
    }
};

// DERIVED CLASS 3
class Triangle : public Shape {
private:
    double base, height;
    
public:
    Triangle(string c, double b, double h) : Shape(c), base(b), height(h) {}
    
    double calculateArea() const override {
        return 0.5 * base * height;
    }
    
    void draw() const override {
        cout << "Drawing a " << color << " triangle" << endl;
    }
};

// Demonstrating POLYMORPHISM
void printArea(const Shape& shape) {
    cout << "Area: " << shape.calculateArea() << endl;
}

void drawShape(const Shape* shape) {
    shape->draw();
}

int main() {
    cout << "=== RUNTIME POLYMORPHISM ===\n" << endl;
    
    // Base class pointer to derived class objects
    Shape* shapes[3];
    
    shapes[0] = new Circle("Red", 5.0);
    shapes[1] = new Rectangle("Blue", 4.0, 6.0);
    shapes[2] = new Triangle("Green", 3.0, 4.0);
    
    // Same interface, different implementations
    for (int i = 0; i < 3; i++) {
        cout << "Shape " << i + 1 << ": ";
        shapes[i]->draw();
        cout << "Color: " << shapes[i]->getColor() << endl;
        cout << "Area: " << shapes[i]->calculateArea() << endl;
        cout << endl;
    }
    
    // Using references
    Circle circle("Yellow", 3.0);
    Rectangle rectangle("Purple", 5.0, 2.0);
    
    cout << "Using printArea function:" << endl;
    printArea(circle);      // Calls Circle::calculateArea()
    printArea(rectangle);   // Calls Rectangle::calculateArea()
    
    // Clean up
    for (int i = 0; i < 3; i++) {
        delete shapes[i];
    }
    
    cout << "\n=== FUNCTION OVERRIDING VS OVERLOADING ===" << endl;
    
    return 0;
}

// Example showing override keyword importance
class BaseClass {
public:
    virtual void display(int x) {
        cout << "Base: " << x << endl;
    }
};

class DerivedClass : public BaseClass {
public:
    // Error if uncommented (detected by override keyword)
    // void display(double x) override {  // Error: doesn't override
    //     cout << "Derived: " << x << endl;
    // }
    
    void display(int x) override {  // Correct override
        cout << "Derived: " << x << endl;
    }
};

5. Encapsulation & Abstraction

Encapsulation - Bundling data and methods, hiding implementation details

Abstraction - Showing only essential features, hiding complexity

cpp

#include <iostream>
#include <string>
using namespace std;

// ENCAPSULATION EXAMPLE
class BankAccount {
private:  // Data hiding - internal details hidden
    string accountNumber;
    double balance;
    string password;
    
    // Private helper methods (implementation details hidden)
    bool authenticate(string pwd) {
        return pwd == password;
    }
    
    void logTransaction(string type, double amount) {
        cout << "[LOG] " << type << ": $" << amount << endl;
    }
    
public:  // Public interface - what users can do
    BankAccount(string accNum, string pwd, double initial = 0.0) 
        : accountNumber(accNum), password(pwd), balance(initial) {}
    
    // Abstraction: Simple interface for complex operations
    bool deposit(double amount, string pwd) {
        if (!authenticate(pwd)) {
            cout << "Authentication failed!" << endl;
            return false;
        }
        
        if (amount > 0) {
            balance += amount;
            logTransaction("DEPOSIT", amount);
            return true;
        }
        return false;
    }
    
    bool withdraw(double amount, string pwd) {
        if (!authenticate(pwd)) {
            cout << "Authentication failed!" << endl;
            return false;
        }
        
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            logTransaction("WITHDRAW", amount);
            return true;
        }
        cout << "Invalid amount or insufficient funds!" << endl;
        return false;
    }
    
    double getBalance(string pwd) {
        if (authenticate(pwd)) {
            return balance;
        }
        cout << "Authentication failed!" << endl;
        return -1;
    }
    
    // Users don't need to know about authentication or logging
};

// ABSTRACTION with Abstract Classes (Interfaces)
class Vehicle {  // Abstract class (interface)
public:
    // Pure virtual functions = abstract methods
    virtual void start() = 0;      // Must be implemented by derived classes
    virtual void stop() = 0;
    virtual void honk() = 0;
    
    // Concrete method (can have implementation)
    void displayType() {
        cout << "I am a Vehicle" << endl;
    }
    
    virtual ~Vehicle() {}  // Virtual destructor
};

// Concrete implementation
class Car : public Vehicle {
private:
    string model;
    
public:
    Car(string m) : model(m) {}
    
    void start() override {
        cout << model << " car started with key" << endl;
    }
    
    void stop() override {
        cout << model << " car stopped" << endl;
    }
    
    void honk() override {
        cout << model << " car goes Beep Beep!" << endl;
    }
};

class Bike : public Vehicle {
public:
    void start() override {
        cout << "Bike started with kick" << endl;
    }
    
    void stop() override {
        cout << "Bike stopped with brakes" << endl;
    }
    
    void honk() override {
        cout << "Bike goes Ring Ring!" << endl;
    }
};

// Using abstraction - client code works with Vehicle interface
void operateVehicle(Vehicle* v) {
    v->start();
    v->honk();
    v->stop();
    cout << endl;
}

// Complete example combining concepts
class SmartHomeDevice {
private:  // ENCAPSULATION
    string deviceId;
    bool isOn;
    int powerConsumption;
    
protected:  // For inheritance
    string location;
    
public:  // ABSTRACTION
    SmartHomeDevice(string id, string loc, int power = 0)
        : deviceId(id), location(loc), powerConsumption(power), isOn(false) {}
    
    virtual void turnOn() {  // Can be overridden
        isOn = true;
        cout << deviceId << " turned ON" << endl;
    }
    
    virtual void turnOff() {
        isOn = false;
        cout << deviceId << " turned OFF" << endl;
    }
    
    virtual void getStatus() {  // Can be overridden
        cout << "Device: " << deviceId << endl;
        cout << "Location: " << location << endl;
        cout << "Status: " << (isOn ? "ON" : "OFF") << endl;
        cout << "Power: " << powerConsumption << "W" << endl;
    }
    
    // Pure virtual function - makes class abstract
    virtual void performAction() = 0;
    
    virtual ~SmartHomeDevice() {}
};

// Concrete implementations
class SmartLight : public SmartHomeDevice {
private:
    int brightness;
    string color;
    
public:
    SmartLight(string id, string loc) 
        : SmartHomeDevice(id, loc, 10), brightness(50), color("White") {}
    
    void turnOn() override {
        SmartHomeDevice::turnOn();
        cout << "Light brightness: " << brightness << "%" << endl;
    }
    
    void performAction() override {
        cout << "Emitting " << color << " light at " << brightness << "% brightness" << endl;
    }
    
    void setBrightness(int level) {  // Extended functionality
        brightness = level;
        cout << "Brightness set to " << brightness << "%" << endl;
    }
    
    void setColor(string c) {
        color = c;
        cout << "Color changed to " << color << endl;
    }
};

class SmartThermostat : public SmartHomeDevice {
private:
    double temperature;
    
public:
    SmartThermostat(string id, string loc, double temp = 22.0)
        : SmartHomeDevice(id, loc, 5), temperature(temp) {}
    
    void performAction() override {
        cout << "Maintaining temperature at " << temperature << "°C" << endl;
    }
    
    void setTemperature(double temp) {
        temperature = temp;
        cout << "Temperature set to " << temperature << "°C" << endl;
    }
};

int main() {
    cout << "=== ENCAPSULATION EXAMPLE ===" << endl;
    BankAccount myAccount("ACC123", "secret123", 1000.0);
    
    // User interacts with simple interface
    myAccount.deposit(500, "secret123");
    myAccount.withdraw(200, "secret123");
    cout << "Balance: $" << myAccount.getBalance("secret123") << endl;
    
    // Can't access internal details
    // myAccount.balance = 10000;  // Error: private
    // myAccount.password = "hack"; // Error: private
    
    cout << "\n=== ABSTRACTION EXAMPLE ===" << endl;
    Car toyota("Toyota");
    Bike bmx;
    
    operateVehicle(&toyota);
    operateVehicle(&bmx);
    
    // Working with abstract interface
    Vehicle* garage[2];
    garage[0] = new Car("Honda");
    garage[1] = new Bike();
    
    for (int i = 0; i < 2; i++) {
        garage[i]->displayType();
        garage[i]->start();
        garage[i]->honk();
        cout << endl;
    }
    
    cout << "\n=== SMART HOME EXAMPLE (Combined) ===" << endl;
    SmartLight livingRoomLight("LR1", "Living Room");
    SmartThermostat hallThermostat("TH1", "Hall", 22.5);
    
    livingRoomLight.turnOn();
    livingRoomLight.setBrightness(75);
    livingRoomLight.setColor("Warm White");
    livingRoomLight.performAction();
    
    cout << endl;
    
    hallThermostat.turnOn();
    hallThermostat.setTemperature(21.5);
    hallThermostat.performAction();
    
    // Clean up
    for (int i = 0; i < 2; i++) {
        delete garage[i];
    }
    
    return 0;
}

Key OOP Principles Summary:

  1. Encapsulation: Bundle data + methods, hide implementation details

    • Uses private/protected access specifiers

    • Provides getters/setters for controlled access

  2. Inheritance: Create new classes from existing ones

    • Promotes code reuse

    • Types: Single, Multilevel, Multiple

    • Access control: public, protected, private inheritance

  3. Polymorphism: Same interface, different implementations

    • Compile-time: Function overloading, operator overloading

    • Runtime: Virtual functions, function overriding

    • Uses virtual keyword and base class pointers/references

  4. Abstraction: Show only essential features

    • Abstract classes with pure virtual functions

    • Interfaces define what can be done, not how

    • Reduces complexity for users

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?