跳轉到內容

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 指標在靜態成員函式中不可用。這將在介紹聯合體時再次說明,在更深入的分析中,將在關於類的部分中提供。

華夏公益教科書