Wie funktioniert die C++ - compiler wissen, welche Implementierung einer virtuellen Funktion aufrufen?
Hier ist ein Beispiel des Polymorphismus von http://www.cplusplus.com/doc/tutorial/polymorphism.html (zur besseren Lesbarkeit umgebrochen):
//abstract base class
#include <iostream>
using namespace std;
class Polygon {
protected:
int width;
int height;
public:
void set_values(int a, int b) { width = a; height = b; }
virtual int area(void) =0;
};
class Rectangle: public Polygon {
public:
int area(void) { return width * height; }
};
class Triangle: public Polygon {
public:
int area(void) { return width * height / 2; }
};
int main () {
Rectangle rect;
Triangle trgl;
Polygon * ppoly1 = ▭
Polygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << endl; //outputs 20
cout << ppoly2->area() << endl; //outputs 10
return 0;
}
Meine Frage ist, wie der compiler wissen, dass ppoly1 ist ein Rechteck, und dass ppoly2 ist ein Dreieck, so dass Sie es nennen können, die richtige area () - Funktion? Könnte es herausfinden, indem man die "Polygon * ppoly1 =
" zu haben und zu wissen, dass ein Rechteck ist ein Rechteck, aber nicht in allen Fällen funktionieren, oder? Was ist, wenn Sie so etwas Tat?
cout << ((Polygon *)0x12345678)->area() << endl;
Davon aus, dass Sie erlaubt, dass der Zugang zufälligen Speicherbereich.
Ich würde das ausprobieren, aber ich kann nicht auf dem computer ich bin mir im moment.
(Ich hoffe, ich bin nicht etwas fehlt offensichtlich...)
- Offtopic: Warum nicht abstimmen, bis die anderen Menschen, die verbrachte Zeit mit dem schreiben hilfreiche Antworten für Sie?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Jedes Objekt (gehört zu einer Klasse mit mindestens einer virtuellen Funktion) hat einen Zeiger, genannt
vptr
. Es weist auf dievtbl
seiner eigentlichen Klasse (die jede Klasse mit virtuellen Funktionen hat mindestens ein, möglicherweise mehr als eine für einige multiple-inheritance-Szenarien).Den
vtbl
enthält eine Reihe von Zeigern, eine für jede virtuelle Funktion. Also zur Laufzeit den code benutzt nur die Objektvptr
zu suchen, dievtbl
, und von dort aus die Adresse der aktuellen Funktion überschrieben.In Ihrem speziellen Fall
Polygon
,Rectangle
, undTriangle
jeder hat einevtbl
mit je einem Eintrag auf seiner relevantenarea
Methode. Ihreppoly1
habenvptr
Hinweis aufRectangle
'svtbl
, undppoly2
ähnlich ist es mitTriangle
'svtbl
. Hoffe, das hilft!Chris Jester-Junge gibt die grundsätzliche Antwort auf diese Frage.
Wikipedia hat eine mehr in die Tiefe der Behandlung.
Wenn Sie wissen wollen, die vollständigen details, wie diese Art der Sache funktioniert (und für alle Art von Vererbung, einschließlich multiple und virtuelle Vererbung), eine der besten Ressourcen ist Stan Lippman ' s "In der C++ - Objekt-Modell".
Missachtung Aspekte der Bindung, es ist eigentlich nicht der compiler, der dies feststellt.
Ist es die C++ - runtime, die wertet, über vtables und vpointers, was das abgeleitete Objekt tatsächlich zur Laufzeit.
Empfehle ich Scott Meyers Buch effective C++ für gute Beschreibungen, wie das gemacht wird.
Sogar deckt, wie default-Parameter in einer Methode in einer abgeleiteten Klasse werden ignoriert und alle Standard-Parameter in einer Basis-Klasse werden noch genommen! Das ist verbindlich.
Beantworten, den zweiten Teil Ihrer Frage: diese Adresse wird wahrscheinlich nicht haben einen v-Tabelle an der richtigen Stelle, und der Wahnsinn, die wird Folgen. Auch, es ist undefiniert, nach dem standard.
Dieser code ist eine Katastrophe warten, um zu geschehen. Der compiler kompiliert es allen Recht, aber wenn es um die Laufzeit, wirst du nicht gerichtet sein, um eine gültige v-Tabelle und wenn Sie Glück haben, wird das Programm einfach Abstürzen.
In C++, sollten Sie nicht verwenden die alten C-style casts wie dieser, sollten Sie dynamic_cast etwa so:
dynamic_cast den Wert NULL zurück, wenn die übergebene Zeiger ist nicht ein gültiges Polygon-Objekt, so wird es gefangen werden, indem die ASSERT.
Virtual function tables. Zu Witz, sowohl von Ihrer Polygon-abgeleiteten Objekte verfügen über eine virtual-function-Tabelle, die enthält Funktionszeiger auf die Implementierungen aller Ihrer (nicht-statische) Funktionen; und wenn Sie instanziieren ein Dreieck, das virtuelle Funktion Zeiger für die area () - Funktion auf das Dreieck::area () - Funktion; beim instanziieren eines Rechtecks, der Fläche () - Funktion Punkte zum Rechteck::area () - Funktion. Da virtual function Pointer gespeichert sind, werden zusammen mit den Daten für ein Objekt im Speicher, jedes mal, wenn Sie das Objekt als Polygon, den entsprechenden Bereich() für das Objekt verwendet wird.