Optymalizacja pustej bazy jest świetna. Obejmuje jednak następujące ograniczenie:
Optymalizacja pustej bazy jest zabroniona, jeśli jedna z pustych klas bazowych jest również typem lub bazą typu pierwszego niestatycznego elementu danych, ponieważ dwa podstawowe podobiekty tego samego typu muszą mieć różne adresy w reprezentacji obiektu najbardziej pochodnego typu.
Aby wyjaśnić to ograniczenie, rozważ następujący kod. Nie static_assert
powiedzie się. Natomiast zmiana albo dziedziczenia Foo
albo Bar
zamiast Base2
spowoduje uniknięcie błędu:
#include <cstddef>
struct Base {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");
Rozumiem to zachowanie całkowicie. Co ja nie rozumiem, dlaczego ta konkretna zachowanie istnieje . Został oczywiście dodany z jakiegoś powodu, ponieważ jest to wyraźny dodatek, a nie przeoczenie. Jakie jest tego uzasadnienie?
W szczególności, dlaczego dwa podstawowe podobiekty powinny mieć różne adresy? Powyżej Bar
jest typ i foo
jest zmienną składową tego typu. Nie rozumiem, dlaczego klasa podstawowa ma Bar
znaczenie dla klasy podstawowej typu foo
lub odwrotnie.
Rzeczywiście, w razie czego oczekiwałbym, że &foo
jest taki sam jak adres Bar
instancji, która go zawiera - tak jak jest to wymagane w innych sytuacjach (1) . W końcu nie robię nic szczególnego z virtual
dziedziczeniem, niezależnie od tego, klasy podstawowe są puste, a kompilacja z Base2
pokazuje, że w tym konkretnym przypadku nic się nie psuje.
Ale wyraźnie to rozumowanie jest w jakiś sposób niepoprawne i istnieją inne sytuacje, w których ograniczenie to byłoby wymagane.
Powiedzmy, że odpowiedzi powinny dotyczyć C ++ 11 lub nowszej (obecnie używam C ++ 17).
(1) Uwaga: EBO został zaktualizowany w C ++ 11, a w szczególności stał się obowiązkowy dla StandardLayoutType
s (chociaż Bar
powyżej nie jest a StandardLayoutType
).
Base *a = new Bar(); Base *b = a->foo;
za==b
, alea
ib
są wyraźnie różne obiekty (być może z różnych metod wirtualnych nadpisania).