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?
- Encapsulation: Bundling data and methods into a class, controlling access via access specifiers (
public,private,protected). - Inheritance: Allowing a class (derived) to inherit properties and methods from another class (base) for code reuse.
- Polymorphism: Enabling objects to be treated as instances of their base class, with different behaviors (via function overriding or overloading).
- Abstraction: Hiding complex implementation details and exposing only necessary functionality.
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:
public: Members accessible everywhere.private: Members accessible only within the class (default forclass).protected: Members accessible in the class and derived classes.
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:
- Compile-Time Polymorphism: Function overloading, operator overloading.
- Run-Time Polymorphism: Virtual functions and overriding in inheritance.
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:
- Classes: Encapsulate data and methods.
- Abstract Classes: Classes with pure virtual functions (
= 0) that cannot be instantiated.
Example:
class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};
Q: How does C++ differ from C in terms of OOP?
- C++: Supports OOP with classes, inheritance, polymorphism, and encapsulation.
- C: Lacks native OOP; uses structs for data grouping without methods or inheritance.
- C++ Advantages: References, function overloading, virtual functions, and STL for OOP-based DSA.
Q: How is OOP used in DSA?
- Classes for Data Structures: Represent nodes (e.g., linked lists, trees) or entire structures (e.g., stacks, queues).
- Inheritance: Reuse common functionality (e.g., a base Graph class for directed/undirected graphs).
- Polymorphism: Implement algorithms with interchangeable types (e.g., different sorting strategies).
- Encapsulation: Protect data integrity (e.g., private node pointers in a tree).
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++?
- Access Specifiers: Forgetting
public/private(defaults toprivateinclass). - Constructor Issues: Not initializing members, leading to undefined behavior.
- Memory Leaks: Forgetting to
deletedynamically allocated objects in polymorphism. - Virtual Function Errors: Omitting
virtualkeyword, breaking run-time polymorphism. - Inheritance Misuse: Overusing inheritance instead of composition.
Q: What are best practices for OOP in C++?
- Use
privatefor data members to enforce encapsulation. - Provide public getters/setters for controlled access.
- Use constructors to initialize objects safely.
- Use
virtualfunctions for polymorphism andoverridecarefully. - Prefer composition over inheritance for flexibility.
- Use
constfor methods that don't modify objects (e.g.,void display() const). - Free dynamically allocated memory in destructors or use smart pointers.