Explain polymorphism with an example.

Polymorphism: The Power of Many Forms in Programming

Polymorphism, a cornerstone of object-oriented programming (OOP), lets you treat objects of different classes in a uniform way. It's a powerful tool that boosts code flexibility, reusability, and makes maintaining your programs much easier. Essentially, it means "many forms." We'll explore its two main types: compile-time and runtime polymorphism.

Compile-Time Polymorphism (Static Polymorphism)

Compile-time polymorphism happens at the compilation stage. The compiler figures out which method to call based on the function signature (parameters). The most common example is method overloading. Let's look at a Java example:


 public class MethodOverloading {
     public int add(int a, int b) { return a + b; }
     public double add(double a, double b) { return a + b; }
     public int add(int a, int b, int c) { return a + b + c; }
 }
 

Here, we have three add methods, each taking different parameters. The compiler chooses the correct version based on the arguments you provide. The main advantage is that it's fast, but it's limited because the method's name must be the same.

Runtime Polymorphism (Dynamic Polymorphism)

Runtime polymorphism, on the other hand, happens during program execution. The actual method called depends on the object's type at runtime. The key is method overriding, where a subclass provides a specific implementation of a method already defined in its superclass.


 public class Animal {
     public void makeSound() { System.out.println("Generic animal sound"); }
 }

 public class Dog extends Animal {
     @Override
     public void makeSound() { System.out.println("Woof!"); }
 }

 public class Cat extends Animal {
     @Override
     public void makeSound() { System.out.println("Meow!"); }
 }
 

In this Java example, Dog and Cat override the makeSound method. When you call makeSound() on a Dog object, you get "Woof!", and on a Cat object, you get "Meow!". This happens dynamically; the right method is selected at runtime. Virtual functions help the program determine which method to call.

Polymorphism in Action: Real-World Examples

Imagine a graphics program drawing shapes. You could have classes for Circle, Square, and Triangle, all inheriting from a Shape class. Each shape would override a draw() method. The program could call draw() on any shape object, and the correct drawing method would execute based on the shape's type. Similarly, processing different document types (like .txt, .pdf, etc.) using a common interface would be another perfect example.

Advantages of Polymorphism

Polymorphism brings significant advantages:

  • Flexibility: Easily add new types without modifying existing code.
  • Extensibility: The system can be easily expanded.
  • Maintainability: Makes code easier to understand and maintain.
  • Reusability: Code can be reused in different contexts.

Conclusion

Polymorphism is essential for creating flexible, robust, and maintainable OOP programs. Both compile-time and runtime polymorphism play vital roles, each suited for different scenarios. Understanding polymorphism is a critical step in mastering object-oriented programming. Now, go forth and write some polymorphic code!