Вопрос

Стандарт определяет, что профсоюзы не могут быть использованы в качестве базового класса, но есть ли конкретные рассуждения для этого? Насколько я понимаю, профсоюзы могут иметь конструкторы, деструкторы, также переменные элементов и методы для работы на этих варибалях. Короче профсоюз может инкапсулировать тип данных и состояния, который может быть доступен через функции участника. Таким образом, он в большинстве распространенных терминов квалифицируется для того, чтобы быть классом, и если он может выступать в качестве класса, то почему он ограничен выступлением в качестве базового класса?

Редактировать: Хотя ответы пытаются объяснить рассуждение, которые я до сих пор не понимаю, как союз, как проводный класс, хуже, чем когда в союзе как просто класс. Так что в надежде получить больше конкретного ответа и рассуждения, я подтолкнусь этим для получения щедрости. Никаких преступлений к уже опубликованным ответам, спасибо за них!

Это было полезно?

Решение

Тони Парк дал ответ, который довольно близко к истине. Комитет C ++ в основном не думал, что целесообразно сделать усилия, чтобы союзы сильной частью C ++, аналогично лечению массивов, как наследие, мы должны были наследовать от C, но не хотелось.

У профсоюзов возникают проблемы: если мы разрешим без струпу в профсоюзах, как они построены? Это, безусловно, может быть сделано, но не обязательно безопасно, и любое внимание потребует ресурсов комитета. И окончательный результат будет меньше, чем удовлетворительным, потому что то, что действительно требуется на здравом языке, является дискриминированные профсоюзы, и профсоюзы Bare C не могут быть повышены для дискриминационных союзов в способе, совместимы с C (что я могу вообще представить, в любом случае).

Чтобы уточнить технические вопросы: поскольку вы можете обернуть POD-компонент только союз в структуре, не теряя ничего, нет никаких преимуществ, позволяющих объединять союзы. С компонентами профсоюза только на POD нет проблем с явными конструкциями, просто присваивая одному из компонентов, ни с использованием битблита (MEMCPY) для созданного компилятора Copy Contrustor (или назначения).

Такие союзы, однако, не достаточно полезны, чтобы беспокоить, за исключением того, чтобы сохранить их, настолько существующий C-код, можно считать действительным C ++. Эти только профсоюзы только на POD разбиты в C ++, потому что они не сохраняют жизненно важный инвариант, который они обладают в C: любой тип данных может использоваться в качестве типа компонента.

Сделать профсоюзы полезными, мы должны разрешить построен типы как участники. Это значимо, потому что это не приемлемо просто назначать компонент в корпусе конструктора, любой из сама профсоюза, либо любые прилагаемые структуры: вы не можете, например, назначить строку в неинициализированную строку компонента.

Следует использовать некоторые правила для инициализации Union Component с MEM-инициаторами, например:

union X { string a; string b; X(string q) : a(q) {} };

Но сейчас вопрос в том, каковы правило? Обычно правило - это вы должны инициализировать каждый член и база класса, если вы не будете делать это явно, конструктор по умолчанию используется для остатка, и если один тип которого не явно инициализирован, не имеет конструктора по умолчанию, это Ошибка [Исключение: Copy Constructors, по умолчанию - это конструктор копирования элементов].

Очевидно, что это правило не может работать на профсоюзах: вместо этого правило: если у Союза есть как минимум один член Non-Pod, вы должны явно инициализировать ровно один член в конструкторе. В этом случае не будет генерироваться конструктор по умолчанию, конструктор копирования, оператор назначения или деструктор, и если какой-либо из этих элементов на самом деле используются, они должны быть явно поставлены.

Так что теперь вопрос становится: как бы вы написали, скажем, скопируйте конструктор? Это, конечно, вполне возможно делать и получить правильно, если вы проектируете свой союз так, скажем, профсоюзы событий X-Windows разработаны: с дискриминантом в каждом компонент, но вам придется использовать оператор размещения, чтобы сделать это , и вам придется перерыв Правило, которое я написал выше, который появился на первый взгляд, чтобы быть правильным!

Как насчет конструктора по умолчанию? Если у вас нет одного из них, вы не можете объявить неинициализированную переменную.

Есть и другие случаи, когда вы можете определить компонент снаружи и использовать размещение нового для управления союзом извне, но это не конструктор копирования. Дело в том, что если у вас есть n компоненты, которые вам нужны конструкторы, и C ++ имеет разбитое представление о том, что конструкторы используют имя класса, которое оставляет вас довольно короткие имена и заставляет вас использовать типы фантомки, чтобы разрешить перегрузку, чтобы выбрать правильный Конструктор. И вы не можете сделать это для конструктора копирования, поскольку его подпись фиксирована.

Хорошо, так есть ли альтернативы? Возможно, да, но они не так легко сновидеть и труднее убедить более чем на 100 человек, что стоит думать о трехдневной встрече, забившими с другими проблемами.

Жаль, что Комитет не реализовал правило выше: профсоюзы являются обязательными для согласования произвольных данных, а внешнее управление компонентами на самом деле не так сложно делать вручную и тривиально и полностью безопасным, когда код генерируется подходящим алгоритмом, Другими словами, правило обязательный Если вы хотите использовать C ++ в качестве целевого языка компилятора и все еще генерируют читаемый, портативный код. Такие союзы с конструируемыми членами имеют много применений, но наиболее важным является представьте кадр стека функции, содержащей вложенные блоки: каждый блок имеет локальные данные в структуре, и каждый структуру представляет собой компонент Union, нет необходимости для каких-либо конструкторов. Или такой компилятор просто будет использовать размещение нового. Союз обеспечивает выравнивание и размер, а также освобождает бесплатный компонентный доступ. [И нет другого соответствия, чтобы получить правильное выравнивание!

Поэтому ответ на ваш вопрос: вы задаете неправильный вопрос. Нет никаких преимуществ для профсоюзов только для POD, и они, безусловно, не могут быть получены классы, потому что тогда они не будут стручкой. Чтобы они были полезными, необходимо понять, почему нужно следовать принципу, используемым везде в C ++: отсутствующие биты не ошибка, если вы не пытаетесь их использовать.

Другие советы

Союз - это тип, который можно использовать как любой из его членов В зависимости от того, какой член был установлен - только этот член может быть позже прочитан.

Когда вы вытекаете из типа, полученный тип наследует базовый тип - полученный тип можно использовать везде, где может быть базовый тип. Если вы можете получить из профсоюза, полученный класс может быть использован (не касается неявно, но явно с именем члена) везде, где может быть использован какой-либо из членов профсоюза, но среди этих членов только один член может быть на законном документе. Проблема в том, что данные, на которых был установлен член, не хранится в Союзе.

Чтобы избежать этого тонкого, но опасное противоречие, что на самом деле подрывает систему типа, вытекающей из союза, не допускается.

Bjarne Strourstrup сказал: «Там кажется мало причин для этого» в аннотированном справочном руководстве C ++.

Название спрашивает, почему профсоюзы не могут быть базовым классом, но вопрос, по-видимому, о профсоюзах как полученный класс. Итак, что это?

Нет технической причины, почему союзы не могут быть базовым классом; Это просто не разрешено. Разумная интерпретация будет думать о профсоюзе как структуре, члены которого случаются потенциально перекрываются в память, и считают, что полученный класс в качестве класса наследует от этой (довольно нечетной) структуры. Если вам нужна эта функциональность, вы обычно можете убедить большинство компиляторов принимать анонимный союз в качестве члена структуры. Вот пример, который подходит для использования в качестве базового класса. (И есть анонимная структура в Союзе для хорошей меры.)

struct V3 {
    union {
        struct {
            float x,y,z;
        };
        float f[3];
    };
};

Обоснование профсоюзов как полученный класс, вероятно, проще: результат не будет союзом. Союзы должны были бы быть союзом всех своих членов, и все их основы. Это достаточно справедливо, и может открыть некоторые интересные возможности шаблона, но у вас будет ряд ограничений (все основания и члены должны быть подготовлены, и вы сможете унаследовать дважды, потому что полученный тип по своей природе не наследует -Под?), Этот тип наследства будет отличаться от другого типа языковых видов спорта (OK, не то, что это остановило C ++ раньше), и это в любом случае его избыток - в любом случае - существующая функциональность профсоюза.

Stroustrup говорит это в книге D & E:

Как с void *, Программисты должны знать, что профсоюзы ... по своей природе опасно, следует избегать везде, где это возможно, и следует обращаться с особой осторожностью, когда на самом деле необходимо.

(Отзыв не изменяет смысл.)

Поэтому я представляю, что решение является произвольным, и он просто не видел причин изменить функциональность профсоюза (он работает нормально, как есть с подмножеством C C ++), и поэтому не оказали никакой интеграции с новыми функциями C ++. И когда ветер менял, он застрял так.

Я думаю, что вы получили ответ сами в своих комментариях ответа EJP.

Я думаю, что союзы включены только в C ++ только для того, чтобы быть обратно совместимыми с C. Я предполагаю, что профсоюзы казались хорошими идеями в 1970 году, на системах с крошечными пространствами памяти. К тому времени, когда C ++ пришел вдоль я представляю, что профсоюзы уже выглядели менее полезными.

Учитывая, что профсоюзы все равно опасны, а не ужасно полезны, огромные новые возможности для создания ошибок, наследство от союзов, создадут, вероятно, просто не казалось хорошей идеей :-)

Вот мое предположение для C ++ 03.

Согласно 9,5 / 1 доллара в C ++ 03, профсоюзы не могут иметь виртуальные функции. Весь смысл значимого вывода должен быть в состоянии переопределить поведение в полученном классе. Если союз не может иметь виртуальные функции, это означает, что нет смысла вытекать из союза.

Отсюда правило.

Вы можете наследовать макет данных профсоюза, используя функцию анонимного союза от C ++ 11.

#include <cstddef>

template <size_t N,typename T>
struct VecData {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float a[N];
  };
};

template <size_t N, typename T>
  class Vec : public VecData<N,T> {
    //methods..
};

В целом ее почти всегда лучше не работать с профсоюзами напрямую, но заключить их в структуре или классе. Затем вы можете основывать свое наследство от структуры внешнего слоя и использовать союзы внутри, если вам нужно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top