QUESTIONS TO COVER IN OOPS:
What are the four pillars of OOP?
Explain the concept of inheritance.
What is the difference between composition and inheritance?
What is encapsulation? Why is it important?
What is polymorphism? Explain with examples.
What is abstraction? How is it different from encapsulation?
What is method overloading vs method overriding?
Can you override a static method in Java/C++?
What is dynamic vs static polymorphism?
How does the ‘this’ keyword work in OOP languages?
✅ Class & Object-Level Questions
What is the difference between a class and an object?
What are constructors? Can constructors be inherited?
What is a copy constructor?
What is object slicing?
What is the difference between shallow copy and deep copy?
✅ Inheritance-Related Questions
What are different types of inheritance (single, multiple, multilevel)?
How is multiple inheritance handled in languages like C++ and Java?
What is the diamond problem in multiple inheritance? How is it solved?
Can a class implement multiple interfaces?
Why is interface preferred over multiple inheritance?
✅ Design & Practical Implementation
What is SOLID in OOP? Explain each principle.
What is the difference between an abstract class and an interface?
When would you use an abstract class vs an interface?
What is dependency injection? How is it related to OOP?
What are access modifiers? How do they affect encapsulation?
✅ Advanced & Common Pitfalls
What is cohesion and coupling? Why do they matter in OOP design?
What is object-oriented design? How is it different from object-oriented programming?
How would you refactor a large class violating SRP (Single Responsibility Principle)?
What is a virtual function?
What is the Liskov Substitution Principle?
ANSWERS:
Q1: What are the four pillars of OOP?
Answer:
The four pillars of Object-Oriented Programming are Encapsulation, Inheritance, Polymorphism, and Abstraction.
Encapsulation: Hiding data and exposing only necessary details.
Inheritance: Reusing code by creating new classes from existing ones.
Polymorphism: Same method behaving differently based on the object.
Abstraction: Showing only essential features and hiding implementation details.
Example:
A Car class can encapsulate properties like speed, model, and methods like drive(). A SportsCar can inherit from Car.
Polymorphism lets different cars implement drive() differently. Abstraction is like a driver only using steering/brakes
without knowing engine internals.
Confident phrasing:
“The four pillars are Encapsulation, Inheritance, Polymorphism, and Abstraction. Together, they help in making code
more modular, reusable, and easier to maintain.”
Q2: Explain the concept of inheritance.
Answer:
Inheritance allows a class (child/derived) to acquire properties and methods from another class (parent/base). It
promotes code reusability and hierarchical relationships.
Example with Syntax (Python):
class Animal:
def speak(self):
print("This is an animal.")
class Dog(Animal): # Dog inherits from Animal
def speak(self):
print("Bark!")
d = Dog()
d.speak() # Output: Bark!
Confident phrasing:
“Inheritance means creating new classes from existing ones. For example, a Dog class can inherit from an Animal
class and reuse or override its methods.”
Q3: What is the difference between composition and inheritance?
Answer:
Inheritance: Defines an “is-a” relationship. A child class extends the parent class.
Composition: Defines a “has-a” relationship. A class contains an object of another class.
Example:
Inheritance: A Car is a type of Vehicle.
Composition: A Car has a Engine.
Code (Python):
# Inheritance
class Vehicle: pass
class Car(Vehicle): pass # Car is a Vehicle
# Composition
class Engine: pass
class Car:
def __init__(self):
self.engine = Engine() # Car has an Engine
Confident phrasing:
“Inheritance models an ‘is-a’ relationship, while composition models a ‘has-a’ relationship. For example, a Car is a
Vehicle (inheritance) but a Car has an Engine (composition).”
Q4: What is encapsulation? Why is it important?
Answer:
Encapsulation is the practice of binding data (variables) and methods together and restricting direct access to some
components. It improves data security, control, and maintainability.
Example (Python):
class BankAccount:
def __init__(self, balance):
self.__balance = balance # private variable
def deposit(self, amount):
self.__balance += amount
return self.__balance
Confident phrasing:
“Encapsulation means restricting direct access to data and only exposing controlled methods. For example, in a
BankAccount class, the balance is private and can only be changed using deposit or withdraw methods. This ensures
security and prevents misuse.”
Q5: What is polymorphism? Explain with examples.
Answer:
Polymorphism means many forms – the same method or operator behaves differently depending on the object. It
can be:
Compile-time (overloading) – Same method name with different parameters.
Runtime (overriding) – Subclass provides its own implementation of a parent method.
Example (Python):
# Runtime polymorphism (method overriding)
class Bird:
def speak(self):
print("Bird sound")
class Parrot(Bird):
def speak(self):
print("Parrot says hello!")
class Crow(Bird):
def speak(self):
print("Crow caws!")
for bird in [Parrot(), Crow()]:
bird.speak()
Output:
Parrot says hello!
Crow caws!
Confident phrasing:
“Polymorphism means the same method can behave differently depending on the object. For instance, a Parrot and a
Crow both implement speak(), but the behavior changes based on the object calling it.”
Q6: What is abstraction? How is it different from encapsulation?
Answer:
Abstraction: Hides implementation details and only shows the essential features to the user.
Encapsulation: Restricts direct access to data and binds it with methods.
Example:
Abstraction: When you drive a car, you only use the steering and brakes, but don’t see how the engine works
internally.
Encapsulation: The car’s internal engine parts are protected inside, and you can’t directly manipulate them.
Code (Python):
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Circle(Shape):
def __init__(self, r): self.r = r
def area(self):
return 3.14 * self.r * self.r
Confident phrasing:
“Abstraction focuses on hiding implementation details and showing only functionality, while encapsulation hides the
internal data and provides controlled access. For example, abstraction is like using a car’s steering, and encapsulation
is the engine being hidden inside.”
Q7: What is method overloading vs method overriding?
Answer:
Overloading (Compile-time polymorphism): Same method name but with different parameter lists (number
or type).
Overriding (Runtime polymorphism): Subclass provides its own implementation of a parent class method
with the same signature.
Example (Java-like syntax):
// Overloading
class MathOps {
int add(int a, int b) { return a+b; }
double add(double a, double b) { return a+b; }
// Overriding
class Animal {
void sound() { System.out.println("Animal sound"); }
class Dog extends Animal {
void sound() { System.out.println("Bark"); }
Confident phrasing:
“Overloading happens at compile time with different method signatures, while overriding happens at runtime when
a subclass redefines a parent method. For example, add(int, int) vs add(double, double) is overloading, while a Dog
redefining sound() is overriding.”
Q8: Can you override a static method in Java/C++?
Answer:
No, static methods cannot be overridden because they belong to the class, not to an instance. However, they can be
hidden if re-declared in a subclass.
Example (Java):
class Parent {
static void display() { System.out.println("Parent"); }
class Child extends Parent {
static void display() { System.out.println("Child"); } // method hiding
Here, Child.display() hides Parent.display() but does not override it.
Confident phrasing:
“Static methods cannot be overridden in Java or C++ since they belong to the class, not the object. If a subclass
defines a static method with the same signature, it’s method hiding, not overriding.”
Q9: What is dynamic vs static polymorphism?
Answer:
Static polymorphism (Compile-time): Method to call is determined at compile-time. Achieved using method
overloading or operator overloading.
Dynamic polymorphism (Runtime): Method to call is determined at runtime. Achieved using method
overriding and virtual functions.
Example (C++):
// Static polymorphism - overloading
class Math {
public:
int add(int a, int b) { return a+b; }
double add(double a, double b) { return a+b; }
};
// Dynamic polymorphism - overriding
class Animal {
public: virtual void sound() { cout << "Animal sound"; }
};
class Dog: public Animal {
public: void sound() override { cout << "Bark"; }
};
Confident phrasing:
“Static polymorphism is resolved at compile-time using method or operator overloading, while dynamic
polymorphism is resolved at runtime using overriding and virtual methods.”
Q10: How does the ‘this’ keyword work in OOP languages?
Answer:
The this keyword is a reference to the current object whose method or constructor is being invoked. It helps to:
Differentiate between instance variables and parameters.
Pass the current object as a parameter.
Call other constructors in the same class.
Example (Java):
class Student {
String name;
Student(String name) {
this.name = name; // 'this' refers to the current object
Confident phrasing:
“The this keyword refers to the current object. It’s mainly used to differentiate instance variables from parameters or
to pass the current object in methods. For example, in a Student constructor, this.name = name; clearly assigns the
parameter to the object’s variable.”
Q11: What is the difference between a class and an object?
Answer:
Class: A blueprint or template that defines attributes (data) and behaviors (methods).
Object: An instance of a class created at runtime that actually occupies memory.
Example (Python):
class Car: # Class
def __init__(self, model):
self.model = model
c1 = Car("Tesla") # Object
Confident phrasing:
“A class is a blueprint, while an object is a real instance of that blueprint. For example, Car is a class, and Tesla is an
object created from it.”
Q12: What are constructors? Can constructors be inherited?
Answer:
Constructor: A special method that initializes an object when it is created.
Inheritance: In Java and C++, constructors are not inherited. However, the child class can call the parent
constructor using super() (Java) or initializer list (C++).
Example (Java):
class Parent {
Parent() { System.out.println("Parent constructor"); }
class Child extends Parent {
Child() { super(); System.out.println("Child constructor"); }
Confident phrasing:
“Constructors are special methods used to initialize objects. They are not inherited, but a subclass can explicitly call
the parent’s constructor using super.”
Q13: What is a copy constructor?
Answer:
A copy constructor creates a new object as a copy of an existing object. It ensures that object properties are
duplicated properly.
Example (C++):
class Student {
int age;
public:
Student(int a) { age = a; }
Student(const Student &s) { age = s.age; } // copy constructor
};
Confident phrasing:
“A copy constructor creates a new object from an existing one. For example, in C++, Student s2 = s1; uses the copy
constructor to copy s1 into s2.”
Q14: What is object slicing?(only in cpp)
Answer:
Object slicing happens in C++ when a derived class object is assigned to a base class object, and the extra properties
of the derived class are sliced off.
Example (C++):
class Base { int x; };
class Derived : public Base { int y; };
Derived d;
Base b = d; // Object slicing: 'y' part of Derived is lost
Confident phrasing:
“Object slicing occurs when a derived object is assigned to a base object, and the derived class’s extra data gets
discarded. Essentially, the ‘derived part’ is sliced off.”
Q15: What is the difference between shallow copy and deep copy?
Answer:
Shallow Copy: Copies only references, not the actual objects. Changes in one object affect the other.
Deep Copy: Creates a completely new copy of the object and its data. Both objects are independent.
Example (Python):
import copy
list1 = [[1,2],[3,4]]
shallow = copy.copy(list1) # Shallow copy
deep = copy.deepcopy(list1) # Deep copy
list1[0][0] = 99
print(shallow) # [[99,2],[3,4]] affected
print(deep) # [[1,2],[3,4]] not affected
Confident phrasing:
“A shallow copy copies only references, so changes affect both objects. A deep copy duplicates everything, making
them independent. For example, in Python, copy.copy() does shallow copy, while copy.deepcopy() creates a true
independent copy.”
Q16: What are different types of inheritance (single, multiple, multilevel)?
Answer:
Single inheritance: One child class inherits from one parent.
Multiple inheritance: A child class inherits from more than one parent.
Multilevel inheritance: A child class inherits from a parent, and another child inherits from it (grandchild).
Example (C++):
// Single
class A {};
class B : public A {};
// Multiple
class A {}; class B {};
class C : public A, public B {};
// Multilevel
class A {};
class B : public A {};
class C : public B {};
Confident phrasing:
“The main types are single, multiple, and multilevel inheritance. For example, in C++, a Car class may inherit from
Vehicle (single), a FlyingCar can inherit from both Car and Airplane (multiple), and a SportsCar can extend Car which
extends Vehicle (multilevel).”
Q17: How is multiple inheritance handled in languages like C++ and Java?
Answer:
C++: Supports multiple inheritance directly, but it can lead to conflicts like the diamond problem. Virtual
inheritance is used to resolve it.
Java: Does not allow multiple inheritance with classes. Instead, it allows multiple inheritance through
interfaces.
Confident phrasing:
“In C++, multiple inheritance is supported but requires careful handling of conflicts using virtual inheritance. In Java,
multiple inheritance is avoided at the class level and is instead achieved through interfaces.”
Q18: What is the diamond problem in multiple inheritance? How is it solved?
Answer:
Problem: When a class inherits from two classes that both inherit from the same base class, the compiler
gets confused about which path to use for the base class.
Solution in C++: Use virtual inheritance to ensure only one copy of the base class is inherited.
Java: Avoids the problem completely by not allowing multiple class inheritance.
Example (C++):
class A { public: int x; };
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {}; // Only one 'A' copy exists
Confident phrasing:
“The diamond problem happens when a class inherits from two classes that share a common base, leading to
ambiguity. In C++, it’s solved using virtual inheritance, while Java avoids it by disallowing multiple inheritance with
classes.”
Q19: Can a class implement multiple interfaces?
Answer:
Yes. In Java, a class can implement multiple interfaces, which allows achieving multiple inheritance of type without
the problems of multiple inheritance of implementation.
Example (Java):
interface Flyable { void fly(); }
interface Drivable { void drive(); }
class FlyingCar implements Flyable, Drivable {
public void fly() { System.out.println("Flying"); }
public void drive() { System.out.println("Driving"); }
Confident phrasing:
“Yes, a class can implement multiple interfaces. For example, a FlyingCar can implement both Flyable and Drivable
interfaces, achieving multiple inheritance in Java safely.”
Q20: Why is interface preferred over multiple inheritance?
Answer:
Interfaces avoid the diamond problem since they only specify method signatures, not implementation.
They provide loose coupling and promote clean design.
A class can implement multiple interfaces without conflict.
Example:
Instead of a class inheriting both Car and Airplane, we can have FlyingCar implement both Drivable and Flyable
interfaces.
Confident phrasing:
“Interfaces are preferred over multiple inheritance because they avoid ambiguity, prevent the diamond problem, and
promote clean, loosely coupled design. They let classes combine multiple behaviors without inheriting conflicting
implementations.”
Q21: What is SOLID in OOP? Explain each principle.
Answer:
SOLID is a set of five design principles that make OOP code more maintainable, scalable, and flexible.
S – Single Responsibility Principle: A class should have only one reason to change. (e.g., InvoicePrinter only
prints invoices, not calculate totals).
O – Open/Closed Principle: Classes should be open for extension but closed for modification. (e.g., new
discount types can be added without changing existing billing logic).
L – Liskov Substitution Principle: Subclasses should be replaceable for their parent without breaking
functionality.
I – Interface Segregation Principle: No class should be forced to implement unused methods. Better to have
smaller, specific interfaces.
D – Dependency Inversion Principle: Depend on abstractions, not concrete classes.
Confident phrasing:
“SOLID stands for five design principles—Single Responsibility, Open/Closed, Liskov Substitution, Interface
Segregation, and Dependency Inversion. Together, they ensure my OOP code is clean, extensible, and maintainable.”
Q22: What is the difference between an abstract class and an interface?
Answer:
Abstract Class: Can have both abstract (unimplemented) and concrete (implemented) methods, along with
variables.
Interface: Only defines method signatures (in Java before Java 8), cannot have instance variables.
Example (Java):
abstract class Animal {
abstract void sound(); // abstract
void eat() { System.out.println("Eating"); } // concrete
}
interface Flyable {
void fly();
Confident phrasing:
“An abstract class can provide partial implementation, but an interface only defines contracts. A class can extend one
abstract class, but it can implement multiple interfaces.”
Q23: When would you use an abstract class vs an interface?
Answer:
Use abstract class when classes share common state or behavior.
Use interface when you only need to define capabilities or multiple types of behavior across unrelated
classes.
Example:
Abstract class: Vehicle with fuelCapacity and start().
Interface: Flyable, Drivable that different classes can implement.
Confident phrasing:
“I use abstract classes when I want to share partial implementation across related classes, and interfaces when I need
to enforce a contract that multiple unrelated classes can implement.”
Q24: What is dependency injection? How is it related to OOP?
Answer:
Dependency Injection (DI) is a design pattern where an object’s dependencies are provided from the outside rather
than the object creating them itself. It supports loose coupling and makes code easier to test and maintain.
Example (Java):
class Engine {}
class Car {
private Engine engine;
Car(Engine engine) { // dependency injected
this.engine = engine;
Confident phrasing:
“Dependency injection means supplying dependencies from outside rather than creating them inside a class. It aligns
with OOP principles like loose coupling and improves testability.”
Q25: What are access modifiers? How do they affect encapsulation?
Answer:
Access modifiers define the visibility of classes, methods, and variables.
Public: Accessible everywhere.
Protected: Accessible within the package and by subclasses.
Default (package-private): Accessible only within the same package.
Private: Accessible only within the class.
They support encapsulation by controlling which parts of a class are exposed and which are hidden.
Example (Java):
class BankAccount {
private double balance; // hidden
public void deposit(double amount) { balance += amount; }
Confident phrasing:
“Access modifiers control visibility. They’re key to encapsulation, because they let me hide sensitive data and expose
only the methods necessary to interact with the class.”