Section 18.5. Union: A Space-Saving Class


18.5. Union: A Space-Saving Class

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.

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.

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:

      // 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.

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.

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.

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.

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 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:

      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.

Using Members of a Union

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

      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.

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.



Nested Unions

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

      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.

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:

      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:

      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:

      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.





C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net