Team LiB
Previous Section Next Section

18.5. Union: A Space-Saving Class

18.5. 联合:节省空间的类

A union is a special kind of class. A union may have multiple data members, but at any point in time, only one of the members may have a value. When a value is assigned to one member of the union, all other members become undefined.

联合是一种特殊的类。一个 union 对象可以有多个数据成员,但在任何时刻,只有一个成员可以有值。当将一个值赋给 union 对象的一个成员的时候,其他所有都变为未定义的。

The amount of storage allocated for a union is at least as much as the amount necessary to contain its largest data member. Like any class, a union defines a new type.

union 对象分配的存储的量至少与包含其最大数据成员的一样多。像任何类一样,一个 union 定义了一个新的类型。

Defining a Union

定义联合

Unions offer a convenient way to represent a set of mutually exclusive values that may have different types. As an example, we might have a process that handles different kinds of numeric or character data. That process might define a union to hold these values:

联合提供了便利的办法表示一组相互排斥的值,这些值可以是不同类型的。作为例子,我们可能有一个处理不同各类数值或字符数据的过程。该过程可以定义一个 union 来保存这些值:

     // objects of type TokenValue have a single member,
     // which could be of any of the listed types
     union TokenValue {
         char   cval;
         int    ival;
         double dval;
     };

A union is defined starting with the keyword union, followed by an (optional) name for the union and a set of member declarations enclosed in curly braces. This code defines a union named TokenValue that can hold a value that is either a char, an int, a pointer to char, or a double. Section 18.5 (p. 795) will look at what it means to omit the union name.

一个 union 定义以关键字 union 开始,后接(可选的)union 名字,以及一组以花括号括住的成员声明。这段代码定义了名为 TokenValueunion,它可以保存一个 charintchar 指针或 double 值。本节介绍省略 union 名字意味着什么。

Like any class, a union type defines how much storage is associated with objects of its type. The size of each union object is fixed at compile time: It is at least as large as the size of the union's largest data member.

像任何类一样,union 类型定义了与 union 类型的对象相关联的内存是多少。每个 union 对象的大小在编译时固定的:它至少与 union 的最大数据成员一样大。

No Static, Reference, or Class Data Members

没有静态数据成员、引用成员或类数据成员

Some, but not all, class features apply equally to unions. For example, like any class, a union can specify protection labels to make members public, private, or protected. By default, unions behave like structs: Unless otherwise specified, the members of a union are public.

某些(但不是全部)类特征同样适用于 union。例如,像任何类一样,union 可以指定保护标记使成员成为公用的、私有的或受保护的。默认情况下,union 表现得像 struct:除非另外指定,否则 union 的成员都为 public 成员。

A union may also define member functions, including constructors and destructors. However, a union may not serve as a base class, so a member function may not be virtual.

union 也可以定义成员函数,包括构造函数和析构函数。但是,union 不能作为基类使用,所以成员函数不能为虚数。

A union cannot have a static data member or a member that is a reference. Moreover, unions cannot have a member of a class type that defines a constructor, destructor, or assignment operator:

union 不能具有静态数据成员或引用成员,而且,union 不能具有定义了构造函数、析构函数或赋值操作符的类类型的成员:

     union illegal_members {
         Screen s;      // error: has constructor
         static int is; // error: static member
         int &rfi;      // error: reference member
         Screen *ps;    // ok: ordinary built-in pointer type
     };

This restriction includes classes with members that have a constructor, destructor, or assignment operator.

这个限制包括了具有带构造函数、析构函数或赋值操作符的成员的类。

Using a Union Type

使用联合类型

The name of a union is a type name:

union 的名字是一个类型名:

     TokenValue first_token = {'a'};  // initialized TokenValue
     TokenValue last_token;           // uninitialized TokenValue object
     TokenValue *pt = new TokenValue; // pointer to a TokenValue object

Like other built-in types, by default unions are uninitialized. We can explicitly initialize a union in the same way that we can explicitly initialize (Section 12.4.5, p. 464) simple classes. However, we can provide an initializer only for the first member. The initializer must be enclosed in a pair of curly braces. The initialization of first_token gives a value to its cval member.

像其他内置类型一样,默认情况下 union 对象是未初始化的。可以用与显式初始化(第 12.4.5 节)简单类对象一样的方法显式初始化 union 对象。但是,只能为第一个成员提供初始化式。该初始化式必须括在一对花括号中。first_token 的初始化给它的 cval 成员一个值。

Using Members of a Union

使用联合的成员

The members of an object of union type are accessed using the normal member access operators (. and ->):

可以使用普通成员访问操作符(.->)访问 union 类型对象的成员:

     last_token.cval = 'z';
     pt->ival = 42;

Giving a value to a data member of a union object makes the other data members undefined. When using a union, we must always know what type of value is currently stored in the union. Retrieving the value stored in the union through the wrong data member can lead to a crash or other incorrect program behavior.

union 对象的某个数据成员一个值使得其他数据成员变为未定义的。使用 union 对象时,我们必须总是知道 union 对象中当前存储的是什么类型的值。通过错误的数据成员检索保存在 union 对象中的值,可能会导致程序崩溃或者其他不正确的程序行为。

The best way to avoid accessing the union value through the wrong member is to define a separate object that keeps track of what value is stored in the union. This additional object is referred to as the discriminant of the union.

避免通过错误成员访问 union 值的最佳办法是,定义一个单独的对象跟踪 union 中存储了什么值。这个附加对象称为 union判别式



Nested Unions

嵌套联合

Most often unions are used as nested types, where the discriminant is a member of the enclosing class:

union 最经常用作嵌套类型,其中判别式是外围类的一个成员:

     class Token {
     public:
         // indicates which kind of value is in val
         enum TokenKind {INT, CHAR, DBL};
         TokenKind tok;
         union {             // unnamed union
             char   cval;
             int    ival;
             double dval;
         } val;              // member val is a union of the 3 listed types
     };

In this class, the enumeration object tok serves to indicate which kind of value is stored in the val member. That member is an (unnamed) union that holds either a char, int, or double.

这个类中,用枚举对象 tok 指出 val 成员中存储了哪种值,val 成员是一个(未命名的)union,它保存 charintdouble 值。

We often use a switch statement (Section 6.6, p. 199) to test the discriminant and then do processing dependent on which value is currently stored in the union:

经常使用 switch 语句(第 6.6 节)测试判别式,然后根据 union 中当前存储的值进行处理:

     Token token;
     switch (token.tok) {
     case Token::INT:
         token.val.ival = 42; break;
     case Token::CHAR:
         token.val.cval = 'a'; break;
     case Token::DBL:
         token.val.dval = 3.14; break;
     }

Anonymous Unions

匿名联合

An unnamed union that is not used to define an object is referred to as an anonymous union. The names of the members of an anonymous union appear in the enclosing scope. For example, here is our Token class rewritten to use an anonymous union:

不用于定义对象的未命名 union 称为匿名联合。匿名 union 的成员的名字出现在外围作用域中。例如,使用匿名 union 重写的 Token 类如下:

     class Token {
     public:
         // indicates which kind of token value is in val
         enum TokenKind {INT, CHAR, DBL};
         TokenKind tok;
         union {                 // anonymous union
             char   cval;
             int    ival;
             double dval;
         };
     };

Because an anonymous union provides no way to access its members, the members are directly accessible as part of the scope where the anonymous union is defined. Rewriting our previous switch to use the anonymous-union version of our class would look like:

因为匿名 union 不提供访问其成员的途径,所以将成员作为定义匿名 union 的作用域的一部分直接访问。重写前面的 switch 以便使用类的匿名 union 版本,如下:

     Token token;
     switch (token.tok) {
     case Token::INT:
         token.ival = 42; break;
     case Token::CHAR:
         token.cval = 'a'; break;
     case Token::DBL:
         token.dval = 3.14; break;
     }

An anonymous union cannot have private or protected members, nor can an anonymous union define member functions.

匿名 union 不能有私有成员或受保护成员,也不能定义成员函数。



Team LiB
Previous Section Next Section