1. 程式人生 > >共用體union與列舉enum(C++)

共用體union與列舉enum(C++)

一、共用體:

共用體(union)是一種資料格式,它能夠儲存不同的資料型別,但只能同時儲存其中的一種型別。也就是說,結構可以同時儲存int、long和double,共用體只能儲存int、long或double。共用體的句法與結構相似,但含義不同。例如:

union one4all {
    int int_val;
    long long_val;
    double double_val;
};

可以使用one4all變數來儲存int、long或double,條件是在不同的時間進行:

one4all pail;
pail.int_val = 15;
cout << pail.int
_val << endl; pail.double_val = 1.38; cout << pail.double_val << endl;

上方程式碼表示,當我們將pail裡的int_val賦值時,pail儲存的是int型別的變數,因此long和double的變數失效,同理當我們將pail裡的double_val賦值時,pail儲存的是double型別的變數。 由於共用體每次只能儲存一個值,因此它必須有足夠的空間儲存空間佔用最大的成員,所以,公用體的長度為其空間佔用最大成員的長度。 公用體的用途之一:當資料項使用兩種或更多種格式(但不會同時使用)時,可節省空間。例如,假設管理一個小商品目錄,其中有些商品的id是整數,另一些id是字串的時候。

struct widget {
    char name[20];
    int type;
    union id {
        int id_int;
        char id_char[20];
    }id_val;
}prize;

int main() {
    cin >> prize.name >> prize.type;
    if (prize.type == 1)    cin >> prize.id_val.id_int;
    else cin >> prize.id_val.id_char;
    return
0; }

其中,上述程式碼的公用體可用匿名共用體代替。

struct widget {
    char name[20];
    int type;
    union {
        int id_int;
        char id_char[20];
    };
}prize;

int main() {
    cin >> prize.name >> prize.type;
    if (prize.type == 1)    cin >> prize.id_int;
    else cin >> prize.id_char;
    return 0;
}

由於共用體是匿名的,因此id_int和id_char被視為prize的兩個成員,它們的地址相同,所以不需要中間識別符號id_val。程式設計師負責確定當前哪個成員是活動的。

共用體常用於(但並非只能用於)節省記憶體,作業系統資料結構或硬體資料結構。

二、列舉:

C++的enum工具提供了另一種建立符號常量的方式,這種方式可以代替const。它還允許定義新型別,但必須按嚴格的限制進行。使用enum的句法與使用結構相似。例如:

enum spectrum{red,orange,yellow,green,blue,violet,indigo,ultraviolet};

這條語句完成兩項工作:

  1. 讓spectrum成為新型別的名稱;spectrum被稱為列舉(enumeration),就像struct變數被稱為結構一樣。
  2. 將red、orange、yellow等作為符號常量,它們對應整數值0~7。這些常量叫作列舉量(enumerator)。 在預設情況下,將整數值賦給列舉量,第一個列舉量的值為0,第二個列舉量的值為1,依此類推。可以通過顯式地制定整數值來覆蓋預設值。例如:
enum bits { one = 1, two = 2, four = 4, eight = 8 };

指定的值必須是整數,也可以只顯式地定義其中一些列舉量的值:

enum bits { zero, null = 0, one, numero_uno = 1 };

其中,zero和null都為0,one和numero_uno都為1。在C++早期的版本中,只能將int值(或提升為int的值)賦給列舉量,但這種限制取消了,因此可以使用long甚至long long型別的值。

可以用列舉名來宣告這種型別的變數,例如上述的spectrum:

spectrum band

在不進行強制型別轉換的情況下,只能將定義列舉時使用的列舉量賦給這種列舉的變數:

band = blue;    //valid, blue is an enumerator
band = 2000;    //invalid,2000not an enumerator

因此,spectrum變數受到限制,只有8個可能的值。如果試圖將一個非法值賦給它,則有些編譯器將出現編譯器錯誤,而另一些則發出警告。為獲得最大限度的可移植性,應將把非enum值賦給enum變數視為錯誤。 對於列舉,只定義了賦值運算子。具體地說,沒有為列舉定義算術運算:

band = orange;  //valid
++band; //not valid
band = orange + red;    //not valid,but a litter tricky

其中band = orange + red非法原因是因為沒有為列舉定義運算子,但用於算數表示式中時,列舉將被轉換為整數,因此表示式orange+red將被轉換為1+0。這是一個合法的表示式,但因為得到的答案型別為int,因此不能將其賦給型別為spectrum的變數band

列舉量是整型,可被提升為int型別,但int型別不能自動轉換為列舉型別:

int color = blue;   //valid,spectrum type promoted to int
band = 3;   //invalid,int not converted to spectrum
color = 3 + red; //valid,red converted to int

如果int值是有效的,則可以通過強制型別轉換,將它賦給列舉變數:

band = spectrum(3);

列舉的取值範圍:最初,對於列舉來說,只有宣告中指出的那些值是有效的。然而,C++現在通過強制型別轉換,增加了可賦給列舉變數的合法值。每個列舉都有取值範圍,通過強制型別轉換,可以將取值範圍中的任何整數值賦給列舉變數,即使這個值不是列舉值。例如:

enum bits { one = 1, two = 2, four = 4, eight = 8 };
bits myflag;
myflag = bits(6);

其中6不是列舉值,但它位於列舉定義的取值範圍內。

取值範圍的定義如下:首先要找出上限,需要知道列舉量的最大。找到大於這個最大值的、最小的2的冪,將它減去1,得到的便是取值範圍的上限。要知道下限,需要知道列舉量的最小值。如果它不小於0,則下限為0;否則,採用與尋找上限一樣的方法。