C ++ - вопрос об объединениях, которые содержат член типа - PullRequest
7 голосов
/ 09 февраля 2011

У меня есть вопрос о том, что я до сих пор не понимаю в профсоюзах.Я читал о многих их применениях и по большей части вижу, как они могут быть полезны, и понимаю их.Я видел, что они могут обеспечить примитивный полиморфизм в стиле «С».Примером, который я видел на нескольких веб-сайтах, является объединение событий SDL:

typedef union {
 Uint8 type;
 SDL_ActiveEvent active;
 SDL_KeyboardEvent key;
 SDL_MouseMotionEvent motion;
 SDL_MouseButtonEvent button;
 SDL_JoyAxisEvent jaxis;
 SDL_JoyBallEvent jball;
 SDL_JoyHatEvent jhat;
 SDL_JoyButtonEvent jbutton;
     SDL_ResizeEvent resize;
 SDL_ExposeEvent expose;
 SDL_QuitEvent quit;
 SDL_UserEvent user;
     SDL_SysWMEvent syswm;
} SDL_Event;

Что я не могу понять, так это то, как может существовать «типовой» член, сосуществующий с типами событий?Разве каждому из них не разрешено существовать по одному, поскольку они занимают одну и ту же область памяти?Разве объединение не существовало бы в любое время как ЛИБО тип или одно из событий?

Я понимаю, что каждое событие на самом деле является структурой с членом типа, например:

// SDL_MouseButtonEvent

typedef struct{
     Uint8 type;
     Uint8 button;
     Uint8 state;
     Uint16 x, y;
} SDL_MouseButtonEvent;

Как это как-то имеет смысл?Позволяет ли это как-то члену типа объединения представлять тип структуры, которой в данный момент является объединение?Является ли это своего рода странным эффектом, который происходит, когда каждый член объединения, кроме одного, является структурой, и каждая структура содержит этот один член?

Можно ли получить доступ к членам структуры, не зная, какой структурой является объект?

Спасибо!

Ответы [ 6 ]

8 голосов
/ 09 февраля 2011

Если каждый из типов событий имеет Uint8 в качестве первого элемента данных, то type член union является просто удобством.

Общее правило с объединениями состоит в том, что выможет получить доступ только к данным в объединении, используя последний элемент данных, в который вы записали.Итак, если вы в последний раз писали в active, вы не могли бы затем прочитать из key.

Исключением из этого правила является то, что если несколько членов объединения имеют один и тот же префикс (если их первые данные(ы) являются одинаковыми), вы можете получить доступ к этому префиксу через любой из данных членов объединения, которые разделяют префикс.Итак, здесь вы можете ссылаться на active.type или key.type, независимо от того, какой элемент данных объединения является активным, и он будет работать.

type член SDL_Event является простоудобный ярлык, позволяющий получить доступ к этому полю type, не квалифицируя его как event_object.active.type или event_object.key.type.Вы можете просто использовать event_object.type.

6 голосов
/ 09 февраля 2011

Давайте посмотрим, как объединение расположено в памяти:

Address:    Uint8    MouseButtonEvent   KeyboardEvent
x+0x0       type     type               type
x+0x1       -        button             ?
x+0x2       -        state              ?
...

Просто так получилось, что все члены type выстроились в ряд, поэтому независимо от того, какой это тип, доступ к объединению какUint8 приведет к фактическому типу события.

0 голосов
/ 09 февраля 2011

[Отредактировано, благодаря комментарию Джеймса.]

Стандарт дает некоторые специальные гарантии для профсоюзов, чтобы такие вещи были безопасными.

Важное правило заключается в том, что если две структуры POD в объединении начинаются с одинаковых типов элементов, вам разрешается использовать «общую начальную последовательность» общих элементов. Таким образом, если было установлено key.type, то можно прочитать button.type, и оно будет иметь то же значение.

Кроме того, простой элемент данных (фундаментального типа) type непосредственно в объединении должен быть размещен в памяти, как если бы он был в struct, содержащем только этот элемент. Другими словами, type также эквивалентно key.type и button.type и т. Д.

0 голосов
/ 09 февраля 2011

Что касается объединения, нет реальной разницы между структурой и примитивным типом. Структура SDL_MouseButtonEven - это просто набор типов один за другим.
Член type профсоюза занимает место члена type структур мероприятия. чтобы выразить это графически, это выглядит так:

SDL_Event union:
  type:    |--------|
  motion:  |--type--|-button-|--state-|-------x--------|-------y--------|  
  active:  |--type--|----------something-else-of-another-event--|          
  key:     |--type--|--maybe-a-smaller-event-|                             
  ... etc'
0 голосов
/ 09 февраля 2011

Стандарты требуют, чтобы объединения в C / C ++ соответствовали строжайшему типу, который они содержат. Кроме того, поскольку элементы структур не могут быть переупорядочены и из-за требований текущих стандартов (изменяющихся в C ++ 0x), что объединения содержат только типы POD, идея состоит в том, что член типа объединения сопоставляется с элементом типа в содержит структурные колоды.

0 голосов
/ 09 февраля 2011

Если каждая из первых двух байтов этой структуры SDL_xyz является собственным полем типа, это означает, что, когда объединение содержит один из этих объектов, первые две байты объединения представляют собой ту же первую пару байтов, что и структура SDL, т.е. поле типа.

Объединение не содержит и того, и другого, оно просто содержит объект SDL, первый элемент которого по типу, размеру и расположению совпадает с полем 'type'.

...