Warum werden virtuelle Funktionen zur Laufzeit behandelt?

8

Sicherlich ist der Compiler schlau genug, um genau zu bestimmen, welche Funktion in einigen Fällen gewünscht ist, aber warum brauchen andere Fälle Laufzeitunterstützung?

    
Kein Mitleid 31.12.2013, 04:08
quelle

4 Antworten

9

Weil wir nicht immer wissen, auf welche Instanz wir zur Laufzeit stoßen werden.

Zum Beispiel haben Sie Klassen: SuperClass , Subclass1 und Subclass2 und alle haben eine Methode doACoolThing() . Der Benutzer drückt eine Schaltfläche 0 , 1 oder 2 , und abhängig von seiner Eingabe wird eine Instanz der entsprechenden Klasse erstellt und die Methode doACoolThing() aufgerufen.

Es gibt für uns (und auch den Compiler) keine Möglichkeit herauszufinden, welche Klassenmethode zur Laufzeit aufgerufen wird.

Deshalb benötigen solche Tricks eine Laufzeitunterstützung.

Ein kleines Beispiel, um eine Idee zu illustrieren (P.S. schreibe den Code nicht so, hier nur um Polymorphie zu illustrieren :)):

%Vor%     
FreeNickname 31.12.2013, 04:13
quelle
6

Betrachten Sie den folgenden Code:

%Vor%

Der Compiler weiß nicht, was der Benutzer eingeben soll. Er kann also nicht erkennen, ob baseptr auf eine Instanz von Derived1 oder Derived2 zeigt.

    
Barmar 31.12.2013 04:17
quelle
2

Angenommen, Sie sind von einer Benutzereingabe abhängig, um zu entscheiden, welche der Unterklassen Sie erstellen möchten.

%Vor%

Wie kann der Compiler ohne virtuelle Funktion die richtige Version von f wissen, die zur Laufzeit aufgerufen wird, wenn Sie f abhängig von verschiedenen Instanzen auswählen möchten? Nur nicht.

    
Eric Z 31.12.2013 04:20
quelle
1

Gründe sind:

  • Es gibt einige Eingaben (Tastatur, Maus, Datei, Datenbank, Netzwerk, Hardwaregerät usw.), die nur zur Laufzeit bekannt sind und den tatsächlichen Datentyp und folglich die Memberfunktionen bestimmen, die aufgerufen werden müssen

  • Funktionen, die nicht inline sind und von vielen Stellen mit unterschiedlichen abgeleiteten Objekten aufgerufen werden, müssen virtuell versendet werden - die Alternative für den statischen Versand beträgt "Instanziierungen" pro Typ (ala Templates und mit etwas Code Bloat Potential impliziert)

  • Funktionen, die virtuellen Versand verwenden, können in Objekten kompiliert werden, die in ausführbare Dateien verknüpft sind und mit Zeigern zu Argumenttypen aufgerufen werden, von denen sie zum Zeitpunkt der Kompilierung noch nichts wussten

  • virtueller Versand kann eine Art "Kompilierungsfirewall" bereitstellen (ähnlich wie der Zeiger auf Implementierung oder pImpl-Idiom), so dass Änderungen an den Dateien, die die Funktionsimplementierung definieren, keine Änderungen an den Kopfzeilen erfordern die Schnittstellen, was bedeutet, dass Client-Code erneut verknüpft, aber nicht neu kompiliert werden muss: das kann enorme Zeit in einer Unternehmensumgebung einsparen

  • es ist oft einfach zu kompliziert, um den Typ an verschiedenen Stellen während des Programms zu verfolgen: selbst wenn es möglich ist, möglich aus der kompilierzeitlichen Analyse des Codes zu erfahren, muss der Compiler nur etwas machen begrenzte Bemühungen, konstante / deterministische Kompilierzeitdaten zu erkennen, und das beinhaltet nicht das Nachverfolgen beliebig komplexer Operationen auf z. B. Unterordnungen von Zeigern zu Basis, die verwendet werden könnten, wenn ein Aufruf schließlich virtuell ausgelöst wird.

    • Dies gilt insbesondere für Container und Variablen, die State-Maschinen implementieren, mit komplexen Regeln darüber, wann der Pointer-to-Base gelöscht und auf einen anderen abgeleiteten Typ zurückgesetzt werden sollte
Tony Delroy 31.12.2013 05:22
quelle