<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Virtuelle_Methode</id>
	<title>Virtuelle Methode - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Virtuelle_Methode"/>
	<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Virtuelle_Methode&amp;action=history"/>
	<updated>2026-05-28T21:09:03Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Wikipedia (Deutsch) – Lokale Kopie</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://wiki-de.moshellshocker.dns64.de/index.php?title=Virtuelle_Methode&amp;diff=245756&amp;oldid=prev</id>
		<title>imported&gt;Uncopy: /* Rein virtuelle Methoden */ Beispiel: Polymorphie mittels Nutzung der Basisklasse demonstriert</title>
		<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Virtuelle_Methode&amp;diff=245756&amp;oldid=prev"/>
		<updated>2024-02-19T09:58:05Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Rein virtuelle Methoden: &lt;/span&gt; Beispiel: Polymorphie mittels Nutzung der Basisklasse demonstriert&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Eine &amp;#039;&amp;#039;&amp;#039;virtuelle Methode&amp;#039;&amp;#039;&amp;#039; ist in der [[Objektorientierte Programmierung|objektorientierten Programmierung]] eine [[Methode (Programmierung)|Methode]] einer [[Klasse (Programmierung)|Klasse]], deren Einsprungadresse erst zur Laufzeit ermittelt wird. Dieses sogenannte [[Dynamische Bindung|dynamische Binden]] ermöglicht es, Klassen von einer Oberklasse abzuleiten und dabei Funktionen zu [[Überschreiben (OOP)|überschreiben]] bzw. zu [[überladen]]. Das Konzept der virtuellen Methoden wird von einem [[Compiler]] (Übersetzer) zum Beispiel mittels [[Tabelle virtueller Methoden|Funktionstabellen]] umgesetzt.&lt;br /&gt;
&lt;br /&gt;
In manchen Programmiersprachen wie [[Java (Programmiersprache)|Java]], [[Smalltalk (Programmiersprache)|Smalltalk]] und [[Python (Programmiersprache)|Python]] sind alle Methoden virtuell. Dagegen müssen in Sprachen wie [[C++]], [[C-Sharp|C#]], [[SystemVerilog]] oder [[Object Pascal]] Methoden für diesen Zweck mit dem Schlüsselwort &amp;lt;code&amp;gt;virtual&amp;lt;/code&amp;gt; gekennzeichnet werden, was die zusätzliche Möglichkeit bietet, das Überladen in Unterklassen zu verhindern.&lt;br /&gt;
&lt;br /&gt;
== Ableiten von Klassen und Überschreiben von Methoden ==&lt;br /&gt;
In objektorientierten Programmiersprachen wie C++, C#, Object Pascal oder Java können Klassen erzeugt werden, indem man sie von anderen Klassen ableitet. Abgeleitete Klassen besitzen alle Methoden und Datenfelder der ursprünglichen Klasse und können durch weitere Felder und Methoden erweitert werden. In einigen Fällen ist es allerdings wünschenswert, bereits existierende Methoden abzuändern, d.&amp;amp;nbsp;h., sie neu zu schreiben. In diesem Fall spricht man von [[Überschreiben (OOP)|Überschreiben]].&lt;br /&gt;
&lt;br /&gt;
Durch das Ableiten von Klassen ergibt sich auch die sogenannte [[Polymorphie (Programmierung)|Polymorphie]]. Jede Klasse repräsentiert einen eigenen [[Datentyp]]. Abgeleitete Klassen haben mindestens einen weiteren Datentyp, nämlich den der [[Basisklasse]] (auch als &amp;#039;&amp;#039;Ober-,&amp;#039;&amp;#039; &amp;#039;&amp;#039;Super- oder Elternklasse&amp;#039;&amp;#039; bezeichnet). Dadurch ist es zum Beispiel möglich, eine Liste von Objekten der Klasse&amp;amp;nbsp;A zu benutzen, obwohl tatsächlich auch Objekte der Klasse&amp;amp;nbsp;B (die von A abgeleitet wurde) in der Liste abgelegt sind.&lt;br /&gt;
&lt;br /&gt;
== Problematik für den Übersetzer ==&lt;br /&gt;
Ein [[Compiler]] versucht während der Übersetzung, für jede aufgerufene Funktion eine Adresse im Speicher festzulegen, an der eine Funktion oder Methode beginnt. Im späteren Programm wird die [[Prozessor|CPU]] bei einem Aufruf die entsprechende Adresse anspringen und weiterarbeiten (daneben wird noch einige administrative Arbeit notwendig, die hier nicht weiter von Bedeutung ist). Bei abgeleiteten Klassen mit überschriebenen oder überladenen Methoden ist jedoch nicht immer zur [[Übersetzungszeit]] bekannt, welche Methode aufzurufen ist. Im Beispiel mit der Liste (s.&amp;amp;nbsp;u.) kann der Übersetzer zum Beispiel nicht immer wissen, wann andere Objekte als Objekte vom Typ&amp;amp;nbsp;A in der Liste auftauchen.&lt;br /&gt;
&lt;br /&gt;
== Lösung: Indirekte Adressierung ==&lt;br /&gt;
Eine Lösung ist die indirekte Adressierung über eine Tabelle. Kann der Übersetzer nicht feststellen, welche Methode angesprungen werden soll, wird nicht eine Einsprungadresse angegeben, sondern nur ein Verweis auf einen Eintrag in der Funktionstabelle abgelegt. Darin stehen die konkreten Einsprungadressen, die während des Programmlaufs angesprungen werden sollen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Eine Liste enthält Elemente des Typs&amp;amp;nbsp;A und B. A ist Oberklasse von B und B überschreibt die Methode&amp;amp;nbsp;m aus A. Nun soll für jedes Element die Methode&amp;amp;nbsp;m aufgerufen werden. Zu jeder Klasse gibt es daher eine Tabelle mit Adressen von Funktionen. Die verzeichneten Adressen der Tabelle von Objekten des Typs&amp;amp;nbsp;B sind andere als die der Tabelle von Objekten des Typs&amp;amp;nbsp;A. Im Maschinencode wird nun die [[Prozessor|CPU]] angewiesen, die Funktion aufzurufen, die an der Tabellenposition&amp;amp;nbsp;„m“ des aktuellen Objekts steht.&lt;br /&gt;
&lt;br /&gt;
== Abstrakte, virtuelle Methoden ==&lt;br /&gt;
Virtuelle Methoden können zusätzlich auch noch &amp;#039;&amp;#039;abstrakt&amp;#039;&amp;#039; sein. In der Klasse, in der die Methode deklariert wird, bleibt die Methode leer, kann aber theoretisch noch aufgerufen werden. Erst in einer abgeleiteten Klasse wird die abstrakte Methode überschrieben und kann dann benutzt werden.&lt;br /&gt;
&lt;br /&gt;
Wenn eine Klasse eine oder mehrere abstrakte Methoden enthält, wird sie als &amp;#039;&amp;#039;[[abstrakte Klasse]]&amp;#039;&amp;#039; bezeichnet. In [[C++]] und [[Java (Programmiersprache)|Java]] ist es nicht möglich, ein Objekt einer abstrakten Klasse zu erzeugen. [[Object Pascal]] lässt dies zu, allerdings wird bei dem Aufruf einer abstrakten Methode eine [[Exception]] ausgelöst.&lt;br /&gt;
&lt;br /&gt;
== Rein virtuelle Methoden ==&lt;br /&gt;
Rein virtuelle Methoden ({{lang|en|&amp;#039;&amp;#039;pure virtual functions&amp;#039;&amp;#039;}}) erweitern den Begriff der abstrakten Methode noch weiter. Da eine abstrakte, virtuelle Methode theoretisch noch aufgerufen werden kann, setzt man zum Beispiel in C++ die Methoden explizit gleich [[Nullwert|Null]]. Dadurch können diese Methoden nicht mehr aufgerufen werden, und von der Klasse kann kein Objekt erstellt werden. Abgeleitete Klassen müssen diese Methoden erst implementieren, nur dann kann ein Objekt von ihnen erzeugt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
struct Tier {&lt;br /&gt;
    // Rein virtuelle Methode&lt;br /&gt;
    virtual void fressen() = 0;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
struct Wolf: Tier {&lt;br /&gt;
    // Implementierung der virtuellen Methode&lt;br /&gt;
    void fressen() {&lt;br /&gt;
        std::cout &amp;lt;&amp;lt; &amp;quot;Der Wolf frisst Fleisch.&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
struct Schaf: Tier {&lt;br /&gt;
    // Implementierung der virtuellen Methode&lt;br /&gt;
    void fressen() {&lt;br /&gt;
        std::cout &amp;lt;&amp;lt; &amp;quot;Das Schaf frisst Pflanzen.&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Allgemeine Funktion die mit jedem Tier benutzt werden kann&lt;br /&gt;
void tier_fuettern(Tier&amp;amp; tier) {&lt;br /&gt;
    tier.fressen();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    Wolf wotan;&lt;br /&gt;
    Schaf dolly;&lt;br /&gt;
    tier_fuettern(wotan);&lt;br /&gt;
    tier_fuettern(dolly);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Destruktoren ==&lt;br /&gt;
Eine weitere Eigenheit von C++ sind [[Destruktor]]en, die für abschließende Aufgaben wie [[Speicherleck#Explizite Speicherfreigabe|Speicherfreigabe]] verwendet werden. Jede Klasse, deren Attribute nicht primitive Typen sind oder die andere [[Ressource#Informatik|Ressourcen]] verwendet (wie z.&amp;amp;nbsp;B. eine Datenbankverbindung), sollte diese unbedingt in ihrem Destruktor freigeben. Um immer auf den richtigen Destruktor zugreifen zu können, muss der Destruktor des Urahnen als &amp;lt;code&amp;gt;virtual&amp;lt;/code&amp;gt; deklariert sein.&lt;br /&gt;
&lt;br /&gt;
Folgendes Beispiel zeigt die Verwendung und Vererbung von nicht-virtuellen Destruktoren, was zu undefiniertem Verhalten führt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace std;&lt;br /&gt;
&lt;br /&gt;
struct A {&lt;br /&gt;
    A() {}&lt;br /&gt;
    ~A() {&lt;br /&gt;
        cout &amp;lt;&amp;lt; &amp;quot;Zerstöre A&amp;quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
struct B: A {&lt;br /&gt;
    B() {}&lt;br /&gt;
    ~B() {&lt;br /&gt;
        cout &amp;lt;&amp;lt; &amp;quot;Zerstöre B&amp;quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    // Gemäß C++-Standard undefiniertes Verhalten&lt;br /&gt;
    // Meist wird am Ende nur ~A() aufgerufen, da ~A() nicht virtuell ist&lt;br /&gt;
    unique_ptr&amp;lt;A&amp;gt; b1 = make_unique&amp;lt;B&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
    // Am Ende werden Destruktoren ~B() und ~A() aufgerufen&lt;br /&gt;
    unique_ptr&amp;lt;B&amp;gt; b2 = make_unique&amp;lt;B&amp;gt;();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Eine mögliche Ausgabe wäre:&lt;br /&gt;
 Zerstöre B&lt;br /&gt;
 Zerstöre A&lt;br /&gt;
 Zerstöre A&lt;br /&gt;
[[Kategorie:Objektorientierte Programmierung]]&lt;br /&gt;
[[Kategorie:Unterprogramm]]&lt;br /&gt;
&lt;br /&gt;
[[sv:Funktion (programmering)#Virtuell funktion]]&lt;/div&gt;</summary>
		<author><name>imported&gt;Uncopy</name></author>
	</entry>
</feed>