Оптимизация пустой базы - это здорово. Тем не менее, он имеет следующие ограничения:
Оптимизация пустой базы запрещена, если один из пустых базовых классов также является типом или базой типа первого не статического члена данных, поскольку два базовых подобъекта одного типа должны иметь разные адреса в представлении объекта. самого производного типа.
Чтобы объяснить это ограничение, рассмотрим следующий код. Не static_assertудастся. Принимая во внимание, что изменение Fooили Barнаследования вместо Base2этого предотвратит ошибку:
#include <cstddef>
struct Base {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");
Я полностью понимаю это поведение. Чего я не понимаю, так это того, почему существует такое поведение . Это было очевидно добавлено по причине, так как это явное дополнение, а не недосмотр. Что является обоснованием для этого?
В частности, почему два базовых подобъекта должны иметь разные адреса? Выше, Barявляется типом и fooявляется переменной-членом этого типа. Я не понимаю, почему базовый класс имеет Barзначение для базового класса типа fooили наоборот.
Действительно, я, если что-нибудь, я ожидал бы, что &fooэто то же самое, что и адрес Barэкземпляра, содержащего его, - как это требуется в других ситуациях (1) . В конце концов, я не делаю ничего сложного с virtualнаследованием, базовые классы пусты независимо, и компиляция с Base2показывает, что в этом конкретном случае ничего не ломается.
Но ясно, что это рассуждение как-то неверно, и есть другие ситуации, когда это ограничение будет необходимо.
Допустим, ответы должны быть для C ++ 11 или новее (в настоящее время я использую C ++ 17).
(1) Примечание: EBO был обновлен в C ++ 11 и, в частности, стал обязательным для StandardLayoutTypes (хотя Bar, выше, это не a StandardLayoutType).
Base *a = new Bar(); Base *b = a->foo;сa==b, ноaиbявно разные объекты (возможно , с разными переопределяет виртуальный метод).