Die Optimierung der leeren Basis ist großartig. Es gibt jedoch die folgende Einschränkung:
Eine leere Basisoptimierung ist verboten, wenn eine der leeren Basisklassen auch der Typ oder die Basis des Typs des ersten nicht statischen Datenelements ist, da die beiden Basisunterobjekte desselben Typs unterschiedliche Adressen innerhalb der Objektdarstellung haben müssen vom am meisten abgeleiteten Typ.
Beachten Sie den folgenden Code, um diese Einschränkung zu erklären. Das static_assertwird scheitern. Wenn Sie entweder Foooder ändern, Barum stattdessen zu erben, Base2wird der Fehler abgewendet:
#include <cstddef>
struct Base {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");
Ich verstehe dieses Verhalten vollständig. Was ich nicht verstehe, ist, warum dieses besondere Verhalten existiert . Es wurde offensichtlich aus einem Grund hinzugefügt, da es sich um eine explizite Ergänzung handelt, nicht um ein Versehen. Was ist ein Grund dafür?
Insbesondere, warum sollten die beiden Basis-Unterobjekte unterschiedliche Adressen haben müssen? Oben Barist ein Typ und fooeine Mitgliedsvariable dieses Typs. Ich verstehe nicht, warum die Basisklasse von Bedeutung Barfür die Basisklasse des Typs fooist oder umgekehrt.
In der Tat würde ich, wenn überhaupt, erwarten, dass &foodies mit der Adresse der BarInstanz übereinstimmt, die es enthält - wie es in anderen Situationen erforderlich ist (1) . Schließlich mache ich nichts Besonderes mit virtualVererbung, die Basisklassen sind trotzdem leer, und die Kompilierung mit Base2zeigt, dass in diesem speziellen Fall nichts kaputt geht.
Aber diese Argumentation ist eindeutig falsch, und es gibt andere Situationen, in denen diese Einschränkung erforderlich wäre.
Angenommen, die Antworten sollten für C ++ 11 oder neuer sein (ich verwende derzeit C ++ 17).
(1) Hinweis: EBO wurde in C ++ 11 aktualisiert und wurde insbesondere für StandardLayoutTypes obligatorisch (obwohl Baroben nicht a StandardLayoutType).
Base *a = new Bar(); Base *b = a->foo;mita==b, aberaundbsind eindeutig unterschiedliche Objekte (möglicherweise mit unterschiedlichen Überschreibungen virtueller Methoden).