A otimização da base vazia é ótima. No entanto, ele vem com a seguinte restrição:
A otimização de base vazia é proibida se uma das classes de base vazias também for o tipo ou a base do tipo do primeiro membro de dados não estático, pois os dois subobjetos de base do mesmo tipo precisam ter endereços diferentes na representação do objeto do tipo mais derivado.
Para explicar essa restrição, considere o seguinte código. O static_assertirá falhar. Considerando que, alterar Fooou Barherdar em vez disso Base2evitará o erro:
#include <cstddef>
struct Base {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");
Eu entendo esse comportamento completamente. O que não entendo é por que esse comportamento específico existe . Obviamente, foi adicionado por um motivo, pois é uma adição explícita, não uma supervisão. Qual é a justificativa para isso?
Em particular, por que os dois subobjetos de base devem ter endereços diferentes? No acima, Baré um tipo e fooé uma variável de membro desse tipo. Não vejo por que a classe base Barimporta para a classe base do tipo de foo, ou vice-versa.
De fato, eu espero que &fooseja o mesmo que o endereço da Barinstância que o contém - como é necessário em outras situações (1) . Afinal, eu não estou fazendo nada sofisticado com virtualherança, as classes base estão vazias de qualquer maneira, e a compilação Base2mostra que nada quebra nesse caso específico.
Mas claramente esse raciocínio está incorreto de alguma maneira, e há outras situações em que essa limitação seria necessária.
Digamos que as respostas devam ser para o C ++ 11 ou mais recente (atualmente estou usando o C ++ 17).
(1) Nota: O EBO foi atualizado no C ++ 11 e, em particular, tornou-se obrigatório para StandardLayoutTypes (embora Bar, acima, não seja a StandardLayoutType).
Base *a = new Bar(); Base *b = a->foo;coma==b, masaebclaramente objetos diferentes (talvez com substituições de métodos virtuais diferentes).