The 4 Pillars of OOP in C# (Interview Guide)
Your Interview Guide to the Four Pillars of OOP in C#
Object-Oriented Programming (OOP) is the core paradigm of C#. An interviewer will always check your understanding of its four main pillars. Being able to define them simply and provide a code example is essential.
Here is the simple, one-sentence definition for each:
- Encapsulation: The concept of bundling data (fields) and the methods that operate on that data into a single unit (a 'class'), and hiding the internal state from the outside world.
- Abstraction: Hiding complex implementation details and exposing only the necessary features to the user (e.g., an
interfaceorabstract class). - Inheritance: The mechanism that allows a new class (a 'child' or 'derived' class) to acquire the properties and methods of an existing class (a 'parent' or 'base' class).
- Polymorphism: The ability for an object to take on many forms. In practice, it means a parent class reference can be used to refer to a child class object, allowing the child to `override` and provide its own implementation of a method.
This cluster will provide a specific, code-based interview answer for each pillar.
OOP Pillar 1: Encapsulation Explained (`public` vs. `private`)
Interview Question: 'What is Encapsulation?'
Answer: 'Encapsulation is the principle of 'data hiding'. It means bundling the data (fields) and the methods that can change that data within a class, and protecting that data from the outside world using access modifiers like private. We then expose controlled access to that data using public methods or properties (getters/setters).'
The goal is to prevent other classes from 'reaching in' and putting your object into an invalid state.
'Before': No Encapsulation (BAD 👎)
Here, the balance field is public. Any other class can change it, even to an invalid value.
public class BankAccount {
public decimal balance; // BAD! This is public.
}
public class Program {
public void Main() {
BankAccount account = new BankAccount();
account.balance = -1000.00m; // PROBLEM! The account is now in an invalid state.
}
}'After': With Encapsulation (GOOD 👍)
Here, the _balance field is private. The only way to change it is through the Deposit or Withdraw methods. This protects our business logic.
public class BankAccount {
// 1. The data is 'private' and hidden.
private decimal _balance = 0;
// 2. We expose a 'public' property for reading (a 'getter')
public decimal Balance {
get { return _balance; }
}
// 3. We expose 'public' methods to safely modify the data
public void Deposit(decimal amount) {
if (amount > 0) {
_balance += amount;
}
}
public bool Withdraw(decimal amount) {
if (amount > 0 && _balance >= amount) {
_balance -= amount;
return true; // Success
}
return false; // Failure (e.g., insufficient funds)
}
}
public class Program {
public void Main() {
BankAccount account = new BankAccount();
// account._balance = -1000.00m; // COMPILE ERROR! Cannot access private field.
// You must use the methods, which contain the safety checks.
account.Deposit(100);
account.Withdraw(50);
}
}OOP Pillar 2: Inheritance Explained (`base` and `derived`)
Interview Question: 'What is Inheritance?'
Answer: 'Inheritance is the mechanism for code reuse. It allows a new class, called the 'derived' or 'child' class, to inherit the non-private fields and methods of an existing 'base' or 'parent' class. This creates an 'is-a' relationship (e.g., a Dog 'is-a' Animal).'
Code Example: `base` and `derived` Classes
Here, we have a base class Animal that has common logic. The derived classes Dog and Cat inherit this logic so we don't have to rewrite it.
// 1. The 'base' or 'parent' class
public class Animal {
public string Name { get; set; }
public Animal(string name) {
Name = name;
Console.WriteLine("Animal constructor called.");
}
public void Eat() {
Console.WriteLine($"{Name} is eating.");
}
}
// 2. The 'derived' or 'child' class
// 'Dog' inherits from 'Animal' using the ':' syntax
public class Dog : Animal {
// 3. We must call the base constructor using 'base()'
public Dog(string name) : base(name) {
Console.WriteLine("Dog constructor called.");
}
// This is a new method only for Dog
public void Bark() {
Console.WriteLine($"{Name} says woof!");
}
}
public class Program {
public void Main() {
Dog myDog = new Dog("Fido");
// 'myDog' has access to its own methods:
myDog.Bark(); // Output: Fido says woof!
// 'myDog' also has access to its parent's methods:
myDog.Eat(); // Output: Fido is eating.
Console.WriteLine(myDog.Name); // Output: Fido
}
}
// Console output from 'new Dog("Fido")':
// Animal constructor called.
// Dog constructor called.OOP Pillar 3: Polymorphism Explained (`virtual`, `override`, `new`)
Interview Question: 'What is Polymorphism?'
Answer: 'Polymorphism means 'many forms'. It's the ability for a 'derived' (child) class to provide its own, specific implementation of a method from its 'base' (parent) class. It allows us to treat a Dog or Cat object as just an Animal, and when we call the MakeSound() method, the correct version (bark or meow) is executed at runtime.'
This is achieved in C# using the virtual and override keywords.
Code Example: virtual and override
This is the classic example of true polymorphism.
public class Animal {
// 1. Mark the base method as 'virtual'
// This means 'derived classes are allowed to override me.'
public virtual void MakeSound() {
Console.WriteLine("Animal makes a generic sound.");
}
}
public class Dog : Animal {
// 2. 'override' the base method
// This provides a new implementation.
public override void MakeSound() {
Console.WriteLine("Woof!");
}
}
public class Cat : Animal {
// 3. 'override' the base method
public override void MakeSound() {
Console.WriteLine("Meow!");
}
}
public class Program {
public void Main() {
// 4. This is Polymorphism in action!
// We create a list of 'Animal' (base type).
List animals = new List();
// 5. We can add 'Dog' and 'Cat' (derived types) to it.
animals.Add(new Animal());
animals.Add(new Dog());
animals.Add(new Cat());
foreach (Animal a in animals) {
// 6. The correct method is called at runtime,
// based on the actual object's type.
a.MakeSound();
}
}
}
// --- CONSOLE OUTPUT ---
// Animal makes a generic sound.
// Woof!
// Meow! Interview 'Gotcha': override vs. new
An interviewer might ask, 'What's the difference between override and new?'
override(Polymorphism): Replaces the base class method. As seen above, when you call it on the baseAnimalreference, theDog's new method is called.new(Method Hiding): Hides the base class method. If you call it on the baseAnimalreference, the base method is called. This is NOT polymorphism and is almost always a bug.
public class Wolf : Animal {
// 'new' hides the base method. It does not override it.
public new void MakeSound() {
Console.WriteLine("Howl!");
}
}
// In Main...
Animal myWolf = new Wolf();
myWolf.MakeSound(); // Output: 'Animal makes a generic sound.'
// The 'Howl' method is only called if you have a 'Wolf' reference:
Wolf realWolf = new Wolf();
realWolf.MakeSound(); // Output: 'Howl!'

