C ++ - 关于包含“类型”成员的联合的问题

时间:2011-02-09 00:14:06

标签: c++ c unions

我有一个关于工会我仍然不理解的问题。我已经阅读了很多他们的用途,并且在大多数情况下可以看到它们如何有用并理解它们。我已经看到他们可以提供原始的“C风格”多态性。我在几个网站上看到的这个例子是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;

这有什么意义?这是否以某种方式允许联合的类型成员表示联合当前的任何结构的类型?当一个联盟的每个成员除了一个结构并且每个结构包含那个成员时,会发生这种奇怪的效果吗?

您可以在不知道对象是哪个结构的情况下访问struct成员吗?

谢谢!

6 个答案:

答案 0 :(得分:8)

如果每个事件类型都有Uint8作为其第一个数据成员,那么type的{​​{1}}成员只是方便。

使用联合的一般规则是,您只能使用您编写的最后一个数据成员访问联合中的数据。因此,如果您上次写信给union,则接下来无法从active读取。

此规则的一个例外是,如果联盟的多个成员共享相同的前缀(如果它们的第一个数据成员相同),则可以通过共享的联合的任何数据成员访问该前缀前缀。所以,在这里,你可以引用keyactive.type,无论联合的哪个数据成员是活动的,它都可以工作。

key.type type成员只是一种方便的快捷方式,可让您访问该SDL_Event字段,而无需将其限定为typeevent_object.active.type 。您可以使用event_object.key.type

答案 1 :(得分:6)

让我们来看看联盟是如何在记忆中铺设的:

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

恰好恰好type成员排队,所以无论它是什么类型,以Uint8访问联合将产生事件的实际类型。

答案 2 :(得分:0)

如果每个SDL_xyz结构的前几个字节都是它们自己的类型字段,这意味着当union包含其中一个对象时,union的前几个字节与SDL结构的前几个字节相同 - 即类型字段。

union不包含两者,它只包含SDL对象,其第一个成员恰好在类型,大小和位置上与'type'字段重合。

答案 3 :(得分:0)

标准要求C / C ++中的联盟符合它们包含的最严格类型。此外,由于结构的成员不能重新排序,并且由于当前标准的要求(在C ++ 0x中更改),联合仅包含POD类型,因此联盟的类型成员映射到类型成员中它包含的struct decks。

答案 4 :(得分:0)

就联合而言,结构和原始类型之间没有真正的区别。 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'

答案 5 :(得分:0)

[编辑,感谢詹姆斯的评论。]

标准对工会做出了一些特殊的保证,以便这种事情是安全的。

重要的规则是,如果联合中的两个POD结构以相同的成员类型开头,则允许您使用共享成员的“公共初始序列”。因此,如果设置了key.type,那么阅读button.type是合法的,它将具有相同的值。

此外,直接在union中的普通数据成员(基本类型)type必须在内存中布局,就好像它只在struct中包含该成员一样。换句话说,type也相当于key.typebutton.type等。