Wir alle wissen, dass bei Verwendung einer einfachen Einzelvererbung die Adresse einer abgeleiteten Klasse mit der Adresse der Basisklasse übereinstimmt. Mehrfachvererbung macht das unwahr.
Macht die virtuelle Vererbung das auch falsch? Mit anderen Worten, ist der folgende Code korrekt:
struct A {};
struct B : virtual A
{
int i;
};
int main()
{
A* a = new B; // implicit upcast
B* b = reinterpret_cast<B*>(a); // fishy?
b->i = 0;
return 0;
}
c++
virtual-inheritance
user1610015
quelle
quelle
reinterpret_cast
mit Klassen ist immer faul (außer von Klasse zuvoid*
und zurück zur gleichen Klasse).Antworten:
Ich denke, die Behauptung ist nicht wahr. Im folgenden Code haben wir eine einfache (nicht virtuelle) einzelne (nicht mehrfache) Vererbung, aber die Adressen sind unterschiedlich.
und die Ausgabe für VS2015 ist:
Wenn Sie die Vererbung im obigen Code in virtuell ändern, ist das Ergebnis dasselbe. Selbst bei virtueller Vererbung können die Adressen von Basisobjekten und abgeleiteten Objekten unterschiedlich sein.
quelle
void main()
ist auch in modernen MSVS-Compilern akzeptabel. Übrigens, danke für den Kommentar. Ich habe den Code aktualisiert.void main()
ist nicht akzeptabel. Es mussint main()
dem Standard entsprechen. Und bitte entfernen Sie dasdynamic_cast
aus dem Code, es wird dort nicht benötigt und es verursacht Verwirrung.Das Ergebnis
reinterpret_cast<B*>(a);
wird nur Punkt zu der einschließe garantiertB
Aufgabe ,a
wenn dasa
Unterobjekt und das einschließendeB
Objekt sind zeiger interconvertible , siehe [expr.static.cast] / 3 des C ++ 17 - Standard.Das abgeleitete Klasse Objekt ist zeiger interconvertible mit dem Objekt Basisklasse nur dann , wenn das abgeleitete Objekt Standard-Layout , hat keine direkten nicht-statische Datenelemente und das Basisklassenobjekt ist seine erste Basisklasse Subobjekt. [Grundverbindung] /4.3
Wenn eine
virtual
Basisklasse vorhanden ist, wird eine Klasse vom Standardlayout ausgeschlossen . [Klasse] /7.2 .Da
B
eine virtuelle Basisklasse und ein nicht statisches Datenelement vorhanden sind,b
wird daher nicht auf das umschließendeB
Objekt verwiesen , sondernb
der Zeigerwert bleibt unveränderta
.Der Zugriff auf das
i
Mitglied, als würde es auf dasB
Objekt zeigen, hat ein undefiniertes Verhalten.Alle anderen Garantien stammen von Ihrem spezifischen ABI oder einer anderen Spezifikation.
quelle
Das ist nicht ganz richtig. Betrachten Sie dieses Beispiel:
Beim Erstellen einer Instanz
D
,B
undC
sind jeweils mit ihren jeweiligen Instanz instanziiertA
. Es wäre jedoch kein Problem, wenn die Instanz vonD
dieselbe Adresse wie ihre InstanzB
und ihre jeweilige Instanz von hätteA
. Obwohl dies nicht erforderlich ist, geschieht genau dies beim Kompilieren mitclang 11
undgcc 10
:Betrachten wir eine modifizierte Version des obigen Beispiels:
Die Verwendung des
virtual
Funktionsbezeichners wird normalerweise verwendet, um mehrdeutige Funktionsaufrufe zu vermeiden. Daher müssen bei Verwendung dervirtual
Vererbung sowohlB
als auchC
Instanzen eine gemeinsameA
Instanz erstellen . Beim Instanziieren erhaltenD
wir folgende Adressen:Es gibt hier keinen Grund zu verwenden
reinterpret_cast
, noch mehr, es führt zu undefiniertem Verhalten. Verwenden Siestatic_cast
stattdessen:Beide Darsteller verhalten sich in diesem Beispiel unterschiedlich. Der
reinterpret_cast
wirdpB
als Zeiger auf neu interpretiertA
, aber der ZeigerpA
kann auf eine andere Adresse zeigen, wie im obigen Beispiel (C vs A). Der Zeiger wird bei Verwendung korrekt hochgesendetstatic_cast
.quelle
Der Grund
a
undb
die Unterschiede in Ihrem Fall sind, dass, daA
keine virtuelle Methode vorhandenA
ist, a nicht verwaltet wirdvtable
. Auf der anderen SeiteB
wird a beibehaltenvtable
.Wenn Sie upcast zu
A
, ist der Compiler intelligent genug , um das überspringenvtable
für gemeintB
. Und damit der Unterschied in den Adressen. Sie sollten nichtreinterpret_cast
zurückkehrenB
, es würde nicht funktionieren.Versuchen Sie, eine
virtual
Methode hinzuzufügen , z . B.virtual void foo() {}
in, um meinen Anspruch zu überprüfenclass A
. JetztA
wird auch ein beibehaltenvtable
. Downcast (reinterpret_cast
) nach B gibt Ihnen also das Original zurückb
.quelle
Subclass address equal to virtual base class address?
hat alles mit virtueller Vererbung zu tun. Und virtuelle Vererbung hat alles mit vtables zu tun.A
sicherstellen wird, dass die Adressen übereinstimmen und die Besetzung entweder in der Theorie oder in der Praxis funktioniert. Ich kann meine Downvote nicht ohne eine Post-Bearbeitung entfernen, da sie gesperrt ist.