Polymorphism (OOP) (OCR A-Level Computer Science): Revision Notes
Polymorphism (OOP)
Overview
Polymorphism is a core concept in Object-Oriented Programming (OOP) that allows objects of different classes to be treated as instances of the same class, typically through a shared parent class. The term "polymorphism" means "many forms," and in programming, it enables a single function, method, or operator to work in different ways depending on the context. Polymorphism promotes flexibility, code reuse, and the ability to extend systems easily, as it allows programmers to write code that can uniformly handle different types of objects.
Types of Polymorphism
Method Overriding (Run-time Polymorphism)
- Definition: Method overriding allows a child class to provide a specific implementation of a method that is already defined in its parent class. This type of polymorphism occurs at runtime, allowing the correct version of the method to be called based on the actual object type.
- Purpose: Run-time polymorphism lets child classes customise or extend the behaviour of inherited methods, making it possible for different classes to define their own unique behaviour while sharing a common interface.
Example:
class Animal:
def make_sound(self):
return "Some generic animal sound"
class Dog(Animal):
def make_sound(self): # Overrides make_sound in Animal
return "Woof woof"
class Cat(Animal):
def make_sound(self): # Overrides make_sound in Animal
return "Meow"
# Using polymorphism
animals = [Dog(), Cat(), Animal()]
for animal in animals:
print(animal.make_sound())
Explanation: The make_sound method is overridden in both Dog and Cat, allowing each subclass to provide its own version of the method.
When the make_sound method is called on each object in the animals list, the correct method for each specific object (dog, cat, or generic animal) is executed.
Method Overloading (Compile-time Polymorphism)
- Definition: Method overloading allows a class to define multiple methods with the same name but different parameters. In languages like Python, true method overloading is not directly supported, but similar behaviour can be achieved using optional or keyword arguments.
- Purpose: Compile-time polymorphism makes methods more flexible, enabling different behaviours based on input parameters.
Example:
class Calculator:
def add(self, a, b, c=0):
return a + b + c
calc = Calculator()
print(calc.add(3, 5)) # Outputs: 8
print(calc.add(3, 5, 10)) # Outputs: 18
Explanation: The add method in Calculator can accept two or three parameters.
This enables the same method to handle different types of input, even though Python achieves this without true overloading.
Polymorphism with Interfaces
- Definition: In OOP languages that support interfaces or abstract classes (like Java), polymorphism is often achieved by defining a set of methods in an interface that multiple classes implement, each with its own specific behaviour.
- Purpose: Interfaces ensure that different classes provide the same methods, allowing polymorphic behaviour based on the interface type.
Example in Python (with an abstract base class):
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self): # Provides specific implementation
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self): # Provides specific implementation
return 3.14159 * self.radius ** 2
# Using polymorphism with an interface
shapes = [Rectangle(3, 4), Circle(5)]
for shape in shapes:
print(shape.area()) # Calls the area method for each shape
Explanation: Both Rectangle and Circle implement the area method defined by the Shape interface.
Each class provides its own version of area, which is called appropriately for each object in the shapes list.
Benefits of Polymorphism
- Flexibility: Polymorphism allows code to work with objects of different types interchangeably, making it adaptable to future changes or additions.
- Code Reusability: With polymorphism, classes can share methods, reducing redundancy and improving code reusability.
- Ease of Maintenance: Polymorphic code is more modular and less complex, which improves maintainability. Changes to shared methods can be made in a parent class without modifying subclasses.
- Extensibility: New subclasses can be added that extend or override existing methods, enabling the programme to expand easily.
Note Summary
Common Mistakes with Polymorphism
- Incorrect Method Signatures: When overriding methods, the method name and parameters must match the parent method exactly. Any variation can cause errors or unexpected behaviour.
- Misinterpreting Overloading: In languages without built-in overloading (like Python), developers may accidentally create multiple methods with the same name, which leads to overwriting rather than overloading.
- Not Using Polymorphic Methods Consistently: Failing to take advantage of polymorphism can result in duplicated code. It's best to use polymorphic methods for similar functionality across subclasses.
Key Takeaways
- Polymorphism enables methods to take on different forms based on the specific object or input type, enhancing flexibility in OOP.
- Method Overriding (runtime polymorphism) allows child classes to provide specialised behaviour for inherited methods.
- Method Overloading (compile-time polymorphism) allows methods to handle different input types or parameters, though it's limited in some languages like Python.
- Interfaces and Abstract Classes promote polymorphism by enforcing method consistency across multiple classes, allowing objects to be used interchangeably.