Если у меня есть эти объекты:
struct A
{
int aa{};
A() {};
~A()
{
OutputDebugStringA("~A\n");
}
};
struct B : public A
{
B() {};
~B()
{
OutputDebugStringA("~B\n");
}
};
Я могу агрегировать инициализацию std::array
из A
или B
без копирования:
std::array<A, 1> arr0{ A{} };
std::array<B, 1> arr1{ B{} };
НО если я попытаюсь создать std::array
базового класса и инициализировать его производным классом:
std::array<A, 1> arr0{ B{} };
Однако он работает без ошибок, копирование происходит при вызове деструкторов. Итак, мой вопрос: почему? И есть ли разумный способ структурировать его, чтобы избежать копирования?
Причина, по которой я спрашиваю, заключается в том, что у меня есть базовый объект, содержащий данные, и большое количество производных объектов, которые наследуют только данные от базы, но по-разному манипулируют ими в своем конструкторе.
Программа работает без ошибок. Мне просто не нравится трата уничтоженных объектов. Я предполагаю, что это невозможно при агрегатной инициализации. В этом случае я могу либо игнорировать потери (жизнеспособный вариант), либо структурировать их по-другому, что также сделает их немного более многословными.
Все объекты, размер и типы известны во время компиляции.
«но манипулировать им по-другому в своем конструкторе». Это слабая причина для определения производного класса, и, настаивая на использовании этого подхода (X), вы исключаете потенциальные решения вашей исходной проблемы (Y).
Также известна как Проблема XY
@JaMiT На самом деле я не «настаиваю» на этом. У меня просто появилось узкое видение попыток сделать это с помощью наследования, и мне нужно было сделать шаг назад и увидеть более широкую картину: есть и другие способы достижения желаемого результата.
@RemyLebeau, нажав на эту ссылку, понял, что это именно та ошибка, которую я совершил! Виноват!
@poby «На самом деле я не настаиваю на этом». -- Я допускаю, что моя формулировка несколько преувеличена, но все же верно, что вопрос устанавливает наследование как данность, что ограничивает направление ответов. Имейте это в виду, но не беспокойтесь об этом слишком сильно — туннельное зрение в какой-то момент затрагивает большинство людей.
Однако он работает без ошибок, копирование происходит при вызове деструкторов. Итак, мой вопрос: почему?
Ваш массив содержит реальные экземпляры A
. Вы не можете сохранить объект B
в экземпляре A
. Компилятор разрежет объект B и скопирует только часть A
объекта в экземпляр A
. Итак, в вашем примере объект B
является временным и уничтожается после копирования его базы A
в массив.
И есть ли разумный способ структурировать его, чтобы избежать копирования?
Нет. Если вам нужен массив A
для хранения B
объектов, вместо этого вам придется использовать указатели A*
, например:
std::array<B, 1> arr0{ B{} };
std::array<A*, 1> arr1{ &arr0[0] };
Или:
std::array<std::unique_ptr<A>, 1> arr0{ std::make_unique<B>() };
Да, я понимаю. Но я хочу иметь производные объекты с конструкторами, которые манипулируют данными базового объекта по-своему. Вот почему B не содержит фактических данных. У A есть все необходимые мне данные для производного объекта. Если я попытаюсь поместить B в A, ошибок не возникнет, так что это, по крайней мере, разрешено, и это действительно работает. Меня просто раздражает, что вызываются деструкторы, а это расточительно.
Если ваш B
только «[манипулирует] данными базового объекта собственными способами», это звучит так, как будто вам лучше использовать функции компоновщика, чем наследование.
Спасибо @StephenNewell! Ваш ответ дал мне нужную подсказку.
Вы не можете поместить объект
B
в массивA
.