Wie funktioniert der Polymorphismus mit nicht definierten Zwischentypen in C #?

7

Im folgenden Code hätte ich erwartet, dass der Aufruf von a.Generate(v) zum Aufrufen von V.Visit(A a) geführt hätte, da, wenn Generate aufgerufen wird this vom Typ A ist. Hoewever scheint this als gesehen zu haben ein Inter stattdessen.

Ist es möglich, das beabsichtigte Verhalten zu haben, ohne die (identische) Methode explizit in A und B und nur in der gemeinsamen Basisklasse zu implementieren? Wenn ja, wie kann es erreicht werden?

%Vor%

Bearbeiten In den Antworten wurde vorgeschlagen, dass der obige Code nicht polymorph ist. Dem würde ich widersprechen. V.Visit ist polymorph .

    
joce 30.01.2012, 19:21
quelle

4 Antworten

15

Sie erwarten, dass der Aufruf von v.Visit(this) ermittelt, welche Überladung von Visit basierend auf den Laufzeittypen von sowohl v als auch% co_de aufgerufen werden soll %.

Sprachen, die diese Funktion haben, werden "double virtual dispatch" -Sprachen genannt. (Oder, wenn mehr als zwei Dinge berücksichtigt werden, werden sie als "multiple virtual dispatch" -Sprachen oder "multimethod" -Sprachen bezeichnet.)

C # ist keine doppelte virtuelle Dispatch-Sprache; es ist eine einzige virtuelle Dispatch-Sprache , wenn Dispatch-Entscheidungen zur Kompilierungszeit getroffen werden . Das heißt, die Entscheidung, welche Überladung zu wählen ist, basiert auf dem Laufzeit Typ des Empfängers , aber auf den Kompilierzeit Typen der Argumente .

In Ihrem Fall verwendet C # nicht einzelnen virtuellen Versand , da der Aufruf von this gar nicht erst ein virtueller Anruf ist! Die Tatsache, dass der Aufruf von Visit ein virtueller Aufruf war, ist völlig irrelevant, und die Tatsache, dass Generate überladen ist, ist ebenfalls irrelevant. Der Versand an Visit erfolgt nicht-virtuell , sodass die Dispatch-Logik vollständig auf dem Kompilierzeit -Typ des Empfängers, Visit , und dem Argument basiert %Code%. Da bekannt ist, dass der Empfänger vom Typ v ist und das Argument vom Typ this ist, muss die Überladungsauflösung die bestmögliche Übereinstimmung auswählen, die nur für diese Information gilt . Es kann nicht die Versionen von V auswählen, die Inter oder Visit benötigen, weil diese abgeleiteter sind als der bekannte Argumenttyp A . Es muss die Überladung mit dem formalen Parameter weniger abgeleitet , B , auswählen.

Wenn Sie einen doppelten virtuellen Versand in C # erreichen möchten, gibt es zwei Standardmethoden. Zuerst können Sie Inter ; Mit Base wird die Analyse zur Laufzeit mit den Laufzeittypen durchgeführt. Übergeben Sie einfach den Empfänger und die Argumente an dynamic und der Compiler wird sich darum kümmern. Dies verursacht jedoch erhebliche Leistungskosten.

Der zweite Standardweg ist das Besuchermuster , das Sie im Internet finden können. Ich vermute aufgrund der Namen Ihrer Methoden, dass Sie bereits versuchen, das Besuchermuster zu implementieren; Das ist nicht der richtige Weg.

    
Eric Lippert 30.01.2012, 19:59
quelle
2

Das ist kein polymorpher Code, polymorpher Code hat eine dynamische Bindung, die bestimmt, welche Methode zur Laufzeit aufgerufen wird. Beide Objekte müssen eine ähnliche Basisklasse mit virtuellen Methoden haben, um diese dynamische Bindung durchzuführen. Momentan ist Ihre Bindung statisch und wird zur Kompilierzeit bestimmt.

    
Matthew 30.01.2012 19:27
quelle
2

Das Problem ist, dass die Methode Generate in der Klasse Iter definiert ist. Wenn also die Methode Generate aufgerufen wird, übergibt sie eine Referenz an eine Iter .

Wenn Sie A oder B in übergeben möchten, machen Sie Generate virtual und überschreiben Sie sie auf den Ebenen A und B , um den korrekt gewichteten Wert zu übergeben.

    
Randolpho 30.01.2012 19:24
quelle
1

Was erwartest du genau?

%Vor%

Irgendwie kompiliert der Compiler eine Version des Codes für v.Visit (this). Es kann nicht verschiedene Versionen für jede Aufrufinstanz gemäß dem tatsächlichen tpye des übergebenen Arguments kompilieren.

In einem polymorphen Design sind Inter und jede seiner abgeleiteten Klassen dafür verantwortlich, "persönliche" Dinge zu tun.

%Vor%

wobei VisitedBy() eine virtuelle Funktion ist.

    
Serge Wautier 30.01.2012 19:27
quelle

Tags und Links