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_assertpowiedzie się. Natomiast zmiana albo dziedziczenia Fooalbo Barzamiast Base2spowoduje 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 Barjest typ i foojest zmienną składową tego typu. Nie rozumiem, dlaczego klasa podstawowa ma Barznaczenie dla klasy podstawowej typu foolub odwrotnie.
Rzeczywiście, w razie czego oczekiwałbym, że &foojest taki sam jak adres Barinstancji, która go zawiera - tak jak jest to wymagane w innych sytuacjach (1) . W końcu nie robię nic szczególnego z virtualdziedziczeniem, niezależnie od tego, klasy podstawowe są puste, a kompilacja z Base2pokazuje, ż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 StandardLayoutTypes (chociaż Barpowyżej nie jest a StandardLayoutType).
Base *a = new Bar(); Base *b = a->foo;za==b, aleaibsą wyraźnie różne obiekty (być może z różnych metod wirtualnych nadpisania).