Тони Парк дал ответ, довольно близкий к истине.Комитет C ++, по сути, не думал, что стоит сделать усилия, чтобы сделать союзы сильной частью C ++, подобно тому, как массивы рассматривались как устаревшие вещи, которые мы должны были унаследовать от C, но на самом деле не хотели.
У союзов есть проблемы: если мы разрешаем не-POD типы в союзах, как они создаются?Это, безусловно, можно сделать, но не обязательно безопасно, и любое рассмотрение потребует ресурсов комитета.И конечный результат будет менее чем удовлетворительным, потому что на нормальном языке действительно требуются дискриминируемые союзы, и голые союзы C никогда не могут быть возведены в дискриминационные союзы способом, совместимым с C (что я могу себе представить, во всяком случае).
Чтобы уточнить технические вопросы: поскольку вы можете обернуть объединение только POD-компонентом в структуру, не теряя ничего, нет никакого преимущества в том, чтобы объединять в качестве баз.С компонентами объединения POD-only нет проблем ни с явными конструкторами, просто назначающими один из компонентов, ни с использованием битблита (memcpy) для конструктора (или назначения), генерируемого компилятором.
Однако такие объединения не нужныне достаточно полезен, чтобы беспокоиться, за исключением того, чтобы сохранить их, поэтому существующий код C может считаться допустимым C ++.Эти объединения только для POD нарушены в C ++, потому что они не могут сохранить жизненно важный инвариант, которым они обладают в C: любой тип данных может использоваться как тип компонента.
Чтобы сделать объединения полезными, мы должны разрешить конструируемые типы в качестве членов.Это важно, поскольку недопустимо просто назначать компонент в теле конструктора, либо самого объединения, либо любой включающей структуры: например, нельзя присвоить строку неинициализированному строковому компоненту.
Отсюда следует придумать некоторые правила для инициализации компонента объединения с помощью mem-initialisers, например:
union X { string a; string b; X(string q) : a(q) {} };
Но теперь возникает вопрос: что это за правило?Обычно правило состоит в том, что вы должны инициализировать каждый член и базу класса, если вы не сделаете этого явно, конструктор по умолчанию используется для остатка, и если один тип, который не был явно инициализирован, не имеет конструктора по умолчанию, этоошибка [Исключение: конструкторы копирования, по умолчанию используется конструктор копирования члена].
Очевидно, что это правило не может работать для объединений: вместо этого должно быть правило: если объединение имеет хотя бы одного члена, не являющегося POD, вы должны явно инициализировать ровно один член в конструкторе.В этом случае не будет сгенерирован конструктор по умолчанию, конструктор копирования, оператор присваивания или деструктор, и если какой-либо из этих элементов фактически используется, они должны быть явно указаны.
Так что теперь возникает вопрос: как бы вынаписать, скажем, конструктор копирования?Конечно, это вполне возможно сделать и получить правильно, если вы спроектируете свой союз, как, скажем, спроектированы союзы событий X-Windows: с тегом дискриминанта в каждом компоненте, но вам придется использовать оператор размещения new, чтобы сделать это.и вам придется нарушить написанное выше правило, которое на первый взгляд оказалось правильным!
А как насчет конструктора по умолчанию?Если у вас нет одного из них, вы не можете объявить неинициализированную переменную.
В других случаях вы можете определить компонент извне и использовать новое размещение для внешнего управления объединением, но это не так.т конструктор копирования.Дело в том, что если у вас есть N компонентов, вам понадобится N конструкторов, а в C ++ сложилось неверное представление о том, что конструкторы используют имя класса, что оставляет вам довольно мало имен и вынуждает вас использовать фантомные типы, чтобы разрешить перегрузку, чтобы выбрать правильныйконструктор ... и вы не можете сделать это для конструктора копирования, так как его подпись фиксирована.
Хорошо, есть ли альтернативы?Возможно, да, но их не так легко придумать, и труднее убедить более 100 человек, что стоит подумать на трехдневной встрече, наполненной другими вопросами.
Жаль, что комитет не выполнил вышеизложенное правило: профсоюзы являются обязательными для выравнивания произвольных данных, а внешнее управление компонентами не так уж сложно сделать вручную, а тривиально и совершенно безопасно, когда код генерируется подходящим алгоритмом, другими словами, правило обязательно , если вы хотите использовать C ++ в качестве целевого языка компилятора и по-прежнему генерировать читаемый, переносимый код. Такие объединения с конструируемыми членами имеют много применений, но наиболее важным является представление стекового фрейма функции, содержащей вложенные блоки: каждый блок имеет локальные данные в структуре, и каждая структура является компонентом объединения, нет необходимости в каких-либо конструкторах или такой, компилятор будет просто использовать размещение нового. Объединение обеспечивает выравнивание и размер, а также свободный доступ к компонентам.
[И нет другого подходящего способа получить правильное выравнивание!]
Поэтому ответ на ваш вопрос таков: вы задаете не тот вопрос. Нет никакого преимущества в том, что союзы, использующие только POD, являются базовыми, и они, конечно, не могут быть производными классами, потому что тогда они не будут POD. Чтобы сделать их полезными, требуется некоторое время, чтобы понять, почему нужно следовать принципу, используемому повсеместно в C ++: пропущенные биты не являются ошибкой, если вы не пытаетесь их использовать.