C++ Object-Oriented Programming: Classes, Inheritance, Polymorphism, Encapsulation & Abstraction

1. Object-Oriented Programming

Q: What is Object-Oriented Programming (OOP) in C++?

OOP is a programming paradigm that organizes code around objects, which are instances of classes combining data (attributes) and behavior (methods). C++ supports OOP through features like classes, inheritance, polymorphism, and encapsulation, making it ideal for modular and reusable code in DSA (e.g., implementing graphs or trees as classes).

Q: What are the core principles of OOP?

Q: What is a class and an object in C++?

Class: A blueprint defining data (members) and functions (methods) for objects.

Syntax:

class ClassName {
public:
    // Members and methods
};

Object: An instance of a class, created to use its data and methods.

Example: ClassName obj;

Q: How do you declare and use a class in C++?

Use the class keyword, define members and methods, and create objects to access them.

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

class Student {
private:
    string name; // Encapsulated data
    int id;
public:
    // Constructor
    Student(string n, int i) : name(n), id(i) {}
    
    // Method
    void display() {
        cout << "Name: " << name << ", ID: " << id << endl;
    }
};

int main() {
    // Create objects
    Student s1("John", 101);
    Student s2("Kristal", 102);
    
    // Call methods
    s1.display(); // Output: Name: John, ID: 101
    s2.display(); // Output: Name: Kristal, ID: 102
    
    return 0;
}

Q: What is encapsulation and how is it implemented in C++?

Encapsulation hides data and restricts access to protect object integrity, achieved using access specifiers:

Example: Private data (name, id) with public methods (display) in the above code.

Q: What is inheritance and how is it implemented in C++?

Inheritance allows a derived class to inherit members from a base class, promoting code reuse.

Syntax:

class Derived : access_specifier Base {
    // Additional members
};

Example:

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

class Person {
protected:
    string name;
public:
    Person(string n) : name(n) {}
    void introduce() {
        cout << "I am " << name << endl;
    }
};

class Student : public Person {
private:
    int id;
public:
    Student(string n, int i) : Person(n), id(i) {}
    void display() {
        cout << "Student: " << name << ", ID: " << id << endl;
    }
};

int main() {
    Student s("Kristal", 101);
    s.introduce(); // From base class
    s.display();   // From derived class
    return 0;
}

Output:

I am Kristal
Student: Kristal, ID: 101

Q: What is polymorphism in C++?

Polymorphism allows objects to be treated as instances of a base class with different behaviors. C++ supports:

Example (Run-Time):

#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() { // Virtual function
        cout << "Drawing a shape" << endl;
    }
};

class Circle : public Shape {
public:
    void draw() override { // Override base class method
        cout << "Drawing a circle" << endl;
    }
};

class Square : public Shape {
public:
    void draw() override {
        cout << "Drawing a square" << endl;
    }
};

int main() {
    Shape* shapes[] = {new Circle(), new Square()};
    for (int i = 0; i < 2; i++) {
        shapes[i]->draw(); // Run-time polymorphism
        delete shapes[i];  // Free memory
    }
    return 0;
}

Output:

Drawing a circle
Drawing a square

Q: What is abstraction in C++?

Abstraction hides implementation details, exposing only essential functionality. It's achieved using:

Example:

class Shape {
public:
    virtual void draw() = 0; // Pure virtual function
};

Q: How does C++ differ from C in terms of OOP?

Q: How is OOP used in DSA?

Q: Can you give a DSA-related example using OOP?

Example: A simple stack implementation using a class.

#include <iostream>
using namespace std;

class Stack {
private:
    static const int MAX = 100;
    int arr[MAX];
    int top;
public:
    Stack() : top(-1) {} // Constructor
    void push(int value) {
        if (top >= MAX - 1) {
            cout << "Stack Overflow" << endl;
            return;
        }
        arr[++top] = value;
    }
    int pop() {
        if (top < 0) {
            cout << "Stack Underflow" << endl;
            return -1;
        }
        return arr[top--];
    }
    bool isEmpty() {
        return top < 0;
    }
};

int main() {
    Stack s;
    s.push(1);
    s.push(2);
    s.push(3);
    cout << "Popped: " << s.pop() << endl; // 3
    cout << "Popped: " << s.pop() << endl; // 2
    cout << "Is empty? " << boolalpha << s.isEmpty() << endl; // false
    cout << "Popped: " << s.pop() << endl; // 1
    cout << "Is empty? " << s.isEmpty() << endl; // true
    return 0;
}

Output:

Popped: 3
Popped: 2
Is empty? false
Popped: 1
Is empty? true

Q: What are common mistakes with OOP in C++?

Q: What are best practices for OOP in C++?