跳转到内容

C++ 编程/联合体

来自维基教科书,自由的教科书

联合体关键字用于定义联合体类型。

语法
    union union-name 
    {
        public-members-list;
    private:
        private-members-list;
    } object-list;

联合体类似于struct(比class更像),联合体在union的字段共享内存中的相同位置,并且默认情况下是public而不是private方面有所不同。union的大小是其最大字段的大小(如果对齐要求这样做,则更大,例如在 SPARC 机器上,一个union包含一个double和一个char [17],因此其大小可能是 24,因为它需要 64 位对齐)。联合体不能有析构函数

这样做有什么意义呢?联合体提供多种方法来查看同一个内存位置,从而允许更有效地使用内存。C++ 中大多数联合体的使用都被面向对象的功能所涵盖,因此它在 C 中更为常见。但是,有时在性能至关重要或知道所讨论的项目不会被扩展时,避免面向对象编程的繁文缛节是方便的。

     union Data {
       int i;
       char c;
     };


写入不同的字节

[编辑 | 编辑源代码]

联合体对于涉及写入同一个内存区域但位于分配内存空间的不同部分的低级编程任务非常有用,例如

union item 
{
  // The item is 16-bits
  short theItem;

  // In little-endian lo accesses the low 8-bits -
  // hi, the upper 8-bits
  struct { char lo; char hi; } portions;
};

注意
可以省略在项目中声明的结构体的名称,因为它没有使用。唯一需要显式命名的部分是我们打算访问的部分,即实例本身,部分。

  item tItem;
  tItem.theItem = 0xBEAD;
  tItem.portions.lo = 0xEF; // The item now equals 0xBEEF

使用此联合体,我们可以修改 theItem 的低位字节或高位字节,而不会影响任何其他字节。

实践示例:SDL 事件

[编辑 | 编辑源代码]

联合体的现实例子是 SDL 的事件系统,SDL 是 C 中的图形库。在图形编程中,事件是由用户触发的操作,例如鼠标移动或键盘按下。SDL 的职责之一是处理事件并提供一种机制供程序员监听和响应事件。

注意
以下部分涉及 C 而不是 C++ 中的库,因此某些功能(如对象的方法)在此处未使用。但是,C++ 或多或少是 C 的超集,因此您可以使用您迄今为止获得的知识来理解代码。

// primary event structure in 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;

除了Uint8(一个 8 位无符号整数)之外,每种类型都是一个包含该特定事件详细信息的结构体。

// SDL_MouseButtonEvent

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

当程序员从 SDL 接收事件时,他首先检查类型值。这告诉他事件是什么类型。根据此值,他要么忽略该事件,要么通过获取联合体的相应部分来获取更多信息。

例如,如果程序员在SDL_Event ev中接收到事件,他可以使用以下代码对鼠标点击做出反应。

if (ev.type == SDL_MOUSEBUTTONUP && ev.button.button == SDL_BUTTON_RIGHT) 
{
  cout << "You have right-clicked at coordinates (" << ev.button.x << ", "
       << ev.button.y << ")." << endl;
}

注意
由于每个 SDL_SomethingEvent 结构体都包含一个Uint8 type条目,因此可以安全地同时访问两者Uint8 type以及相应的子结构体。

虽然可以用结构体而不是联合体来提供相同的功能,但联合体更节省空间;结构体将为每种不同的事件类型使用内存,而联合体只为一种事件类型使用内存。由于每个实例只有一个条目有意义,因此在这种情况下使用联合体是合理的。

此方案也可以使用面向对象的 C++ 的多态性和继承功能构建,但是设置将很复杂,效率低于此方案。使用联合体会失去类型安全性,但会提高性能。

this 关键字是一个隐式创建的指针,它只能在联合体(或结构体或类)的非静态成员函数中访问,并且指向调用成员函数的对象。this 指针在静态成员函数中不可用。这将在介绍联合体时再次说明,在更深入的分析中,将在关于类的部分中提供。

华夏公益教科书