1. 程式人生 > >共用體union用法講解

共用體union用法講解

一、 聯合說明和聯合變數定義 
    聯合也是一種新的資料型別, 它是一種特殊形式的變數。 
    聯合說明和聯合變數定義與結構十分相似。其形式為: 
     union 聯合名{ 
          資料型別 成員名; 
          資料型別 成員名; 
          ... 
     } 聯合變數名; 
    聯合表示幾個變數公用一個記憶體位置, 在不同的時間儲存不同的資料型別 
和不同長度的變數。 
    下例表示說明一個聯合a_bc: 
     union a_bc{ 
          int i; 
          char mm; 
     }; 
    再用已說明的聯合可定義聯合變數。 
    例如用上面說明的聯合定義一個名為lgc的聯合變數, 可寫成: 
      union a_bc lgc; 
    在聯合變數lgc中, 整型量i和字元mm公用同一記憶體位置。 
    當一個聯合被說明時, 編譯程式自動地產生一個變數, 其長度為聯合中最大 
的變數長度。 
    聯合訪問其成員的方法與結構相同。同樣聯合變數也可以定義成陣列或指標, 
但定義為指標時, 也要用"->"符號, 此時聯合訪問成員可表示成: 
     聯合名->成員名 
    另外, 聯合既可以出現在結構內, 它的成員也可以是結構。 
    例如: 
     struct{ 
          int age; 
          char *addr; 
          union{ 
               int i; 
               char *ch; 
          }x; 
     }y[10]; 
    若要訪問結構變數y[1]中聯合x的成員i, 可以寫成: 
      y[1].x.i; 
    若要訪問結構變數y[2]中聯合x的字串指標ch的第一個字元可寫成: 
      *y[2].x.ch; 
    若寫成"y[2].x.*ch;"是錯誤的。

     二、 結構和聯合的區別 
    結構和聯合有下列區別: 
    1. 結構和聯合都是由多個不同的資料型別成員組成, 但在任何同一時刻, 
聯合中只存放了一個被選中的成員, 而結構的所有成員都存在。 
    2. 對於聯合的不同成員賦值, 將會對其它成員重寫, 原來成員的值就不存 
在了, 而對於結構的不同成員賦值是互不影響的。 
    下面舉一個例了來加對深聯合的理解。 
    例4: 
     main() 
     { 
          union{                   /*定義一個聯合*/ 
               int i; 
               struct{             /*在聯合中定義一個結構*/ 
                    char first; 
                    char second; 
               }half; 
          }number; 
          number.i=0x4241;         /*聯合成員賦值*/ 
          printf("%c%c/n", number.half.first, mumber.half.second); 
          number.half.first='a';   /*聯合中結構成員賦值*/ 
          number.half.second='b'; 
          printf("%x/n", number.i); 
          getch(); 
     } 
    輸出結果為: 
     AB 
     6261 
    從上例結果可以看出: 當給i賦值後, 其低八位也就是first和second的值; 
當給first和second賦字元後, 這兩個字元的ASCII碼也將作為i 的低八位和高八 
位。

   這裡注意一點,個人認為譚浩強的C語言書中有一點錯誤,他書裡面說對i賦值後就不能

夠輸出結構體 half,其實是可以的.

熟悉C的程式設計師都知道union(聯合體)的用法,利用union可以用相同的儲存空間儲存不同型別的資料型別,從而節省記憶體空間。當訪問其內成員時可用"."和"-> "來直接訪問。在C++出現後,它繼承了union並保留了其在C中的特性。但是在C++中的union又有了新的擴充套件,這需要大家瞭解,要不然你會感到費解和迷惑。下面我講兩點。 

  一、在union中儲存物件 

  在C中union中可以儲存任意型別的內建資料型別,那麼在C++中union是否可以儲存物件呢?還是讓我們看一個例子吧,這比任何言語都能說明問題,不是嗎? 

#pragma warning(disable : 4786) 
#include 
using namespace std; 

class TestUnion 

 public: 
 TestUnion(long l):data_(l) 
 { 
  }; 
 int data_; 
}; 

typedef union _tagUtype_ 

 TestUnion obj; 
}UT; 

int main (void) 

 return 0; 



  這樣不行,union中不可以儲存TestUnion類的物件,但在C中union可以儲存struct呀,為什麼不能儲存類的物件呢?很簡單,請問,在C中union可以儲存帶有建構函式的struct嗎?對了,在C中的struct是沒有建構函式的。所以如果C++中union可以儲存有建構函式的類的物件就不太符合邏輯,那不是說C++和C完全相容嗎?不錯,正因為這一點,C++中union不可以儲存有建構函式的類的物件,但是可以儲存不帶建構函式的類的物件,這樣就和C保持一致了,不想信你試試。對TestUnion類的宣告進行如下修改: 

class TestUnion 

 public: 
 int data_; 
}; 

  再進行編譯,一切OK!。但是這樣卻失去了C++的構造初始化特性,這樣做是沒有任何意義的,我只是在說其在C++中的語義,並不是推薦大家使用(絕對不推薦)。但是我們可以在union中儲存物件的指標,從而引用不同的物件型別。不用我再多說了吧,大家還是試試吧! 

  二、類中union的初始化 

  由於union的共享記憶體特點,我們可以使我們的類儲存不同的型別而不浪費記憶體空間,在類中我們可以宣告一個union儲存不同型別的指標,示例如下: 

#pragma warning(disable : 4786) 
#include 

using namespace std; 

class TestUnion 

enum StoreType{Long,Const_CharP}; 
union 

const char* ch_; 
long l_; 
} data_; 
StoreType stype_; 
TestUnion(TestUnion&); 
TestUnion& operator=(const TestUnion&); 
public: 
TestUnion(const char* ch); 
TestUnion(long l); 
operator const char*() const {return data_.ch_;} 
operator long() const {return data_.l_;} 
}; 

TestUnion::TestUnion(const char* ch):data_.ch_(ch),stype_(Const_CharP) 



TestUnion::TestUnion(long l):data_.l_(l),stype_(Long) 



int main (void) 

TestUnion pszobj("yuankai"); 
TestUnion lobj(1234); 
cout<(pszobj)< cout< 
return 0; 



  真是不幸,編譯都通不過,好象沒有什麼問題呀,為什麼呢?data_.ch_(ch)和data_.l_(l)有問題嗎?如果你問一個C程式設計師他會告訴你,絕對沒問題。你不會去懷疑編譯器有問題吧!不好意思!我一開始就是這麼想的,真是慚愧。費解,迷惑。讓我們來看看構造TestUnion物件時發生了什麼,這樣你就會明白了。當建立TestUnion物件時,自然要呼叫其相應的建構函式,在建構函式中當然要呼叫其成員的建構函式,所以其要去呼叫union成員的建構函式,但是其為匿名的,有沒有建構函式可呼叫,所以出錯。很明顯在C++中union和class一樣它可以有建構函式,不能如此直接引用其成員。struct同樣有這限制。只要我們給其定義一個建構函式什麼問題都解決了。示例如下: 

class TestUnion 

enum StoreType{Long,Const_CharP}; 
union DataUnion //不能匿名 

DataUnion(const char*); //宣告const char*建構函式 
DataUnion(long); //宣告long建構函式 
const char* ch_; 
long l_; 
} data_; 
StoreType stype_; 
TestUnion(TestUnion&); 
TestUnion& operator=(const TestUnion&); 
public: 
TestUnion(const char* ch); 
TestUnion(long l); 
operator const char*() const {return data_.ch_;} 
operator long() const {return data_.l_;} 
}; 

TestUnion::TestUnion(const char* ch):data_(ch),stype_(Const_CharP) 
{//注意data_(ch),這裡直接引用data_ 


TestUnion::TestUnion(long l):data_(l),stype_(Long) 
{//注意data_(l),這裡直接引用data_ 


TestUnion::DataUnion::DataUnion(const char* ch):ch_(ch) 



TestUnion::DataUnion::DataUnion(long l):l_(l) 



  現在再編譯,如果還不行,你懷疑編譯器有問題是有理由的。好了就寫這麼多吧!希望對大家有幫助,我可是花了一個下午的時間呀!如果有什麼錯誤,希望來信指出,很希望和大家共同探討C++,共同進步