c ++ virtueller Funktionsaufruf ohne Zeiger oder Referenz

7

Soweit ich weiß, erfordert der virtuelle Funktionsaufruf normalerweise einen Zeiger oder eine Referenz. Daher bin ich sehr von den folgenden Codes überrascht.

%Vor%

Die Ausgabe ist

D

Könnte jemand bitte kommentieren, warum dieser virtuelle Funktionsaufruf funktioniert? Danke.

    
chao 13.08.2014, 01:21
quelle

3 Antworten

11

Innerhalb einer Elementfunktion werden alle Verweise auf andere Elementfunktionen oder Variablen implizit über den Zeiger this aufgelöst. In der Definition von runB() bedeutet also call() wirklich this->call() . Der Aufruf der virtuellen Funktion wird mithilfe der virtuellen Tabelle des aktuellen Objekts ausgeführt.

    
Wyzard 13.08.2014 01:25
quelle
7

Erstens erfordert der Aufruf virtueller Funktionen keinen Zeiger oder eine Referenz. Soweit es die Sprache betrifft, ist der Aufruf any für die virtuelle Funktion ein virtueller Aufruf, es sei denn, Sie unterdrücken den Mechanismus für den virtuellen Versand explizit durch Verwendung eines qualifizierten Funktionsnamens . Zum Beispiel diese

%Vor%

sind Aufrufe, die explizit gezwungen wurden, nicht virtuell zu sein. Dies ist jedoch

%Vor%

ist ein virtueller Anruf. In diesem Fall ist es für den Compiler sofort offensichtlich, dass die Zielfunktion D::call() ist, so dass der Compiler diesen virtuellen Aufruf normalerweise zu einem regulären direkten Aufruf optimiert. Doch konzeptionell ist d.call() immer noch ein virtueller Aufruf.

Zweitens wird der Aufruf von call() in B::runB() über einen Zeiger ausgeführt. Der Zeiger ist dort implizit vorhanden. Das Schreiben von call() in B::runB() ist nur eine Kurzform für (*this).call() . this ist ein Zeiger. Also wird durch einen Zeiger aufgerufen.

Drittens besteht die Schlüsseleigenschaft von virtuellem Aufruf darin, dass die Zielfunktion in Übereinstimmung mit dem dynamischen -Typ des im Aufruf verwendeten Objekts ausgewählt wird. In Ihrem Fall ist der dynamische Typ des Objekts B::runB() sogar% *this % D . Deshalb ruft es D::call() auf, wie es sollte.

Viertens: Was Sie wirklich brauchen, ist ein Zeiger oder eine Referenz, um den tatsächlichen Polymorphismus zu beobachten. Der eigentliche Polymorphismus tritt auf, wenn der statische Typ des im Aufruf verwendeten Objektausdrucks sich von seinem dynamischen Typ unterscheidet. Dafür brauchen Sie tatsächlich einen Zeiger oder eine Referenz. Und das ist genau das, was Sie in diesem (*this).call() -Aufruf in B::runB() beobachten. Obwohl der statische Typ von *this B ist, lautet der dynamische Typ D und der Aufruf wird an D::call() gesendet.

    
AnT 13.08.2014 02:35
quelle
3

Der Unterschied zwischen virtuell und nicht virtuell ist:

nicht virtuell - geht immer nach dem Aufruferobjekt / Verweis / Zeigertyp.

virtual - Referenz / Zeiger - geht nach dem erstellten Objekttyp.

virtual - object - geht nach dem Aufrufer.

zum Beispiel:

%Vor%     
SHR 13.08.2014 01:38
quelle

Tags und Links