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_assert
irá falhar. Considerando que, alterar Foo
ou Bar
herdar em vez disso Base2
evitará 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 Bar
importa para a classe base do tipo de foo
, ou vice-versa.
De fato, eu espero que &foo
seja o mesmo que o endereço da Bar
instância que o contém - como é necessário em outras situações (1) . Afinal, eu não estou fazendo nada sofisticado com virtual
herança, as classes base estão vazias de qualquer maneira, e a compilação Base2
mostra 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 StandardLayoutType
s (embora Bar
, acima, não seja a StandardLayoutType
).
Base *a = new Bar(); Base *b = a->foo;
coma==b
, masa
eb
claramente objetos diferentes (talvez com substituições de métodos virtuais diferentes).