Оптимізація порожньої бази чудова. Однак він поставляється із наступним обмеженням:
Оптимізація порожньої бази забороняється, якщо одним із порожніх базових класів є також тип або база типу першого нестатичного члена даних, оскільки два базових суб'єкти одного типу повинні мати різні адреси в рамках представлення об'єкта найбільш похідного типу.
Щоб пояснити це обмеження, врахуйте наступний код. 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явно різні об'єкти (можливо , з різними переопределяет віртуальний метод).