2015-05-13 17 views
5

In der Theorie hat C++ keine binäre Schnittstelle und die Reihenfolge der Methoden in der vtable ist undefiniert. Ändern Sie alles über die Definition einer Klasse und Sie müssen jede Klasse neu kompilieren, die davon abhängt, in jeder DLL usw.Wie werden C++ - vtable-Methoden angeordnet? * In der Praxis *

Aber was ich gerne wissen würde ist, wie die Compiler in der Praxis arbeiten. Ich würde hoffen, dass sie nur die Reihenfolge verwenden, in der die Methoden in der Kopfzeile/Klasse definiert sind, was zusätzliche Methoden sicher machen würde. Aber sie könnten auch einen Hash der verstümmelten Namen verwenden, um sie unabhängig von der Reihenfolge zu machen, aber auch dann komplett nicht aktualisierbar.

Wenn die Leute spezifische Kenntnisse darüber haben, wie bestimmte Versionen spezifischer Compiler in verschiedenen Betriebssystemen usw. funktionieren, wäre dies am hilfreichsten.

Hinzugefügt: Idealerweise würden Linker-Symbole für die Offsets der virtuellen Methoden erstellt, so dass die Offsets niemals in aufrufende Funktionen kompiliert würden. Aber mein Verständnis ist, dass das nie gemacht wird. Richtig?

+0

Ich würde überprüfen müssen, um sicherzustellen, dass ich ziemlich sicher bin, dass sie in der Reihenfolge sind, die Sie ihnen erklären. Wenn Sie eine Unterklasse ableiten und weitere virtuelle Funktionen hinzufügen, kommen sie sicher nach der Basisklasse. – tukra

+0

tukra

+0

Nicht nur die Reihenfolge der Methoden in der vtable, sondern auch das Vorhandensein der vtable ist ein Implementierungsdetail. Der Standard spezifiziert nur die virtuellen Funktionen und nicht ihre Implementierung :-) –

Antwort

2

In MSVC 2010 sind sie in der Reihenfolge, in der Sie sie deklarieren. Ich kann mir keine Begründung für einen anderen Compiler vorstellen, der es anders macht, obwohl es eine willkürliche Wahl ist. Es muss nur konsistent sein. Sie sind nur Arrays von Zeigern, also mach dir keine Sorgen über Hashes oder Mangling.

Unabhängig von der Reihenfolge müssen zusätzliche virtuelle Funktionen in abgeleiteten Klassen hinzugefügt werden, nachdem diejenigen in der Basis oder polymorphe Umwandlungen nicht funktionieren.

+0

MSVC hat keine große Auswahl, da sein vtable-Layout mit der COM-Konvention übereinstimmen muss. – MSalters

1

Soweit ich weiß, sind sie immer in der Reihenfolge der Deklarationen. Auf diese Weise können Sie immer Deklarationen neuer virtueller Methoden am Ende hinzufügen (oder unter allen vorherigen Deklaration von virtuellen Methoden). Wenn Sie eine virtuelle Methode entfernen oder irgendwo in der Mitte eine neue hinzufügen, müssen Sie alles neu kompilieren und neu verknüpfen. Ich weiß das sicher - ich habe diesen Fehler bereits gemacht. Aus meiner Erfahrung gelten diese Regeln sowohl für MSVC als auch für GCC.

0

Jeder Compiler muss mindestens alle brauchbaren Einträge für eine bestimmte Klasse zusammen mit denen für abgeleitete Klassen, die entweder vor oder nachher kommen, zusammenstellen.

Der einfachste Weg, dies zu erreichen, ist die Verwendung der Header-Reihenfolge. Es ist schwer zu verstehen, warum jeder Compiler etwas anderes machen würde, da es mehr Code, mehr Tests usw. benötigt und nur einen anderen Weg für Fehler bietet. Kein erkennbarer Vorteil, den ich sehen kann.

+0

Nun, wenn die Reihenfolge der Methoden in verschiedenen Headern für die gleiche Klasse unterschiedlich wäre, dann würde die Verwendung eines Hashes eines mangelnden Namens das beheben. Die Reihenfolge, in der die Methoden angezeigt werden, sollte nach dem Standard (ich denke) nicht relevant sein. Nicht, dass ich denke, das ist eine gute Idee, aber es ist ein Grund für die Verwendung einer anderen Reihenfolge. – Tuntable

+1

'wenn die Reihenfolge der Methoden in verschiedenen Headern für dieselbe Klasse unterschiedlich war' Dies verstößt gegen die eine Definitionsregel. Das Ergebnis ist undefiniertes Verhalten! – Klaus

2

Es scheint, dass von Microsoft die VTable neu geordnet werden kann.

Im Folgenden wird kopiert von https://marc.info/?l=kde-core-devel&m=139744177410091&w=2

I (Nicolas Alvarez) kann dieses Verhalten geschieht bestätigen.

I zusammengestellt diese Klasse:

struct Testobj { 
    virtual void func1(); 
    virtual void func2(); 
    virtual void func3(); 
}; 

Und ein Programm, das func1() aufruft; func2(); func3();

Dann habe ich eine func2 (int) Überlastung des Ende:

struct Testobj { 
    virtual void func1(); 
    virtual void func2(); 
    virtual void func3(); 
    virtual void func2(int); 
}; 

und die Klasse neu kompiliert, aber nicht das Programm die Klasse.

Ausgabe des Aufrufs func1(); func2(); func3();

war
This is func1 
This is func2 taking int 
This is func2 

Dies zeigt, dass, wenn ich func1() func2() func3() func2 (int) erklären, die VTable als func1 angelegt wird() func2 (int) func2() func3().

Getestet mit MSVC2010.

+0

Ich traf das gleiche Problem. Hast du eine Idee? – ldlchina