Overview
Polymorphism is a core concept in object-oriented programming (OOP) that allows objects of different classes to be treated as objects of a common super class. It is a principle that facilitates flexibility and innovation in software design, enabling a single interface to represent different underlying forms (data types). Polymorphism plays a crucial role in allowing the same function or method to operate in many different ways, depending on the context or the objects it is applied to. This concept is particularly important in the creation of flexible and scalable software systems.
Key Concepts
- Static (Compile-time) Polymorphism: Achieved through method overloading or operator overloading.
- Dynamic (Run-time) Polymorphism: Achieved through method overriding using inheritance and interfaces.
- Polymorphic Behavior: The ability of different classes to respond to the same message (method call) in different ways.
Common Interview Questions
Basic Level
- What is polymorphism and why is it important in OOP?
- Can you explain the difference between static and dynamic polymorphism?
Intermediate Level
- How does method overriding work in C# to achieve polymorphism?
Advanced Level
- Can you design a polymorphic system using interfaces in C# that illustrates the Open/Closed Principle?
Detailed Answers
1. What is polymorphism and why is it important in OOP?
Answer: Polymorphism, derived from Greek words meaning "many shapes," is a fundamental concept in OOP that allows objects to be treated as instances of their parent class rather than their actual class. The importance of polymorphism lies in its ability to simplify programming by allowing the same interface to be used for different underlying data types. This enhances code readability, reusability, and maintainability.
Key Points:
- Simplifies code through the use of a common interface.
- Enhances code reusability by allowing the same code to work with objects of different classes.
- Supports the implementation of clean and scalable architecture.
Example:
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Some generic sound");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Bark");
}
}
public class Cat : Animal
{
public override void Speak()
{
Console.WriteLine("Meow");
}
}
public class Program
{
static void Main(string[] args)
{
List<Animal> animals = new List<Animal> { new Dog(), new Cat() };
foreach (var animal in animals)
{
animal.Speak(); // Polymorphism in action
}
}
}
2. Can you explain the difference between static and dynamic polymorphism?
Answer: Static polymorphism, also known as compile-time polymorphism, is achieved through method overloading or operator overloading within the same class. It allows methods with the same name but different parameters to coexist, with the method call resolved at compile time. Dynamic polymorphism, or run-time polymorphism, is achieved through method overriding. This allows a subclass to provide a specific implementation of a method that is already defined in its superclass. The method call is resolved at runtime, enabling dynamic dispatch.
Key Points:
- Static polymorphism is resolved at compile time.
- Dynamic polymorphism is resolved at run time.
- Method overloading is an example of static polymorphism, while method overriding is an example of dynamic polymorphism.
Example:
// Static Polymorphism Example
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
public int Add(int a, int b, int c)
{
return a + b + c;
}
}
// Dynamic Polymorphism Example
public class BaseClass
{
public virtual void Display()
{
Console.WriteLine("Base Class Display");
}
}
public class DerivedClass : BaseClass
{
public override void Display()
{
Console.WriteLine("Derived Class Display");
}
}
public class Program
{
static void Main(string[] args)
{
BaseClass obj = new DerivedClass();
obj.Display(); // Calls Derived Class's Display method due to dynamic polymorphism
}
}
3. How does method overriding work in C# to achieve polymorphism?
Answer: Method overriding in C# is a feature that allows a subclass to provide a specific implementation of a method that is already defined in its superclass. This is a cornerstone of dynamic polymorphism. The method in the base class must be marked with the virtual
keyword, and the method in the derived class is marked with the override
keyword.
Key Points:
- Base class method must be virtual
or abstract
.
- Derived class method must use the override
keyword.
- Allows derived classes to modify or extend the behavior of base class methods.
Example:
public class Shape
{
public virtual void Draw()
{
Console.WriteLine("Drawing a shape");
}
}
public class Circle : Shape
{
public override void Draw()
{
// Custom implementation for Circle
Console.WriteLine("Drawing a circle");
}
}
public class Program
{
static void Main(string[] args)
{
Shape myShape = new Circle();
myShape.Draw(); // Outputs: Drawing a circle
}
}
4. Can you design a polymorphic system using interfaces in C# that illustrates the Open/Closed Principle?
Answer: The Open/Closed Principle states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. A polymorphic system using interfaces can perfectly illustrate this principle, as it allows new functionality to be added without modifying existing code.
Key Points:
- Interfaces define contracts without implementing behavior.
- Classes implement these interfaces, providing specific behaviors.
- New functionality can be added by creating new classes that implement these interfaces.
Example:
public interface IPrintable
{
void Print();
}
public class TextDocument : IPrintable
{
public void Print()
{
Console.WriteLine("Printing TextDocument");
}
}
public class GraphicDocument : IPrintable
{
public void Print()
{
Console.WriteLine("Printing GraphicDocument");
}
}
public class Program
{
static void Main(string[] args)
{
List<IPrintable> documents = new List<IPrintable>
{
new TextDocument(),
new GraphicDocument()
};
foreach (var doc in documents)
{
doc.Print(); // Open/Closed Principle in action
}
}
}
This system is open for extension since new document types implementing the IPrintable
interface can be added without altering the existing code structure, thus adhering to the Open/Closed Principle.