Overview
Polymorphism is a core concept in Object-Oriented Programming (OOP) that allows objects to be treated as instances of their parent class rather than their actual derived class. This enables a single function or method to process objects of different classes in different ways. It's crucial in enabling code to be more flexible and reusable, leading to more efficient and manageable codebases.
Key Concepts
- Static (Compile-time) Polymorphism: Achieved through method overloading and operator overloading, allowing functions or operators to operate in different ways based on the input parameters.
- Dynamic (Run-time) Polymorphism: Achieved through method overriding, allowing a method in a derived class to have a different implementation from a method in its base class, even if they share the same name.
- Interfaces and Abstract Classes: Enable polymorphism by defining contracts that derived classes must implement, allowing objects to be treated in a polymorphic way.
Common Interview Questions
Basic Level
- What is polymorphism in OOP and why is it important?
- Can you provide a simple example of method overloading in C#?
Intermediate Level
- How does polymorphism work with inheritance in C#?
Advanced Level
- Explain how you would use interfaces to implement polymorphism in a complex system.
Detailed Answers
1. What is polymorphism in OOP and why is it important?
Answer: Polymorphism allows objects of different classes to be treated as objects of a common super class. This is important because it enables methods to use objects of different classes interchangeably, making it easier to add new classes without modifying the code that uses them. It enhances code reusability and flexibility, making the software easier to extend and maintain.
Key Points:
- Enables objects to be treated based on their behavioral rather than structural differences.
- Supports the open-closed principle, allowing systems to be open for extension but closed for modification.
- Facilitates clean and maintainable code by minimizing conditional statements.
2. Can you provide a simple example of method overloading in C#?
Answer: Method overloading is a form of compile-time polymorphism where multiple methods have the same name but differ in the type or number of their parameters. It allows a class to perform a single action in different ways, depending on the arguments passed to it.
Key Points:
- Overloaded methods must differ in the number or type of parameters.
- The return type alone cannot be used to distinguish overloaded methods.
- Overloading enables clearer, more intuitive code.
Example:
public class Calculator
{
// Overload 1: Adds two integers
public int Add(int a, int b)
{
return a + b;
}
// Overload 2: Adds two double values
public double Add(double a, double b)
{
return a + b;
}
// Overload 3: Adds three integers
public int Add(int a, int b, int c)
{
return a + b + c;
}
}
class Program
{
static void Main(string[] args)
{
Calculator calc = new Calculator();
Console.WriteLine(calc.Add(1, 2)); // Calls first overload
Console.WriteLine(calc.Add(1.1, 2.2)); // Calls second overload
Console.WriteLine(calc.Add(1, 2, 3)); // Calls third overload
}
}
3. How does polymorphism work with inheritance in C#?
Answer: In C#, polymorphism is most commonly achieved through inheritance, where a base class defines a method as virtual, and derived classes override that method with new implementations. This allows an object of a derived class to be treated as an object of the base class, but when the method is invoked, the overridden version in the derived class is executed.
Key Points:
- The virtual
keyword is used in the base class to allow a method to be overridden.
- The override
keyword is used in the derived class to redefine the base class method.
- This mechanism enables dynamic polymorphism or run-time polymorphism.
Example:
public class Shape
{
public virtual void Draw()
{
Console.WriteLine("Drawing a shape.");
}
}
public class Circle : Shape
{
public override void Draw()
{
// Draw a circle.
Console.WriteLine("Drawing a circle.");
}
}
public class Square : Shape
{
public override void Draw()
{
// Draw a square.
Console.WriteLine("Drawing a square.");
}
}
class Program
{
static void Main(string[] args)
{
Shape[] shapes = new Shape[] { new Circle(), new Square() };
foreach (var shape in shapes)
{
shape.Draw(); // Calls the appropriate Draw method depending on the object's class.
}
}
}
4. Explain how you would use interfaces to implement polymorphism in a complex system.
Answer: Interfaces in C# provide a way to achieve polymorphism by specifying a set of methods that implementing classes must provide. In a complex system, interfaces can be used to define capabilities or contracts without specifying how those functionalities should be implemented, allowing different classes to implement the same interface in diverse ways while ensuring they can be used interchangeably.
Key Points:
- Interfaces specify what a class does, not how it does it.
- A class can implement multiple interfaces, enabling more flexible designs.
- Interfaces are crucial in dependency inversion and for creating loosely coupled systems.
Example:
public interface IDrawable
{
void Draw();
}
public class Circle : IDrawable
{
public void Draw()
{
Console.WriteLine("Drawing a circle.");
}
}
public class Square : IDrawable
{
public void Draw()
{
Console.WriteLine("Drawing a square.");
}
}
class Program
{
static void Main(string[] args)
{
IDrawable[] drawables = new IDrawable[] { new Circle(), new Square() };
foreach (var drawable in drawables)
{
drawable.Draw(); // Calls Draw method on each drawable object.
}
}
}
This example demonstrates how interfaces can be used to define a common contract (IDrawable
interface) that multiple classes (Circle
and Square
) implement, allowing the use of polymorphism to treat each instance uniformly while executing their specific implementations of the Draw
method.