共用體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++,共同進步