共用体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;否则,采用与寻找上限一样的方法。

声明:以上整理自个人理解和Stephen Prata 著的《C++ Primer Plus》

你可能感兴趣的:(C++,union,enum)