2012-06-12 19 views
6

Ich war durch eine article von Don Clugston auf Codeproject. Es ist ein schöner Artikel und ist ziemlich berühmt. Im folgenden Code-Schnipsel, fand ich eine bestimmte Vorstellung sehr schwer zu begreifen:Funktion Pointer

class A { 
public: 
     virtual int Afunc() { return 2; }; 
}; 

class B { 
public: 
     int Bfunc() { return 3; }; 
}; 

// C is a single inheritance class, derives only from A 
class C: public A { 
public: 
    int Cfunc() { return 4; }; 
}; 

// D uses multiple inheritance 
class D: public A, public B { 
public: 
    int Dfunc() { return 5; }; 
}; 

Das Snippet durch folgenden Absatz folgt:

Angenommen, erstellen wir ein Mitglied Funktionszeiger für die Klasse C Diese Beispiel, Afunc und Cfunc sind beide Mitgliedsfunktionen von C, so dass unser Mitglied Funktionszeiger auf Afunc oder Cfunc zeigen kann. Aber Afunc benötigt einen This-Zeiger, der auf C :: A (was ich Athis nenne), zeigt, während Cfunc einen This-Zeiger benötigt, der auf C zeigt (was ich Cthis nennen werde). Compiler Writer befassen sich mit dieser Situation durch einen Trick: Sie sicherstellen, dass A zu Beginn von C physisch gespeichert ist. Dies bedeutet, dass Athis == Cthis. Wir haben nur einen, über den wir uns Sorgen machen müssen, und alles ist gut, mit der Welt.

Das einzige, was ich verstehen will, ist die Zeile in BOLD und ITALICS im obigen Absatz.

Ich verstehe nicht vollständig Afunc einen Zeiger auf C benötigt :: A während CFunc einen Zeiger auf C benötigt ganz natürlich ist.

Jede Hilfe wäre willkommen.

Antwort

9

Durch den Aufruf einer Elementfunktion in C++ wird intern die Instanz als verborgenes erstes Argument übergeben (Beachten Sie jedoch, dass dieses Verhalten implizit von der Implementierung definiert ist. Der C++ - Standard hat zu diesem Thema nichts zu sagen , es ist nur eine sehr verbreitete Art und Weise ihrer Durchführung):

x.f(y); // is treated internally as: 
f(&x, y); 

das erste Argument dann über den this Zeiger zur Verfügung steht.

nun Afunc in dem obigen Beispiel intern hat die Signatur void Afunc(A* const this) während CFuncvoid CFunc(C* const this) die interne Signatur hat.

Beachten Sie, dass die Argumenttypen in beiden Fällen unterschiedlich sind. Wenn Sie also die Funktionen für dasselbe Objekt aufrufen, muss ein anderer Zeiger übergeben werden. C++ löst dies, indem es eine implizite Konvertierung von jedem abgeleiteten Objekt in sein Basisobjekt definiert. Das heißt, in dem folgenden Code:

C* pc = something; 
pc->Afunc(); 

Dieser Code wird intern ähnlich der folgenden (Pseudocode) behandelt:

C* pc = something; 
Afunc(static_cast<A*>(pc)); 

Diese gegossen wird, für Einzelvererbung, No-operation (dh es kann einfach entfernt werden) durch den Trick im Zitat erwähnt: das Objekt C und seine Eltern A Objekt sind unter der gleichen physikalischen Adresse gespeichert.Ein Objekt des Typs C die an einer Adresse x im Speicher gespeichert ist, physikalisch in der Weise angelegt, der sein übergeordnetes Objekt des Typs A ist auch an der Adresse gespeichert x, und wird von allen anderen Mitgliedern gefolgt dass C aufweisen (aber in Ihrem Fall hat es keine Mitglieder und sizeof(C) == sizeof(A)).

+0

Könnten Sie bitte den letzten Satz umformulieren? – msiyer

+0

@msiyer Ich habe versucht, weitere Informationen hinzuzufügen, hoffentlich ist dies ein bisschen klarer. –

+0

Das ist eine großartige Erklärung. Ich bin Diplom-Ingenieur und habe daher keine CS-Kurse belegt. Ich mache es jetzt alleine. Lernen Sie alles, was erforderlich ist, um im Compiler-Design und -Konstruieren fundiert zu sein. Mit Antworten wie diesen mag man die formale Bildung von CS nicht wirklich vermissen. Danke Konrad. – msiyer