Überladen (Programmierung)

Ü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 verdeckt eine Vereinbarung nur dann eine andere, wenn nicht nur der Bezeichner, sondern weitere Merkmale übereinstimmen. Meist handelt es sich um Bezeichner von Unterprogrammen, die aufgrund der Parameter-, bisweilen auch des Resultattypen unterschieden werden. Das Überladen wird, da es sich um einen rein syntaktischen Mechanismus handelt, nach Strachey, als Ad-hoc-Polymorphie betrachtet.

Auch Aufzählungswerte und Literale können überladen werden.

Operatorüberladung

Seit jeher unterschieden die meisten Programmiersprachen, der mathematischen Tradition folgend, nicht zwischen den Operatorssymbolen (+, –, …) für Ganzzahl- (Integer) und Gleitpunktarithmetik (real, float). Zur bruchlosen Erweiterung einer Sprache um benutzerdefinierte Typen ist es hilfreich, die Operatorsymbole auch für benutzerdefinierte Typen überladen zu können.

Ein Beispiel für das Überladen des Operators + in C++:

 class EinfacheKomplexeZahl
 {
 public:
    EinfacheKomplexeZahl() {}
    EinfacheKomplexeZahl(float real, float imag)
    {
        m_real = real;
        m_imag = imag;
    }
    ~EinfacheKomplexeZahl() {}
 
    EinfacheKomplexeZahl operator+(const EinfacheKomplexeZahl &o) const
    {
        return EinfacheKomplexeZahl(o.m_real + m_real, o.m_imag + m_imag);
    }
 
 private:
    float m_real, m_imag;
 };
 
 int main(int argc, char *argv[])
 {
    EinfacheKomplexeZahl z1(5.0f, 3.14159f);
    EinfacheKomplexeZahl z2(0.0f, -3.14159f);
    EinfacheKomplexeZahl z3 = z1 + z2;
    // z3.m_real = 5 und z3.m_imag = 0
    return 0;
 }

In C++ lassen sich fast alle vorhandenen Operatoren überladen.

Die Parameter und Rückgabewerte der Operatorüberladungen müssen für jeden Operator sorgsam gewählt werden, denn manchmal ist er vordefiniert. So übernimmt der new-Operator einen size_t-Parameter und muss einen void*-Zeiger auf den reservierten Speicherblock zurückgeben. Analog dazu übernimmt der delete-Operator einen Zeiger auf den Speicherblock und muss diesen freigeben. Mit dieser Technik kann man sich sehr leicht einen Mechanismus zur Überwachung des Speichers programmieren, was ohne Operatorüberladung wesentlich umständlicher wäre. Dazu könnte man z. B. mit malloc() mehr Speicher als nötig reservieren und an den Anfang des Speichers eine Struktur mit diversen Informationen über den Speicherblock speichern. Der zurückgegebene Zeiger zeigt auf den Speicher nach der Struktur. Die delete-Funktion ruft free() dann auf den Beginn der Struktur auf. Außerdem könnte man die Menge an reserviertem Speicher zählen und mit der freigegebenen Menge abgleichen:

 static std::size_t nichtFreigegebenerSpeicher = 0;
 struct blockKopf
 {
   int magic;
   std::size_t size;
 };
 
 void * operator new(std::size_t size) throw (std::bad_alloc)
 {
   blockKopf *p = (blockKopf *)malloc(sizeof(blockKopf) + size);
   if (p == NULL)
      throw(std::bad_alloc);
   p->magic = 0815;
   p->size = size;
   nichtFreigegebenerSpeicher += size;
   return (void *)((char *)p + sizeof(blockKopf));
 }
 
 void operator delete(void *p)
 {
   blockKopf *block = (char *)p - sizeof(blockKopf);
   if (block->magic != 0815)
     return;
   nichtFreigegebenerSpeicher -= block->size;
   free(block);
 }
 
 #include <iostream>
 int main(int argc, char *argv[])
 {
   // Objekte mit new erstellen und mit delete löschen
   // .....
 
   std::cout << nichtFreigegebenerSpeicher << " unfreigegebener Speicher!" << std::endl;
 }

Operatoren können sowohl als globale Funktion als auch als Methode überladen werden. Als Beispiel bedeutet eine globale Überladung für new, dass alle mit new angelegten Objekte über diese Funktion erstellt werden, während dies bei Überladung in einer Methode nur bei Anlegen von Objekten dieser einen Klasse mit new geschieht. Ist ein Operator sowohl global als auch als Methode einer Klasse definiert, wird letztere der globalen Überladung vorgezogen.

Ziel der Operatorüberladung ist immer ein einfach lesbarer Quellcode, wobei genau dies bei hoher Abstraktion von Klassen durch die Benutzung von Operatorüberladungen erschwert werden kann. Bei primitiven numerischen Datentypen ist die Überladung von * selbsterklärend. Überlädt man diesen Operator allerdings für dreidimensionale Vektoren, ist nicht eindeutig, ob das Skalarprodukt- oder Kreuzprodukt ausgeführt wird. In diesem Fall sind zwei Methoden namens Skalarprodukt() und Kreuzprodukt() vorzuziehen. Sogar die Konkatenation von zwei Strings mit dem Operator +, wie sie von der std::string-Klasse aus der C++-Standardbibliothek geliefert wird, ist ein Grenzfall.

Anzumerken ist, dass Operatorenüberladung normalerweise nur als syntaktischer Zucker verwendet werden soll, das heißt die dem Programmierer zur Verfügung gestellte Funktionalität auch über namentliche Funktionen bzw. Methoden zur Verfügung gestellt werden sollte.

Abgrenzung des Begriffs

Beim dynamischen Binden wird statt des deklarierten Typs der zur Laufzeit tatsächlich angetroffene Typ herangezogen. Dieser Unterschied zwischen dynamischem Binden und Überladen führt oft zu subtilen Programmfehlern.

Beispiel in C++:

 // Funktion 1
 int quadrat(int i) // Übernimmt einen int
 {
   return i * i;
 }
 
 // Funktion 2
 int quadrat(const std::string& str) // Übernimmt eine Referenz auf ein String-Objekt mit konstanten Member-Variablen aus der STL
 {
    int t = atoi(str.c_str());
    return t * t;
 }
 
 int main()
 {
    std::string s("2");
    int  i   = 3;
    int  k   = quadrat(s); // ruft die überladene Funktion für String-Parameter auf => k == 4
    int  m   = quadrat(i); // ruft die Funktion für Parameter vom Typ int auf => m == 9
 }

Siehe auch


Wikimedia Foundation.

Игры ⚽ Нужно решить контрольную?

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

  • Überladen — Eine Programmiersprache ermöglicht das Überladen (von englisch: overloading) eines Bezeichners, wenn mehrere Vereinbarungen mit demselben Bezeichner gleichzeitig sichtbar sein können; bei der Verwendung erfolgt dann die Auswahl anhand des… …   Deutsch Wikipedia

  • 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… …   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

  • Funktionionale Programmierung — Dieser Artikel oder Abschnitt bedarf einer Überarbeitung. Näheres ist auf der Diskussionsseite angegeben. Hilf mit, ihn zu verbessern, und entferne anschließend diese Markierung. Funktionale Programmierung ist ein Programmierparadigma. Programme… …   Deutsch Wikipedia

  • Methode (Programmierung) — Der Begriff Methode (Eng. method oder member function, zu deutsch auch Mitgliedsfunktion) wird in der Programmierung allgemein als Sammelbegriff sowie auch synonym unter anderem für Funktionen und Prozeduren verwendet. Speziell in der… …   Deutsch Wikipedia

  • Template (Programmierung) — Templates (engl. für Schablonen), auch Mustervorlagen oder Schablone, sind fortgeschrittene Elemente von Programmiersprachen. Sie sind „Programmgerüste“, die bei Bedarf vom Übersetzer instanziiert und als normale Klassen oder Funktionen zur… …   Deutsch Wikipedia

  • Späte Bindung — Polymorphie (griechisch, „Vielgestaltigkeit“) ist die Fähigkeit eines Bezeichners – der einen Festwert (Literal) oder eine Variable repräsentieren kann – sich abhängig von seiner Verwendung unterschiedlich darzustellen. Sie erlaubt dem Bezeichner …   Deutsch Wikipedia

  • Rücksprungadresse — Ein Unterprogramm oder eine Subroutine ist ein Teil eines Programmes, der aus gegebenenfalls mehreren anderen Programmteilen heraus gerufen werden kann und nach Abschluss der Abarbeitung jeweils in das aufrufende Programm wieder zurückkehrt. Je… …   Deutsch Wikipedia

  • Subroutine — Ein Unterprogramm oder eine Subroutine ist ein Teil eines Programmes, der aus gegebenenfalls mehreren anderen Programmteilen heraus gerufen werden kann und nach Abschluss der Abarbeitung jeweils in das aufrufende Programm wieder zurückkehrt. Je… …   Deutsch Wikipedia

  • Invarianz (Informatik) — In der objektorientierten Programmierung bedeutet Kovarianz und Kontravarianz, ob ein Aspekt gleichartig der Vererbungsrichtung (kovariant) oder entgegengesetzt zu dieser (kontravariant) ist. Liegt in der Unterklasse keine Änderung gegenüber der… …   Deutsch Wikipedia

Share the article and excerpts

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