Polymorphism is a fundamental concept in object-oriented programming that allows objects of different types to be treated as instances of a common superclass or interface. It enables the use of a single interface to represent multiple related classes, providing flexibility and extensibility in the code.
There are two types of polymorphism: compile-time polymorphism (also known as static polymorphism) and runtime polymorphism (also known as dynamic polymorphism).
1. Compile-time Polymorphism: Compile-time polymorphism is achieved through method overloading and operator overloading. It allows multiple methods or operators with the same name but different parameters or behaviors to coexist in a class.
Method Overloading: Method overloading enables the definition of multiple methods with the same name but different parameter lists. The compiler determines which method to invoke based on the arguments provided during the method call. Method overloading is resolved at compile-time.
anand
For example, consider a class named Calculator with two overloaded methods named add():
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
In this example, the add() method is overloaded to accept both integers and doubles as arguments. The appropriate add() method is selected based on the argument types provided during the method call.
Operator Overloading: Operator overloading allows operators such as +, -, *, /, etc., to be overloaded and customized for objects of user-defined classes. It involves defining the behavior of an operator when applied to objects of a specific class. Operator overloading is also resolved at compile-time.
For example, consider a class named Complex representing complex numbers. We can overload the + operator to add two Complex objects:
class Complex {
private double real;
private double imaginary;
Complex(double real, double imaginary) {
this.real = real;
this.imaginary = imaginary;
}
Complex operator +(Complex other) {
return new Complex(this.real + other.real, this.imaginary + other.imaginary);
}
}
In this example, the + operator is overloaded to add two Complex objects by combining their real and imaginary parts.
2. Runtime Polymorphism: Runtime polymorphism is achieved through method overriding. It allows a subclass to provide its own implementation of a method that is already defined in its superclass. The appropriate method to execute is determined dynamically at runtime based on the actual type of the object.
Method Overriding: Method overriding allows a subclass to provide a different implementation of a method inherited from its superclass. The method in the subclass must have the same name, return type, and parameter list as the method in the superclass. Method overriding is resolved at runtime.
For example, consider a class hierarchy with a superclass named Shape and two subclasses named Circle and Rectangle. The Shape class has a method named area() that calculates the area of a shape. Each subclass overrides the area() method to provide its own implementation:
class Shape {
double area() {
return 0;
}
}
class Circle extends Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
double area() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
private double length;
private double width;
Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
double area() {
return length * width;
}
}
In this example, the area() method is overridden in the Circle and Rectangle subclasses to provide their specific implementations of calculating the area.
To summarize the differences between operator overriding and operator overloading:
Operator Overloading:
- Operator overloading allows operators such as +, -, *, /, etc., to be overloaded and customized for objects of user-defined classes.
- It involves defining the behavior of an operator when applied to objects of a specific class.
- Operator overloading is resolved at compile-time.
- It provides the ability to use familiar operators with user-defined types, making the code more expressive and intuitive.
Operator Overriding:
- Operator overriding is specific to method overriding and applies to predefined operators that can be used with objects, such as ==, !=, <, >, etc.
- It allows a subclass to provide its own implementation of an operator inherited from its superclass.
- The operator to be executed is determined dynamically at runtime based on the actual type of the object.
- Operator overriding is resolved at runtime.
- It provides the ability to customize the behavior of predefined operators for specific classes, allowing objects to be compared or operated upon in a meaningful way.
In summary, operator overloading enables customization of operators for user-defined classes, while operator overriding allows customization of predefined operators inherited from superclasses. Operator overloading is resolved at compile-time, whereas operator overriding is resolved at runtime based on the actual type of the object. Both forms of polymorphism, compile-time and runtime polymorphism, contribute to the flexibility and versatility of object-oriented programming languages.
Subscribe on YouTube - NotesWorld
For PDF copy of Solved Assignment
Any University Assignment Solution