2010-06-18 8 views
26

Ich versuche, die Adresse einer virtuellen Mitgliedsfunktion zu drucken. Wenn ich weiß, welche Klasse die Funktion implementiert, kann ich schreiben:Druckadresse der virtuellen Mitgliedsfunktion

print("address: %p", &A::func); 

Aber ich will, so etwas tun:

A *b = new B(); 

printf("address: %p", &b->func); 
printf("address: %p", &b->A::func); 

Dies gilt jedoch nicht kompilieren. Ist es möglich, etwas zu tun, vielleicht die Adresse in der Vtable zur Laufzeit nachschlagen?

Antwort

1

macht nicht viel Sinn für mich. Wenn Sie eine normale Funktion haben:

void f(int n) { 
} 

dann kann man seine Adresse übernehmen:

f 

aber Sie Aufruf die Adresse einer Funktion nicht übernehmen kann, das ist, was Sie scheinen zu wollen, zu tun .

+0

@GMan Das ist, was ich dachte, sagte ich. Jedenfalls glaube ich nicht, dass das möglich ist. –

1

Von was ich in der Norm sagen kann, ist die einzige Zeit, die Sie dynamische Bindung erhalten, während einer virtuellen Funktion Anruf. Und sobald Sie eine Funktion aufgerufen haben, führen Sie die Anweisungen innerhalb der Funktion aus (d. H. Sie können nicht in der Mitte des Anrufs anhalten und erhalten die Adresse.)

Ich denke, es ist unmöglich.

+0

Ich nehme an, es ist unmöglich portabel, aber wenn man die Implementierung kennt, sollte es möglich sein, die virtuelle Tabelle eines Objekts zur Laufzeit zu überprüfen. –

6

Zeiger auf Elementfunktionen sind nicht immer einfache Speicheradressen. Sehen Sie sich die Tabelle in this article an, die die Größen der Mitgliedsfunktionszeiger auf verschiedenen Compilern zeigt - einige gehen bis zu 20 Bytes.

Wie der Artikel beschreibt, ist ein Mitgliedsfunktionszeiger tatsächlich ein Blob von implementierungsdefinierten Daten, die dabei helfen, einen Aufruf über den Zeiger aufzulösen. Sie können sie speichern und sie OK nennen, aber wenn Sie sie drucken möchten, was drucken Sie? Am besten behandeln Sie es als eine Folge von Bytes und erhalten Sie ihre Länge über sizeof.

+4

Noch bleibt das Problem: Wie identifizieren Sie die Funktion, die durch einen virtuellen Aufruf aufgerufen wird :)? –

+1

Das war nicht Teil der Frage, oder? Aber ich würde antworten "indem ich es anrufe" :) – AshleysBrain

11

Gegenwärtig gibt es keine Standardmethode in C++, obwohl die Information irgendwo verfügbar sein muss. Wie könnte das Programm sonst die Funktion aufrufen? Allerdings bietet GCC eine Erweiterung, die uns die Adresse einer virtuellen Funktion abrufen können:

void (A::*mfp)() = &A::func; 
printf("address: %p", (void*)(b->*mfp)); 

... vorausgesetzt, die Member-Funktion den Prototyp void func() hat. Dies kann sehr nützlich sein, wenn Sie die Adresse einer virtuellen Funktion zwischenspeichern oder in generiertem Code verwenden möchten. GCC warnt Sie vor diesem Konstrukt, wenn Sie -Wno-pmf-conversions nicht angeben. Es ist unwahrscheinlich, dass es mit einem anderen Compiler funktioniert.