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