Try OpenEdge Now
skip to main content
Object-oriented Programming
Object-oriented Programming and ABL : Overview of object-oriented programming : Polymorphism
 

Polymorphism

Polymorphism is one of the most powerful advantages of object-oriented programming, and it relies fundamentally on inheritance and overriding. When a message is sent to an object of a class, the class must have a method defined to respond to that message. In a class hierarchy, all subclasses inherit the same methods from a common super class. The same message sent to each subclass invokes the same inherited method. However, because each subclass is a separate entity, it can implement a different response to the same message by overriding the specified super class method with one that implements the unique behavior of the subclass. In other words, polymorphism allows different subclasses based on the same class hierarchy to respond to the same message in different ways.
Thus, polymorphism allows a given message sent to a super class to be dispatched to an overridden method that provides different run-time behavior depending on the particular subclass that overrides the method in the super class. Therefore, polymorphism simplifies programming, where invocation of the same method produces a different result depending on the subclass that implements the method.
The following figure shows an example of polymorphism where ClassA defines a MethodA( ) that is inherited and overridden by ClassB and ClassC in two separate class hierarchies, respectively. The pseudo-code fragment takes advantage of this polymorphism by defining a single object reference (dotted arrow) to ClassA (ObjectA) that can access both overrides of the method.
Figure 3. Example of polymorphism with method overriding
The pseudo-code can reference an instance of both ClassB and ClassC and invoke MethodA( ) as if it were an instance of ClassA. However, the implementation of MethodA( ) that it executes is the one that overrides the ClassA method in the instance actually referenced as ObjectA.
So, as the numbered arrows show:
1. The pseudo-code instantiates ClassC and sets ObjectA to reference the instance (1a). So, when the code invokes MethodA( ) on ObjectA (1b), it is ClassC’s override that executes.
2. The pseudo-code instantiates ClassB and sets ObjectA to reference the instance (2a). So, when the code invokes MethodA( ) on ObjectA (2b), it is ClassB’s override that executes.
As a practical example, you might have a system with many different shapes, where Shape is a super class. However, a circle, a square, and a star are each drawn differently. By using polymorphism, you can define a Draw( ) method in the Shape super class, then send the super class a message to invoke this Draw( ) method, and each subclass of Shape (Circle, Square, or Star) is responsible for drawing itself using its own implementation of the Draw( ) method. There is no need, when invoking the Draw( ) method, to know what subclass of Shape is responding to the message.
Another kind of polymorphism that provides features similar to method overriding relies on interfaces alone (without super classes) to specify common methods that are implemented differently by different classes. This allows a given message sent to an object referenced as an interface type to be dispatched to an implemented method that provides different run-time behavior depending on the particular class that implements the interface type.
The following figure shows an example of polymorphism where ClassB and ClassC each provide different versions of the MethodA( ) declared by an interface, InterfaceA, that they both implement. The pseudo-code fragment takes advantage of this polymorphism by defining a single object reference (dotted arrow) to InterfaceA (ObjectA) that can access both implementations of the method. Thus, this example provides exactly the same functionality using interfaces as does the overriding example.
Figure 4. Example of polymorphism with interfaces
Because both classes implement InterfaceA, when the pseudo-code references each instance of ClassB and ClassC using the ObjectA reference, it can invoke MethodA( ) in exactly the same way for the two different class instances. However, the version of MethodA( ) that executes is the one that is implemented by the class instance actually referenced as ObjectA.
So, as the numbered arrows show:
1. The pseudo-code instantiates ClassC and sets ObjectA to reference the instance (1a). So, when the code invokes MethodA( ) on ObjectA (1b), it is ClassC’s implementation that executes.
2. The pseudo-code instantiates ClassB and sets ObjectA to reference the instance (2a). So, when the code invokes MethodA( ) on ObjectA (2b), it is ClassB’s implementation that executes.
Again, as a practical example, the Draw( ) method defined by different subclasses of a Shape super class can just as well be a Draw( ) method defined by different classes that implement a Shape interface. Like method overriding, the same message invokes different behavior, but the class that implements an interface is entirely responsible for implementing that behavior, because it does not inherit any of its implementation from a super class. This kind of polymorphism, using interfaces, can also be used to implement delegation. For more information on delegation, see Delegation.
Note that method overloading also provides a less powerful mechanism, similar to (and sometimes referred to as a kind of) polymorphism. With method overloading, an object responds to different messages, each of which invokes a method of the same name, but a different signature, depending on the message. With method overloading, although you are invoking a method of the same name, the behavior depends on a different message for a given object, which you must know at compile time, to invoke the appropriate method. This contrasts with method overriding, where the behavior depends on different objects at run time that all respond to the same message, which you know at compile time, to invoke the appropriate method. For more information on method overloading, see Method overloading.