Polymorphism in object-oriented programming: Difference between revisions
Added Perl examples. In particular highlighting the languages ability to do method Polymorphsim |
No edit summary |
||
Line 1: | Line 1: | ||
In simple terms, polymorphism is the ability of one type, A, to appear as and be used like another type, B. In strongly typed languages, this usually means that type A somehow derives from type B, or type A implements an interface that represents type B. In non-strongly typed languages (dynamically typed languages) types are implicitly polymorphic to the extent they have similar features (fields, methods, operators). In fact, this is one of the principal benefits of dynamic typing. For example, the numerical operators +,-,/,* allow polymorphic treatment of the various numerical types Integer, UnSigned Integer, Float, Decimal, etc; each of which have different ranges, bit patterns, and representations. Another common example is the use of the "+" operator which allows similar or polymorphic treatment of numbers (addition), strings (concatination), and lists (attachment).More precisely, polymorphism ([[object-oriented programming]] theory) is the ability of [[Object (computer science)|objects]] belonging to different [[Data type|types]] to respond to [[Method (computer science)|method]] calls of the same name, each one according to an appropriate type-specific behavior. The programmer (and the program) does not have to know the exact type of the object in advance, and so the exact behavior is determined at run time (this is called ''late binding'' or ''[[dynamic binding]]'').The different objects involved only need to present a compatible [[Interface (computer science)|interface]] to the clients ([[Subroutine|the calling routines]]). That is, there must be public methods with the same name and the same [[Parameter (computer science)|parameter sets]] in all the objects. In principle, the object types may be unrelated, but since they share a common interface, they are often implemented as [[Subclass (computer science)|subclasses]] of the same [[Superclass (computer science)|parent class]]. Though it is not required, it is understood that the different methods will also produce similar results (for example, returning values of the same type).In practical terms, polymorphism means that if class B inherits from class A, it doesn’t have to inherit everything about class A; it can do some of the things that class A does differently. This means that the same “verb” can result in different actions as appropriate for a specific class, so controlling code can issue the same command to a series of objects and get appropriately different results from each one.==Overriding and Overloading ==If a Dog is commanded to speak(), this may emit a Bark. However, if a Pig is commanded to speak(), this may emit an Oink. They both inherit speak() from Animal, but their derived class methods override the methods of the parent class; this is Overriding Polymorphism. Overloading Polymorphism is the use of one method signature, or one operator such as "+", to perform several different functions depending on the implementation. The "+" operator, for example, may be used to perform integer addition, float addition, list concatenation, or string concatenation. Any two subclasses of Number, such as Integer and Double, are expected to add together properly in an OOP language. The language must therefore overload the concatenation operator, "+", to work this way. This helps improve code readability.==Advantages of polymorphism==Polymorphism allows client programs to be written based only on the [[Abstraction (computer science)|abstract]] interfaces of the objects which will be manipulated ([[interface inheritance]]). This means that future extension in the form of new types of objects is easy, if the new objects conform to the original interface. In particular, with object-oriented polymorphism, the original client program does not even need to be [[Compiler|recompiled]] (only [[Linker|relinked]]) in order to make use of new types exhibiting new (but interface-conformant) behavior. In C++, for instance, this is possible because the interface definition for a class defines a memory layout, the [[Virtual table|virtual function table]] describing where pointers to functions can be found. Future, new classes can work with old, precompiled code because the new classes must conform to the [[Abstract class#Abstract and concrete classes|abstract class]] interface, meaning that the layout of the new class's virtual function table is the same as before; the old, precompiled code can still look at the same memory offsets relative to the start of the object's memory in order to find a pointer to the new function. It is only that the new virtual function table points to a new implementation of the functions in the table, thus allowing new, interface-compliant behavior with old, precompiled code.Since program evolution very often appears in the form of adding types of objects (i.e. classes), this ability to cope with and localize change that polymorphism allows is the key new contribution of object technology to software design.==Examples=====Python===[[Python (programming language)|Python]] makes extensive use of polymorphism in its basic types. For example, strings ([[immutable]] sequences of characters) and lists (mutable sequences of elements of any type) have the same indexing interface and the same lookup interface (which call the appropriate underlying methods).<source lang=python>myString = 'Hello, world!'myList = [0, 'one', 1, 'two', 3, 'five', 8]print myString[:5] # prints Helloprint myList[:5] # prints [0, 'one', 1, 'two', 3]print 'e' in myString # prints Trueprint 5 in myList # prints False</source>However, the most common examples of polymorphism are found in custom classes. Consider the example below, where two subclasses (Cat and Dog) are derived from an Animal superclass. Two Cat objects and one Dog are instantiated and given names, and then they are gathered in a tuple (a, b, c) and their ''talk'' method is called.<source lang=python>class Animal: def __init__(self, name): # Constructor of the class self.name = nameclass Cat(Animal): def talk(self): return 'Meow!'class Dog(Animal): def talk(self): return 'Woof! Woof!'a = Cat('Missy')b = Cat('Mr. Bojangles')c = Dog('Lassie')for animal in (a, b, c): print animal.name + ': ' + animal.talk()# prints the following:## Missy: Meow!# Mr. Bojangles: Meow!# Lassie: Woof! Woof!</source>Note that Python makes polymorphism particularly easy to write, since the language is dynamically (and implicitly) typed: a name can be bound to objects of any type (or class) without having to explicitly specify the type, and a list holds mixed type (unlike a C array or a Java array, be it generic or not). Note the inevitable trade-off though: a language that generates fewer compile-time errors tends to generate more run-time errors, requiring explicit (unit) [[Unit testing|testing]].===C++===<source lang=cpp>#include <iostream>#include <string>using namespace std;class Animal{ public: Animal(const string& name) : name(name) { } virtual const string talk() = 0; const string name;};class Cat : public Animal{ public: Cat(const string& name) : Animal(name) { } virtual const string talk() { return "Meow!"; }};class Dog : public Animal{ public: Dog(const string& name) : Animal(name) { } virtual const string talk() { return "Arf! Arf"; }};// prints the following://// Missy: Meow!// Mr. Bojangles: Meow!// Lassie: Arf! Arf!//int main(){ Animal* animals[] = { new Cat("Missy"), new Cat("Mr. Bojangles"), new Dog("Lassie") }; for(int i = 0; i < 3; i++) cout << animals[i]->name << ": " << animals[i]->talk() << endl; return 0;}</source>Note that the <code>talk()</code> method is explicitly declared as <code>virtual</code>. This is because polymorphic method calls have relatively high overhead in C++ <ref>Driesen, Karel and Hölzle, Urs, [http://www.cs.ucsb.edu/~urs/oocsb/papers/oopsla96.pdf "The Direct Cost of Virtual Function Calls in C++"], OOPSLA 1996</ref>. This overhead is lessened by treating all method calls as non-polymorphic, unless explicitly marked as <code>virtual</code> by the developer.===Visual Basic .NET===One way of doing polymorphism is through the definition and implementation of a common interface. Consider the example below, where two subclasses (Cat and Dog) implement the IAnimal interface. Two Cat objects and one Dog are instantiated and given names, and then they are gathered in a list and their talk method is called.<source lang=vbnet>Namespace std Public Interface IAnimal ReadOnly Property Name() As String Function Talk() As String End Interface Public Class Cat Implements IAnimal Private mName As String Sub New(ByVal name As String) mName = name End Sub Public ReadOnly Property Name() As String Implements IAnimal.Name Get Return mName End Get End Property Public Function Talk() As String Implements IAnimal.Talk Return "Meow!" End Function End Class Public Class Dog Implements IAnimal Private mName As String Sub New(ByVal name As String) mName = name End Sub Public ReadOnly Property Name() As String Implements IAnimal.Name Get Return mName End Get End Property Public Function Talk() As String Implements IAnimal.Talk Return "Arf! Arf!" End Function End Class Public Module TestAnimals ' Prints the following: ' ' Missy: Meow! ' Mr. Bojangles: Meow! ' Lassie: Arf! Arf! Public Sub Main() Dim animals(2) As IAnimal animals(0) = New Cat("Missy") animals(1) = New Cat("Mr. Bojangles") animals(2) = New Dog("Lassie") For Each a As IAnimal In animals Console.Out.WriteLine("{0}: {1}", a.Name, a.Talk) Next a End Sub End ModuleEnd Namespace</source>===Java===Java supports interfaces like .NET does, but does not have anything similar to .NET properties. Since Java interfaces require that all variables in them be class constants, an [[abstract type|abstract class]] is used instead.<source lang=java5>abstract class Animal{ public final String name; public abstract String talk(); public Animal(String name) { this.name = name; }}class Cat extends Animal{ public Cat(String name) { super(name); } public String talk() { return "Meowww!"; }}class Dog extends Animal{ public Dog(String name) { super(name); } public String talk() { return "Arf! Arf!"; }}public class TestAnimals{ // prints the following: // // Missy: Meowww! // Mr. Bojangles: Meowww! // Lassie: Arf! Arf! // public static void main(String[] args) { Animal[] animals = { new Cat("Missy"), new Cat("Mr. Bojangles"), new Dog("Lassie") }; for (Animal a : animals) System.out.println(a.name + ": " + a.talk()); }}</source>===Xbase++===<source lang="visualfoxpro">#include "class.ch"//// This program prints://// Missy Meow!// Mr. Bojangles Meow!// Lassie Bark!// Press any key to continue.../////////////////////////////////PROCEDURE Main()/////////////////////////////// LOCAL aAnimals := Array(3) LOCAL i aAnimals[1] := Cat():New("Missy") aAnimals[2] := Cat():New("Mr. Bojangles") aAnimals[3] := Dog():New("Lassie") FOR i:=1 TO LEN(aAnimals) ? aAnimals[i]:Name + " " + aAnimals[i]:Talk() NEXT i WAITRETURN///////////////////////////////CLASS Animal/////////////////////////////// EXPORTED: VAR Name READONLY METHOD Init DEFERRED CLASS METHOD TalkENDCLASSMETHOD Animal:Init( cName ) ::Name := cNameRETURN Self///////////////////////////////CLASS Dog FROM Animal/////////////////////////////// EXPORTED: METHOD TalkENDCLASSMETHOD Dog:Talk()RETURN "Bark!"///////////////////////////////CLASS Cat FROM Animal/////////////////////////////// EXPORTED: METHOD TalkENDCLASSMETHOD Cat:Talk()RETURN "Meow!"</source>===Perl===Polymorphism in [[Perl (programming language)|Perl]] is inherently straightforward to write because of the languages use of [[Sigil_(computer_programming)|sigils]] and [[Reference_(computer_science)|references]]. This is the Animal example in standard OO Perl...<source lang=perl>{ package Animal; sub new { my ( $class, $name ) = @_; $class = ref $class if ref $class; my $self = bless { name => $name }, $class; return $self; }}{ package Cat; use base qw(Animal); sub talk { 'Meow' }}{ package Dog; use base qw(Animal); sub talk { 'Woof! Woof!' }}my $a = Cat->new('Missy');my $b = Cat->new('Mr. Bojangles');my $c = Dog->new('Lassie');for my $animal ( $a, $b, $c ) { say $animal->{name} . ': ' . $animal->talk;}# prints the following:## Missy: Meow!# Mr. Bojangles: Meow!# Lassie: Woof! Woof!</source>This means that [[Perl (programming language)|Perl]] can also apply Polymorphism to the method call. Example below is written using the Moose module to show modern OO practises in Perl (and is not needed for method Polymorphism)..... <source lang=perl>{ package Animal; use Moose; has 'name' => ( isa => 'Str', is => 'ro' );}{ package Cat; use Moose; extends 'Animal'; sub talk { 'Meow' } sub likes { 'Milk' }}{ package Dog; use Moose; extends 'Animal'; sub talk { 'Woof! Woof!' } sub likes { 'Bone' }}my $a = Cat->new( name => 'Missy' );my $b = Cat->new( name => 'Mr. Bojangles' );my $c = Dog->new( name => 'Lassie' );for my $animal ( $a, $b, $c ) { for my $trait qw/talk likes/ { say $animal->name . ': ' . $trait . ' => ' . $animal->$trait; }}# prints the following:## Missy: talk => Meow# Missy: likes => Milk# Mr. Bojangles: talk => Meow# Mr. Bojangles: likes => Milk# Lassie: talk => Woof! Woof!# Lassie: likes => Bone</source>==Other concepts==In non-object-oriented programming languages, the term [[polymorphism (computer science)|polymorphism]] has different, but related meanings; one of these, ''parametric polymorphism'', is known as [[generic programming]] in the OOP community and is supported by many languages including [[C++]], [[Eiffel (programming language)|Eiffel]], and recent versions of [[C Sharp (programming language)|C#]] and [[Java (programming language)|Java]].==See also==* [[Inheritance (computer science)]]* [[Polymorphic association]]==References==<references/>==External links== * [http://javalessons.com/cgi-bin/fun/java-tutorials-main.cgi?ses=ao789&code=ovd&sub=fun Java polymorphism interactive lesson]* [http://wiki.visual-prolog.com/index.php?title=Objects_and_Polymorphism Objects and Polymorphism (Visual Prolog)][[Category:Articles with example code]][[Category:Articles with example C++ code]][[Category:Articles with example Java code]][[Category:Articles with example Python code]][[Category:Object-oriented programming]][[es:Polimorfismo (programación orientada a objetos)]] |
|||
In simple terms, polymorphism is the ability of one type, A, to appear as and be used like another type, B. In strongly typed languages, this usually means that type A somehow derives from type B, or type A implements an interface that represents type B. |
|||
In non-strongly typed languages (dynamically typed languages) types are implicitly polymorphic to the extent they have similar features (fields, methods, operators). In fact, this is one of the principal benefits of dynamic typing. |
|||
For example, the numerical operators +,-,/,* allow polymorphic treatment of the various numerical types Integer, UnSigned Integer, Float, Decimal, etc; each of which have different ranges, bit patterns, and representations. Another common example is the use of the "+" operator which allows similar or polymorphic treatment of numbers (addition), strings (concatination), and lists (attachment). |
|||
More precisely, polymorphism ([[object-oriented programming]] theory) is the ability of [[Object (computer science)|objects]] belonging to different [[Data type|types]] to respond to [[Method (computer science)|method]] calls of the same name, each one according to an appropriate type-specific behavior. The programmer (and the program) does not have to know the exact type of the object in advance, and so the exact behavior is determined at run time (this is called ''late binding'' or ''[[dynamic binding]]''). |
|||
The different objects involved only need to present a compatible [[Interface (computer science)|interface]] to the clients ([[Subroutine|the calling routines]]). That is, there must be public methods with the same name and the same [[Parameter (computer science)|parameter sets]] in all the objects. In principle, the object types may be unrelated, but since they share a common interface, they are often implemented as [[Subclass (computer science)|subclasses]] of the same [[Superclass (computer science)|parent class]]. Though it is not required, it is understood that the different methods will also produce similar results (for example, returning values of the same type). |
|||
In practical terms, polymorphism means that if class B inherits from class A, it doesn’t have to inherit everything about class A; it can do some of the things that class A does differently. This means that the same “verb” can result in different actions as appropriate for a specific class, so controlling code can issue the same command to a series of objects and get appropriately different results from each one. |
|||
==Overriding and Overloading == |
|||
If a Dog is commanded to speak(), this may emit a Bark. However, if a Pig is commanded to speak(), this may emit an Oink. They both inherit speak() from Animal, but their derived class methods override the methods of the parent class; this is Overriding Polymorphism. |
|||
Overloading Polymorphism is the use of one method signature, or one operator such as "+", to perform several different functions depending on the implementation. The "+" operator, for example, may be used to perform integer addition, float addition, list concatenation, or string concatenation. Any two subclasses of Number, such as Integer and Double, are expected to add together properly in an OOP language. The language must therefore overload the concatenation operator, "+", to work this way. This helps improve code readability. |
|||
==Advantages of polymorphism== |
|||
Polymorphism allows client programs to be written based only on the [[Abstraction (computer science)|abstract]] interfaces of the objects which will be manipulated ([[interface inheritance]]). This means that future extension in the form of new types of objects is easy, if the new objects conform to the original interface. In particular, with object-oriented polymorphism, the original client program does not even need to be [[Compiler|recompiled]] (only [[Linker|relinked]]) in order to make use of new types exhibiting new (but interface-conformant) behavior. |
|||
In C++, for instance, this is possible because the interface definition for a class defines a memory layout, the [[Virtual table|virtual function table]] describing where pointers to functions can be found. Future, new classes can work with old, precompiled code because the new classes must conform to the [[Abstract class#Abstract and concrete classes|abstract class]] interface, meaning that the layout of the new class's virtual function table is the same as before; the old, precompiled code can still look at the same memory offsets relative to the start of the object's memory in order to find a pointer to the new function. It is only that the new virtual function table points to a new implementation of the functions in the table, thus allowing new, interface-compliant behavior with old, precompiled code. |
|||
Since program evolution very often appears in the form of adding types of objects (i.e. classes), this ability to cope with and localize change that polymorphism allows is the key new contribution of object technology to software design. |
|||
==Examples== |
|||
===Python=== |
|||
[[Python (programming language)|Python]] makes extensive use of polymorphism in its basic types. For example, strings ([[immutable]] sequences of characters) and lists (mutable sequences of elements of any type) have the same indexing interface and the same lookup interface (which call the appropriate underlying methods). |
|||
<source lang=python> |
|||
myString = 'Hello, world!' |
|||
myList = [0, 'one', 1, 'two', 3, 'five', 8] |
|||
print myString[:5] # prints Hello |
|||
print myList[:5] # prints [0, 'one', 1, 'two', 3] |
|||
print 'e' in myString # prints True |
|||
print 5 in myList # prints False |
|||
</source> |
|||
However, the most common examples of polymorphism are found in custom classes. Consider the example below, where two subclasses (Cat and Dog) are derived from an Animal superclass. Two Cat objects and one Dog are instantiated and given names, and then they are gathered in a tuple (a, b, c) and their ''talk'' method is called. |
|||
<source lang=python> |
|||
class Animal: |
|||
def __init__(self, name): # Constructor of the class |
|||
self.name = name |
|||
class Cat(Animal): |
|||
def talk(self): |
|||
return 'Meow!' |
|||
class Dog(Animal): |
|||
def talk(self): |
|||
return 'Woof! Woof!' |
|||
a = Cat('Missy') |
|||
b = Cat('Mr. Bojangles') |
|||
c = Dog('Lassie') |
|||
for animal in (a, b, c): |
|||
print animal.name + ': ' + animal.talk() |
|||
# prints the following: |
|||
# |
|||
# Missy: Meow! |
|||
# Mr. Bojangles: Meow! |
|||
# Lassie: Woof! Woof! |
|||
</source> |
|||
Note that Python makes polymorphism particularly easy to write, since the language is dynamically (and implicitly) typed: a name can be bound to objects of any type (or class) without having to explicitly specify the type, and a list holds mixed type (unlike a C array or a Java array, be it generic or not). Note the inevitable trade-off though: a language that generates fewer compile-time errors tends to generate more run-time errors, requiring explicit (unit) [[Unit testing|testing]]. |
|||
===C++=== |
|||
<source lang=cpp> |
|||
#include <iostream> |
|||
#include <string> |
|||
using namespace std; |
|||
class Animal |
|||
{ |
|||
public: |
|||
Animal(const string& name) : name(name) { } |
|||
virtual const string talk() = 0; |
|||
const string name; |
|||
}; |
|||
class Cat : public Animal |
|||
{ |
|||
public: |
|||
Cat(const string& name) : Animal(name) { } |
|||
virtual const string talk() { return "Meow!"; } |
|||
}; |
|||
class Dog : public Animal |
|||
{ |
|||
public: |
|||
Dog(const string& name) : Animal(name) { } |
|||
virtual const string talk() { return "Arf! Arf"; } |
|||
}; |
|||
// prints the following: |
|||
// |
|||
// Missy: Meow! |
|||
// Mr. Bojangles: Meow! |
|||
// Lassie: Arf! Arf! |
|||
// |
|||
int main() |
|||
{ |
|||
Animal* animals[] = |
|||
{ |
|||
new Cat("Missy"), |
|||
new Cat("Mr. Bojangles"), |
|||
new Dog("Lassie") |
|||
}; |
|||
for(int i = 0; i < 3; i++) |
|||
cout << animals[i]->name << ": " << animals[i]->talk() << endl; |
|||
return 0; |
|||
} |
|||
</source> |
|||
Note that the <code>talk()</code> method is explicitly declared as <code>virtual</code>. This is because polymorphic method calls have relatively high overhead in C++ <ref>Driesen, Karel and Hölzle, Urs, [http://www.cs.ucsb.edu/~urs/oocsb/papers/oopsla96.pdf "The Direct Cost of Virtual Function Calls in C++"], OOPSLA 1996</ref>. This overhead is lessened by treating all method calls as non-polymorphic, unless explicitly marked as <code>virtual</code> by the developer. |
|||
===Visual Basic .NET=== |
|||
One way of doing polymorphism is through the definition and implementation of a common interface. Consider the example below, where two subclasses (Cat and Dog) implement the IAnimal interface. Two Cat objects and one Dog are instantiated and given names, and then they are gathered in a list and their talk method is called. |
|||
<source lang=vbnet> |
|||
Namespace std |
|||
Public Interface IAnimal |
|||
ReadOnly Property Name() As String |
|||
Function Talk() As String |
|||
End Interface |
|||
Public Class Cat |
|||
Implements IAnimal |
|||
Private mName As String |
|||
Sub New(ByVal name As String) |
|||
mName = name |
|||
End Sub |
|||
Public ReadOnly Property Name() As String Implements IAnimal.Name |
|||
Get |
|||
Return mName |
|||
End Get |
|||
End Property |
|||
Public Function Talk() As String Implements IAnimal.Talk |
|||
Return "Meow!" |
|||
End Function |
|||
End Class |
|||
Public Class Dog |
|||
Implements IAnimal |
|||
Private mName As String |
|||
Sub New(ByVal name As String) |
|||
mName = name |
|||
End Sub |
|||
Public ReadOnly Property Name() As String Implements IAnimal.Name |
|||
Get |
|||
Return mName |
|||
End Get |
|||
End Property |
|||
Public Function Talk() As String Implements IAnimal.Talk |
|||
Return "Arf! Arf!" |
|||
End Function |
|||
End Class |
|||
Public Module TestAnimals |
|||
' Prints the following: |
|||
' |
|||
' Missy: Meow! |
|||
' Mr. Bojangles: Meow! |
|||
' Lassie: Arf! Arf! |
|||
Public Sub Main() |
|||
Dim animals(2) As IAnimal |
|||
animals(0) = New Cat("Missy") |
|||
animals(1) = New Cat("Mr. Bojangles") |
|||
animals(2) = New Dog("Lassie") |
|||
For Each a As IAnimal In animals |
|||
Console.Out.WriteLine("{0}: {1}", a.Name, a.Talk) |
|||
Next a |
|||
End Sub |
|||
End Module |
|||
End Namespace |
|||
</source> |
|||
===Java=== |
|||
Java supports interfaces like .NET does, but does not have anything similar to .NET properties. Since Java interfaces require that all variables in them be class constants, an [[abstract type|abstract class]] is used instead. |
|||
<source lang=java5> |
|||
abstract class Animal |
|||
{ |
|||
public final String name; |
|||
public abstract String talk(); |
|||
public Animal(String name) { |
|||
this.name = name; |
|||
} |
|||
} |
|||
class Cat extends Animal |
|||
{ |
|||
public Cat(String name) |
|||
{ |
|||
super(name); |
|||
} |
|||
public String talk() |
|||
{ |
|||
return "Meowww!"; |
|||
} |
|||
} |
|||
class Dog extends Animal |
|||
{ |
|||
public Dog(String name) |
|||
{ |
|||
super(name); |
|||
} |
|||
public String talk() |
|||
{ |
|||
return "Arf! Arf!"; |
|||
} |
|||
} |
|||
public class TestAnimals |
|||
{ |
|||
// prints the following: |
|||
// |
|||
// Missy: Meowww! |
|||
// Mr. Bojangles: Meowww! |
|||
// Lassie: Arf! Arf! |
|||
// |
|||
public static void main(String[] args) |
|||
{ |
|||
Animal[] animals = { |
|||
new Cat("Missy"), |
|||
new Cat("Mr. Bojangles"), |
|||
new Dog("Lassie") |
|||
}; |
|||
for (Animal a : animals) |
|||
System.out.println(a.name + ": " + a.talk()); |
|||
} |
|||
} |
|||
</source> |
|||
===Xbase++=== |
|||
<source lang="visualfoxpro"> |
|||
#include "class.ch" |
|||
// |
|||
// This program prints: |
|||
// |
|||
// Missy Meow! |
|||
// Mr. Bojangles Meow! |
|||
// Lassie Bark! |
|||
// Press any key to continue... |
|||
// |
|||
///////////////////////////// |
|||
// |
|||
PROCEDURE Main() |
|||
// |
|||
///////////////////////////// |
|||
LOCAL aAnimals := Array(3) |
|||
LOCAL i |
|||
aAnimals[1] := Cat():New("Missy") |
|||
aAnimals[2] := Cat():New("Mr. Bojangles") |
|||
aAnimals[3] := Dog():New("Lassie") |
|||
FOR i:=1 TO LEN(aAnimals) |
|||
? aAnimals[i]:Name + " " + aAnimals[i]:Talk() |
|||
NEXT i |
|||
WAIT |
|||
RETURN |
|||
///////////////////////////// |
|||
// |
|||
CLASS Animal |
|||
// |
|||
///////////////////////////// |
|||
EXPORTED: |
|||
VAR Name READONLY |
|||
METHOD Init |
|||
DEFERRED CLASS METHOD Talk |
|||
ENDCLASS |
|||
METHOD Animal:Init( cName ) |
|||
::Name := cName |
|||
RETURN Self |
|||
///////////////////////////// |
|||
// |
|||
CLASS Dog FROM Animal |
|||
// |
|||
///////////////////////////// |
|||
EXPORTED: |
|||
METHOD Talk |
|||
ENDCLASS |
|||
METHOD Dog:Talk() |
|||
RETURN "Bark!" |
|||
///////////////////////////// |
|||
// |
|||
CLASS Cat FROM Animal |
|||
// |
|||
///////////////////////////// |
|||
EXPORTED: |
|||
METHOD Talk |
|||
ENDCLASS |
|||
METHOD Cat:Talk() |
|||
RETURN "Meow!" |
|||
</source> |
|||
===Perl=== |
|||
Polymorphism in [[Perl (programming language)|Perl]] is inherently straightforward to write because of the languages use of [[Sigil_(computer_programming)|sigils]] and [[Reference_(computer_science)|references]]. This is the Animal example in standard OO Perl... |
|||
<source lang=perl> |
|||
{ |
|||
package Animal; |
|||
sub new { |
|||
my ( $class, $name ) = @_; |
|||
$class = ref $class if ref $class; |
|||
my $self = bless { name => $name }, $class; |
|||
return $self; |
|||
} |
|||
} |
|||
{ |
|||
package Cat; |
|||
use base qw(Animal); |
|||
sub talk { 'Meow' } |
|||
} |
|||
{ |
|||
package Dog; |
|||
use base qw(Animal); |
|||
sub talk { 'Woof! Woof!' } |
|||
} |
|||
my $a = Cat->new('Missy'); |
|||
my $b = Cat->new('Mr. Bojangles'); |
|||
my $c = Dog->new('Lassie'); |
|||
for my $animal ( $a, $b, $c ) { |
|||
say $animal->{name} . ': ' . $animal->talk; |
|||
} |
|||
# prints the following: |
|||
# |
|||
# Missy: Meow! |
|||
# Mr. Bojangles: Meow! |
|||
# Lassie: Woof! Woof! |
|||
</source> |
|||
This means that [[Perl (programming language)|Perl]] can also apply Polymorphism to the method call. Example below is written using the Moose module to show modern OO practises in Perl (and is not needed for method Polymorphism)..... |
|||
<source lang=perl> |
|||
{ |
|||
package Animal; |
|||
use Moose; |
|||
has 'name' => ( isa => 'Str', is => 'ro' ); |
|||
} |
|||
{ |
|||
package Cat; |
|||
use Moose; |
|||
extends 'Animal'; |
|||
sub talk { 'Meow' } |
|||
sub likes { 'Milk' } |
|||
} |
|||
{ |
|||
package Dog; |
|||
use Moose; |
|||
extends 'Animal'; |
|||
sub talk { 'Woof! Woof!' } |
|||
sub likes { 'Bone' } |
|||
} |
|||
my $a = Cat->new( name => 'Missy' ); |
|||
my $b = Cat->new( name => 'Mr. Bojangles' ); |
|||
my $c = Dog->new( name => 'Lassie' ); |
|||
for my $animal ( $a, $b, $c ) { |
|||
for my $trait qw/talk likes/ { |
|||
say $animal->name . ': ' . $trait . ' => ' . $animal->$trait; |
|||
} |
|||
} |
|||
# prints the following: |
|||
# |
|||
# Missy: talk => Meow |
|||
# Missy: likes => Milk |
|||
# Mr. Bojangles: talk => Meow |
|||
# Mr. Bojangles: likes => Milk |
|||
# Lassie: talk => Woof! Woof! |
|||
# Lassie: likes => Bone |
|||
</source> |
|||
==Other concepts== |
|||
In non-object-oriented programming languages, the term [[polymorphism (computer science)|polymorphism]] has different, but related meanings; one of these, ''parametric polymorphism'', is known as [[generic programming]] in the OOP community and is supported by many languages including [[C++]], [[Eiffel (programming language)|Eiffel]], and recent versions of [[C Sharp (programming language)|C#]] and [[Java (programming language)|Java]]. |
|||
==See also== |
|||
* [[Inheritance (computer science)]] |
|||
* [[Polymorphic association]] |
|||
==References== |
|||
<references/> |
|||
==External links== |
|||
* [http://javalessons.com/cgi-bin/fun/java-tutorials-main.cgi?ses=ao789&code=ovd&sub=fun Java polymorphism interactive lesson] |
|||
* [http://wiki.visual-prolog.com/index.php?title=Objects_and_Polymorphism Objects and Polymorphism (Visual Prolog)] |
|||
[[Category:Articles with example code]] |
|||
[[Category:Articles with example C++ code]] |
|||
[[Category:Articles with example Java code]] |
|||
[[Category:Articles with example Python code]] |
|||
[[Category:Object-oriented programming]] |
|||
[[es:Polimorfismo (programación orientada a objetos)]] |
Revision as of 10:37, 16 October 2008
In simple terms, polymorphism is the ability of one type, A, to appear as and be used like another type, B. In strongly typed languages, this usually means that type A somehow derives from type B, or type A implements an interface that represents type B. In non-strongly typed languages (dynamically typed languages) types are implicitly polymorphic to the extent they have similar features (fields, methods, operators). In fact, this is one of the principal benefits of dynamic typing. For example, the numerical operators +,-,/,* allow polymorphic treatment of the various numerical types Integer, UnSigned Integer, Float, Decimal, etc; each of which have different ranges, bit patterns, and representations. Another common example is the use of the "+" operator which allows similar or polymorphic treatment of numbers (addition), strings (concatination), and lists (attachment).More precisely, polymorphism (object-oriented programming theory) is the ability of objects belonging to different types to respond to method calls of the same name, each one according to an appropriate type-specific behavior. The programmer (and the program) does not have to know the exact type of the object in advance, and so the exact behavior is determined at run time (this is called late binding or dynamic binding).The different objects involved only need to present a compatible interface to the clients (the calling routines). That is, there must be public methods with the same name and the same parameter sets in all the objects. In principle, the object types may be unrelated, but since they share a common interface, they are often implemented as subclasses of the same parent class. Though it is not required, it is understood that the different methods will also produce similar results (for example, returning values of the same type).In practical terms, polymorphism means that if class B inherits from class A, it doesn’t have to inherit everything about class A; it can do some of the things that class A does differently. This means that the same “verb” can result in different actions as appropriate for a specific class, so controlling code can issue the same command to a series of objects and get appropriately different results from each one.==Overriding and Overloading ==If a Dog is commanded to speak(), this may emit a Bark. However, if a Pig is commanded to speak(), this may emit an Oink. They both inherit speak() from Animal, but their derived class methods override the methods of the parent class; this is Overriding Polymorphism. Overloading Polymorphism is the use of one method signature, or one operator such as "+", to perform several different functions depending on the implementation. The "+" operator, for example, may be used to perform integer addition, float addition, list concatenation, or string concatenation. Any two subclasses of Number, such as Integer and Double, are expected to add together properly in an OOP language. The language must therefore overload the concatenation operator, "+", to work this way. This helps improve code readability.==Advantages of polymorphism==Polymorphism allows client programs to be written based only on the abstract interfaces of the objects which will be manipulated (interface inheritance). This means that future extension in the form of new types of objects is easy, if the new objects conform to the original interface. In particular, with object-oriented polymorphism, the original client program does not even need to be recompiled (only relinked) in order to make use of new types exhibiting new (but interface-conformant) behavior. In C++, for instance, this is possible because the interface definition for a class defines a memory layout, the virtual function table describing where pointers to functions can be found. Future, new classes can work with old, precompiled code because the new classes must conform to the abstract class interface, meaning that the layout of the new class's virtual function table is the same as before; the old, precompiled code can still look at the same memory offsets relative to the start of the object's memory in order to find a pointer to the new function. It is only that the new virtual function table points to a new implementation of the functions in the table, thus allowing new, interface-compliant behavior with old, precompiled code.Since program evolution very often appears in the form of adding types of objects (i.e. classes), this ability to cope with and localize change that polymorphism allows is the key new contribution of object technology to software design.==Examples=====Python===Python makes extensive use of polymorphism in its basic types. For example, strings (immutable sequences of characters) and lists (mutable sequences of elements of any type) have the same indexing interface and the same lookup interface (which call the appropriate underlying methods).
myString = 'Hello, world!'myList = [0, 'one', 1, 'two', 3, 'five', 8]print myString[:5] # prints Helloprint myList[:5] # prints [0, 'one', 1, 'two', 3]print 'e' in myString # prints Trueprint 5 in myList # prints False
However, the most common examples of polymorphism are found in custom classes. Consider the example below, where two subclasses (Cat and Dog) are derived from an Animal superclass. Two Cat objects and one Dog are instantiated and given names, and then they are gathered in a tuple (a, b, c) and their talk method is called.
class Animal: def __init__(self, name): # Constructor of the class self.name = nameclass Cat(Animal): def talk(self): return 'Meow!'class Dog(Animal): def talk(self): return 'Woof! Woof!'a = Cat('Missy')b = Cat('Mr. Bojangles')c = Dog('Lassie')for animal in (a, b, c): print animal.name + ': ' + animal.talk()# prints the following:## Missy: Meow!# Mr. Bojangles: Meow!# Lassie: Woof! Woof!
Note that Python makes polymorphism particularly easy to write, since the language is dynamically (and implicitly) typed: a name can be bound to objects of any type (or class) without having to explicitly specify the type, and a list holds mixed type (unlike a C array or a Java array, be it generic or not). Note the inevitable trade-off though: a language that generates fewer compile-time errors tends to generate more run-time errors, requiring explicit (unit) testing.===C++===
#include <iostream>#include <string>using namespace std;class Animal{ public: Animal(const string& name) : name(name) { } virtual const string talk() = 0; const string name;};class Cat : public Animal{ public: Cat(const string& name) : Animal(name) { } virtual const string talk() { return "Meow!"; }};class Dog : public Animal{ public: Dog(const string& name) : Animal(name) { } virtual const string talk() { return "Arf! Arf"; }};// prints the following://// Missy: Meow!// Mr. Bojangles: Meow!// Lassie: Arf! Arf!//int main(){ Animal* animals[] = { new Cat("Missy"), new Cat("Mr. Bojangles"), new Dog("Lassie") }; for(int i = 0; i < 3; i++) cout << animals[i]->name << ": " << animals[i]->talk() << endl; return 0;}
Note that the talk()
method is explicitly declared as virtual
. This is because polymorphic method calls have relatively high overhead in C++ [1]. This overhead is lessened by treating all method calls as non-polymorphic, unless explicitly marked as virtual
by the developer.===Visual Basic .NET===One way of doing polymorphism is through the definition and implementation of a common interface. Consider the example below, where two subclasses (Cat and Dog) implement the IAnimal interface. Two Cat objects and one Dog are instantiated and given names, and then they are gathered in a list and their talk method is called.
Namespace std Public Interface IAnimal ReadOnly Property Name() As String Function Talk() As String End Interface Public Class Cat Implements IAnimal Private mName As String Sub New(ByVal name As String) mName = name End Sub Public ReadOnly Property Name() As String Implements IAnimal.Name Get Return mName End Get End Property Public Function Talk() As String Implements IAnimal.Talk Return "Meow!" End Function End Class Public Class Dog Implements IAnimal Private mName As String Sub New(ByVal name As String) mName = name End Sub Public ReadOnly Property Name() As String Implements IAnimal.Name Get Return mName End Get End Property Public Function Talk() As String Implements IAnimal.Talk Return "Arf! Arf!" End Function End Class Public Module TestAnimals ' Prints the following: ' ' Missy: Meow! ' Mr. Bojangles: Meow! ' Lassie: Arf! Arf! Public Sub Main() Dim animals(2) As IAnimal animals(0) = New Cat("Missy") animals(1) = New Cat("Mr. Bojangles") animals(2) = New Dog("Lassie") For Each a As IAnimal In animals Console.Out.WriteLine("{0}: {1}", a.Name, a.Talk) Next a End Sub End ModuleEnd Namespace
===Java===Java supports interfaces like .NET does, but does not have anything similar to .NET properties. Since Java interfaces require that all variables in them be class constants, an abstract class is used instead.
abstract class Animal{ public final String name; public abstract String talk(); public Animal(String name) { this.name = name; }}class Cat extends Animal{ public Cat(String name) { super(name); } public String talk() { return "Meowww!"; }}class Dog extends Animal{ public Dog(String name) { super(name); } public String talk() { return "Arf! Arf!"; }}public class TestAnimals{ // prints the following: // // Missy: Meowww! // Mr. Bojangles: Meowww! // Lassie: Arf! Arf! // public static void main(String[] args) { Animal[] animals = { new Cat("Missy"), new Cat("Mr. Bojangles"), new Dog("Lassie") }; for (Animal a : animals) System.out.println(a.name + ": " + a.talk()); }}
===Xbase++===
#include "class.ch"//// This program prints://// Missy Meow!// Mr. Bojangles Meow!// Lassie Bark!// Press any key to continue.../////////////////////////////////PROCEDURE Main()/////////////////////////////// LOCAL aAnimals := Array(3) LOCAL i aAnimals[1] := Cat():New("Missy") aAnimals[2] := Cat():New("Mr. Bojangles") aAnimals[3] := Dog():New("Lassie") FOR i:=1 TO LEN(aAnimals) ? aAnimals[i]:Name + " " + aAnimals[i]:Talk() NEXT i WAITRETURN///////////////////////////////CLASS Animal/////////////////////////////// EXPORTED: VAR Name READONLY METHOD Init DEFERRED CLASS METHOD TalkENDCLASSMETHOD Animal:Init( cName ) ::Name := cNameRETURN Self///////////////////////////////CLASS Dog FROM Animal/////////////////////////////// EXPORTED: METHOD TalkENDCLASSMETHOD Dog:Talk()RETURN "Bark!"///////////////////////////////CLASS Cat FROM Animal/////////////////////////////// EXPORTED: METHOD TalkENDCLASSMETHOD Cat:Talk()RETURN "Meow!"
===Perl===Polymorphism in Perl is inherently straightforward to write because of the languages use of sigils and references. This is the Animal example in standard OO Perl...
{ package Animal; sub new { my ( $class, $name ) = @_; $class = ref $class if ref $class; my $self = bless { name => $name }, $class; return $self; }}{ package Cat; use base qw(Animal); sub talk { 'Meow' }}{ package Dog; use base qw(Animal); sub talk { 'Woof! Woof!' }}my $a = Cat->new('Missy');my $b = Cat->new('Mr. Bojangles');my $c = Dog->new('Lassie');for my $animal ( $a, $b, $c ) { say $animal->{name} . ': ' . $animal->talk;}# prints the following:## Missy: Meow!# Mr. Bojangles: Meow!# Lassie: Woof! Woof!
This means that Perl can also apply Polymorphism to the method call. Example below is written using the Moose module to show modern OO practises in Perl (and is not needed for method Polymorphism).....
{ package Animal; use Moose; has 'name' => ( isa => 'Str', is => 'ro' );}{ package Cat; use Moose; extends 'Animal'; sub talk { 'Meow' } sub likes { 'Milk' }}{ package Dog; use Moose; extends 'Animal'; sub talk { 'Woof! Woof!' } sub likes { 'Bone' }}my $a = Cat->new( name => 'Missy' );my $b = Cat->new( name => 'Mr. Bojangles' );my $c = Dog->new( name => 'Lassie' );for my $animal ( $a, $b, $c ) { for my $trait qw/talk likes/ { say $animal->name . ': ' . $trait . ' => ' . $animal->$trait; }}# prints the following:## Missy: talk => Meow# Missy: likes => Milk# Mr. Bojangles: talk => Meow# Mr. Bojangles: likes => Milk# Lassie: talk => Woof! Woof!# Lassie: likes => Bone
==Other concepts==In non-object-oriented programming languages, the term polymorphism has different, but related meanings; one of these, parametric polymorphism, is known as generic programming in the OOP community and is supported by many languages including C++, Eiffel, and recent versions of C# and Java.==See also==* Inheritance (computer science)* Polymorphic association==References==
- ^ Driesen, Karel and Hölzle, Urs, "The Direct Cost of Virtual Function Calls in C++", OOPSLA 1996
==External links== * Java polymorphism interactive lesson* Objects and Polymorphism (Visual Prolog)