Polymorphie (Programmierung)

Polymorphie (Programmierung)

Polymorphie (griechisch, „Vielgestaltigkeit“) ist ein Konzept in Programmiersprachen, das die Fähigkeit eines Bezeichners beschreibt, abhängig von seiner Verwendung unterschiedliche Datentypen anzunehmen.

Das Gegenteil der Polymorphie ist die Monomorphie. Hier sind die Variable oder das Literal während der gesamten Laufzeit von genau einem Typ.

Inhaltsverzeichnis

Einleitung

Um das Konzept der Polymorphie zu verstehen, ist ein grundlegendes Verständnis von Programmierung und Datentypen notwendig. In dieser Einführung wird die Motivation dahinter verdeutlicht und die verschiedenen Arten der Polymorphie vorweggenommen. Sie werden in den entsprechenden Abschnitten genauer erklärt.

In älteren typisierten Programmiersprachen wird jedem Namen und jedem Wert im Quelltext eines Programms höchstens ein Typ zugeordnet. Die folgenden Beispiele stammen aus keiner konkreten Sprache, sind aber denkbar:

  • Einer Variablen wird bei der Deklaration der Typ "Gleitkommazahl" zugewiesen. Sie behält diesen Typ während der gesamten Laufzeit des Programms.
  • Der Wert einer Zeichenkette ist von einem Typ, der üblicherweise mit "String" bezeichnet wird.
  • Das Literal 42 (oder der Wert, den es bezeichnet) hat einen Ganzzahltyp, oft mit "Integer" oder einer Kurzform davon bezeichnet.
  • Der Operator + hat den Typ {\scriptstyle Integer \times Integer \rightarrow Integer}, akzeptiert also genau zwei Argumente vom Typ Integer und liefert genau einen Wert vom Typ Integer.
  • Die Funktion second, die zwei Strings akzeptiert und immer den zweiten zurückliefert ist vom Typ {\scriptstyle String \times String \rightarrow String}

Bei diesen Beispielen fallen ein paar interessante Dinge ins Auge. Typischerweise kann der Operator + nicht nur dazu verwendet werden, ganze Zahlen zu addieren, sondern auch reelle oder auch eine ganze Zahl mit einer reellen. In manchen Sprachen wird er auch zur Verknüpfung von Strings verwendet: Man kann den Operator + "überladen", d. h. für verschiedene Parametertypen definieren oder ganze Zahlen implizit, also versteckt in reelle umwandeln (Coercion). Der Operator + besitzt also (vielleicht implizit) verschiedene Typen. Bemerkung: der Typ eines Operators oder einer Funktion besteht aus den Typen der Parameter, deren Reihenfolge und dem Rückgabetyp.

Die Funktion second könnte auch für andere Parametertypen geschrieben werden. Es spielt keine Rolle, von welchem Typ die Parameter sind (Achtung: der Rückgabetyp muss immer genau der des zweiten Parameters sein). Dazu werden die Parametertypen variabel gelassen, genauso wie die Argumente durch die Parameter variabel gelassen werden (parametrische Polymorphie).

Viele arithmetische Operatoren sind auf Ganzzahlen, reellen oder auch komplexen Zahlen definiert. Den verschiedenen Zahlenarten ist also etwas gemeinsam, nämlich, dass man mit ihnen multiplizieren, addieren usw. kann. Einigen wohnt auch eine Ordnung inne, d. h. man kann bestimmen, welche von zwei Zahlen größer oder kleiner als die andere ist. Dabei variieren die Implementierungen der Operationen oft. Dazu führt man einen Typ mit dem Namen Number ein und sagt, dass alle Zahltypen nicht nur von ihrem speziellen Typ (z. B. Integer), sondern gleichzeitig auch vom Typ Number sein können (Inklusionspolymorphie).

Arten der Polymorphie

  1. Polymorphie überladener Operatoren
  2. Polymorphie der Objektorientierten Programmierung
  3. Polymorphie einer Funktion bzw. Prozedur
  4. Polymorphie von Datentypen oder Klassen
  5. Polymorphie bei der Softwareentwicklung

Polymorphie überladener Operatoren

Ein Bezeichner, der für einen Operator steht (bspw. „+“, „-“ oder „minus“), kann mehrmals mit anderer Bedeutung implementiert werden. Für jeden Kontext, in dem der Operator neu deklariert wurde, muss die Implementierung immer eindeutig sein.

Polymorphie der Objektorientierten Programmierung

Die Polymorphie der Objektorientierten Programmierung ist eine Eigenschaft, die immer im Zusammenhang mit Vererbung und Schnittstellen (Interfaces) auftritt. Eine Methode ist polymorph, wenn sie in verschiedenen Klassen die gleiche Signatur hat, jedoch erneut implementiert ist.

Gibt es in einem Vererbungszweig einer Klassenhierarchie mehrere Methoden auf unterschiedlicher Hierarchieebene, jedoch mit gleicher Signatur, wird erst zur Laufzeit bestimmt, welche der Methoden für ein gegebenes Objekt verwendet wird (Dynamisches Binden). Bei einer mehrstufigen Vererbung wird jene Methode verwendet, die direkt in der Objektklasse (d. h. jene Klasse, von der das Objekt ein Exemplar ist) definiert ist, oder jene, die im Vererbungszweig am weitesten "unten" liegt (d. h. die Methode, die von der Vererbung her am nächsten ist).

Moderne Konzepte kennen jedoch auch Polymorphie über Klassengrenzen hinaus. So erlaubt Objective-C die Polymorphie zwischen zwei gleichnamigen Methoden, die in verschiedenen Klassen erstmalig definiert sind.

// NSObject kennt nicht -doSomething
@interface KlasseA : NSObject {}
- (void) doSomething;
@end
 
@interface KlasseB : NSObject {}
- (void) doSomething;
@end
// irgendwo
id object =// Ein Objekt einer beliebigen Klasse
[object doSomething]; // polymorph zwischen KlasseA und KlasseB

Selbstverständlich gilt die Subklasse-vor-Basisklasse-Regel auch hier: Wenn die KlasseB zur KlasseC abgeleitet wird, würde die entsprechende Methode der KlasseC ausgeführt.

Polymorphie einer Funktion bzw. Prozedur

Ist der Rückgabewert oder ein Argument einer Funktion polymorph, heißt die Funktion polymorphe Funktion. Mit Hilfe polymorpher Funktionen kann die Generizität von Datenstrukturen auch in Algorithmen angewandt werden [1].

Polymorphie von Datentypen oder Klassen

Wird für eigene Datentypen bzw. Klassen bei der Instanzierung bzw. beim Konstruktoraufruf ein Parameter für den tatsächlich verwendeten Datentyp übergeben, spricht man von parametrischer Polymorphie, das semantisch mit Generizität übereinstimmt.

Weitere Unterteilung

Folgende weitere Unterteilung ist möglich:

  • universelle Polymorphie
    • parametrische Polymorphie
    • Inklusions-/Vererbungspolymorphie
  • Ad-hoc-Polymorphie
    • Coercion
    • Überladung

Manchmal wird Ad-hoc-Polymorphie gleichgesetzt mit Überladen. Das ist auf Christopher Strachey zurückzuführen[2], der als erster Polymorphie unterteilte und zwar in parametrische und Ad-hoc-Polymorphie. Seine formlose Beschreibung lässt vermuten, dass er bei letzterem tatsächlich nur Überladen im Sinn hatte.

Luca Cardelli und Peter Wegner erweiterten Stracheys Konzept um die Inklusionspolymorphie[3], um Subtypen und Vererbung zu modellieren. Die obige Auflistung spiegelt also Stracheys Einteilung wider, erweitert um die Inklusionspolymorphie von Cardelli und Wegner.

Universelle und Ad-hoc-Polymorphie

Universelle Polymorphie unterscheidet sich von Ad-hoc-Polymorphie in mehreren Aspekten. Bei Ad-hoc-Polymorphie kann ein Name oder ein Wert nur endlich viele verschiedene Typen besitzen. Diese sind zudem während der Kompilierung bekannt. Universelle Polymorphie dagegen erlaubt es, unendlich viele Typen zuzuordnen.

Ein weiterer Unterschied liegt darin, dass die Implementierung einer universell polymorphen Funktion generell gleichen Code unabhängig von den Typen ihrer Argumente ausführt, während ad-hoc-polymorphe (also überladene) Funktionen abhängig von den Typen ihrer Argumente unterschiedlich implementiert sein können.

Überladen und Coercion

Variablen sind überladen, wenn unterschiedliche Funktionen mit demselben Namen verbunden sind. Beispielsweise ist der Operator + in vielen Programmiersprachen von vornherein überladen. So können mit ihm ganze Zahlen und Gleitkommazahlen addiert werden. Oft wird er auch zur Stringkonkatenierung verwendet:

 42 + 3              (1)
 3.14 + 1.0          (2)
 "Hallo" + " Welt!"  (3)

Einige Sprachen unterscheiden dabei, welche Namen überladen werden dürfen und welche nicht. In Java ist Methodenüberladung erlaubt, Operatorüberladung außer der schon eingebauten Überladung, wie des +-Operators aber nicht. C++ und andere Sprachen erlauben generell beides.

Coercion ist eine Art implizite Typumwandlung, um zum Beispiel Argumente einer Funktion in die von der Funktion erwarteten Typen umzuwandeln. Coercion ist mit dem Überladen eng verknüpft und Unterschiede sind für den Programmierer nicht unbedingt gleich ersichtlich.

Zum Additionsbeispiel von oben gesellen sich noch zwei weitere hinzu:

 3.14 + 2            (4)
 3 + 2.14            (5)

In einer Sprache könnte der Additionsoperator lediglich für zwei reelle Zahlen definiert sein. Coercion würde dann dafür sorgen, dass ganze Zahlen zuerst in Gleitkommazahlen umgewandelt werden. In (4) und (5) würde dann Coercion zum Einsatz kommen. Es ist aber auch denkbar, dass der Additionsoperator für mehrere Varianten definiert ist.

Bei der Überladung handelt es sich offenbar nicht um eine echte Form von Polymorphie, da man sich vorstellen könnte, der Compiler werde die Uneindeutigkeit durch die mehrfache Benutzung eines Symboles zur Kompilationszeit wieder auflösen. Wir erlauben also nur einem Symbol, verschiedene Werte zu denotieren, die allerdings unterschiedliche und möglicherweise zueinander inkompatible Typen haben.

Mit Coercions verhält es sich ähnlich. Man könnte meinen, ein Operator akzeptiere Operanden verschiedenen Typs (wie das + oben), jedoch müssen die Typen erst für den Operator gewandelt werden. Der Ausgabetyp des Operators hängt also nicht mehr mit den Typen der Operanden zusammen (oder nur partiell), daher kann keine echte Polymorphie vorliegen.

Parametrische Polymorphie

Parametrisierte Polymorphie repräsentiert Typen, deren Definitionen Typvariablen enthalten. In Java spricht man auch von generischen Typen oder Generics. Die meisten modernen objektorientierten Programmiersprachen unterstützen parametrische Typdefinitionen, darunter auch Strongtalk (eine Variante von Smalltalk mit Typsystem), C# oder Eiffel. In C++ können generische Typen mit Hilfe sogenannter Templates nachgebildet werden.

Beispiel:

  • monomorph
TYPE iContainer IS ARRAY OF INTEGER;
  • polymorph durch Typvariable
TYPE Stack IS ARRAY OF [TYPVARIABLE]

Beschränkter parametrischer Polymorphismus

Man unterscheidet grundsätzlich

  • einfachen parametrischen Polymorphismus und
  • beschränkten parametrischen Polymorphismus.

Letzterer behebt die Probleme der Typsicherheit, die innerhalb von Typdefinitionen dadurch entstehen, dass beim Erstellen der Typdefinition auf Grund der Parametrisierung noch nicht klar ist, Objekte welchen Typs eigentlich Gegenstand der Typ-Operationen (des Protokolls, der Methoden, die Terminologie variiert hier je nach Programmiersprache) sind. Wird durch einen Typ beispielsweise eine numerische Operation definiert, die auf den Elementen des Typs ausführbar sein soll, seine Typvariable dann aber mit einem nichtnumerischen Typen belegt, so würde es zu Laufzeitfehlern kommen. In der Regel verwendet man daher beschränkte parametrische Typen, die für ihre Typvariablen eine Beschränkung auf bestimmte Typen angeben. In Strongtalk wird hierzu bspw. die Typvariable mittels T < Supertyp angegeben, wobei Supertyp die Einschränkung der Typen angibt, die in die Typvariable T eingesetzt werden können. Java ermöglicht die Angabe solcher Einschränkungen mittels der Schreibweise <T extends Supertyp>.

Inklusionspolymorphie

Inklusionspolymorphie bezeichnet die Eigenschaft, jede Methode statt auf einem Subtyp auch auf einem Basistypen ausführen zu können. Subtyping ist demnach eine Form der Inklusionspolymorphie.

Man unterscheidet zwischen

  • Kompilationszeit-Polymorphie (statisches Binden)
    Es kann zur Kompilationszeit der Typ des Objekts die aufgerufene Funktion (auch "Methode" genannt) bestimmt werden.
  • Laufzeit-Polymorphie (dynamisches Binden).
    Erst zur Laufzeit kann bestimmt werden, welche Methode aufzurufen ist (späte Bindung). Es kann also vom Programmlauf abhängig sein, welche Methode zur Anwendung kommt. Die Laufzeit-Polymorphie ist einer der wichtigsten Bestandteile der objektorientierten Programmierung und wurde zuerst in der Programmiersprache Smalltalk umgesetzt und zum Beispiel in Objective-C eingesetzt. Ein weiteres Beispiel für späte Bindung sind generische Methoden wie im "Common Lisp Object System".

Beispiel

Angenommen, eine Anwendung soll statistische Daten sowohl grafisch als auch schriftlich in Tabellenform darstellen. Außerdem soll es möglich sein, die Darstellungsmethoden über Plugins zu erweitern. Dann erlaubt das Konzept der Polymorphie über das VisualizationPlugin Interface jede beliebige Implementierung (hier GraphDisplayPlugin, TextDisplayPlugin, HistogramDisplayPlugin) aufzurufen.

Die Anwendung selbst muss bei neuen Plugins nicht geändert werden und kann diese einfach über das Interface mit dem Aufruf von setData und display starten.

 interface VisualizationPlugin {
   public void setData( DisplayData data );
   public void display();
 }
 class GraphDisplayPlugin implements VisualizationPlugin {
   public void setData( DisplayData data ) { /* set data to be displayed */ }
   public void display() { /* Show Data as Graph */ }
 }
 class TextDisplayPlugin implements VisualizationPlugin {
   public void setData( DisplayData data ) { /* set data to be displayed */ }
   public void display() { /* Show Data as table */ }
 }
 class HistogramDisplayPlugin implements VisualizationPlugin {
   public void setData( DisplayData data ) { /* set data and calculate history data */ }
   public void display() { /* Show history data as Graph */ }
 }

Literatur

Weblinks

Einzelnachweise

  1. Informatik. Duden, Mannheim 2001, ISBN 978-3-411-10023-1, S. 496
  2. Fundamental concepts in programming languages. Lecture notes for International Summer School in Computer Programming, Copenhagen, Aug. 1967
  3. On Understanding Types, Data Abstraction, and Polymorphism. ACM Computing Surveys, 17(4):471–522, 1985

Wikimedia Foundation.

Schlagen Sie auch in anderen Wörterbüchern nach:

  • Polymorphie — (gr. πολυμορφία Polymorphia „Vielgestaltigkeit“) steht für: ein Konzept der Programmierung, siehe Polymorphie (Programmierung) das Konzept der Polymorphie bei Computerviren, siehe Polymorphe Computerviren das Auftreten einer Genvariante in einer… …   Deutsch Wikipedia

  • Polymorphie — Vielgestaltigkeit; Polymorphismus (fachsprachlich) * * * Po|ly|mor|phie 〈f. 19; unz.〉 oV Polymorphismus 1. 〈Chem.; Min.〉 Ausbildung verschiedener Kristallformen von Mineralen bei gleicher chem. Zusammensetzung; Sy Heteromorphie 2. 〈Biol.〉… …   Universal-Lexikon

  • Methode (objektorientierte Programmierung) — Die objektorientierte Programmierung (kurz OOP) ist ein auf dem Konzept der Objektorientierung basierendes Programmierparadigma. Die Grundidee der objektorientierten Programmierung ist, Daten und Funktionen, die auf diese Daten angewandt werden… …   Deutsch Wikipedia

  • Objektorientierte Programmierung — Die objektorientierte Programmierung (kurz OOP) ist ein auf dem Konzept der Objektorientierung basierendes Programmierparadigma. Die Grundidee dabei ist, Daten und Funktionen, die auf diese Daten angewandt werden können, möglichst eng in einem… …   Deutsch Wikipedia

  • Vererbung (objektorientierte Programmierung) — Vererbung dargestellt mittels UML. Die abgeleitete Klasse hat die Attribute x und y und verfügt über die Methoden a und b (im UML Sprachgebrauch Operationen a und b). Die Vererbung (engl. Inheritance) ist eines der grundlegenden Konzepte der… …   Deutsch Wikipedia

  • Kapselung (objektorientierte Programmierung) — Die Objektorientierung, kurz OO, ist ein Ansatz zur Entwicklung von Software, der darauf beruht, die zu verarbeitenden Daten anhand ihrer Eigenschaften und der möglichen Operationen zu klassifizieren. Im Vergleich zu Ansätzen, bei denen… …   Deutsch Wikipedia

  • Aspekt-orientierte Programmierung — Die Artikel Aspektorientierte Programmierung und Cross Cutting Concern überschneiden sich thematisch. Hilf mit, die Artikel besser voneinander abzugrenzen oder zu vereinigen. Beteilige dich dazu an der Diskussion über diese Überschneidungen.… …   Deutsch Wikipedia

  • Überladen (Programmierung) — Eine Programmiersprache ermöglicht das Überladen eines Bezeichners, wenn mehrere Vereinbarungen mit demselben Bezeichner gleichzeitig sichtbar sein können; bei der Verwendung erfolgt dann die Auswahl anhand des Kontextes. Mit anderen Worten… …   Deutsch Wikipedia

  • Klasse (objektorientierte Programmierung) — Klasse ist in der Objektorientierung ein abstrakter Oberbegriff für die Beschreibung der gemeinsamen Struktur und des gemeinsamen Verhaltens von realen Objekten (Klassifizierung) im Softwaredesign: reale Objekte werden auf die für die Software… …   Deutsch Wikipedia

  • Überschreiben (objektorientierte Programmierung) — Der Begriff Überschreiben (engl. override, wörtlich außer Kraft setzen, überwinden) beschreibt eine Technik in der objektorientierten Programmierung, die es einer Unterklasse erlaubt, eine eigene Implementierung einer von der Oberklasse geerbten… …   Deutsch Wikipedia

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”