Union Removal



next up previous
Next: Polar Point Up: TECHNIQUES AND EXAMPLES Previous: Named Formal Parameters

Union Removal

 

C++'s union type is untagged and therefore unsafe. Unions require the programmer to include a separate tag field indicating which field of the union is ``current.'' Unfortunately, in large projects it is increasingly likely that this tag is incorrect or is left out in a particular function either unintentionally or because ``that case can't possibly happen here.''

The following example shows a simple union and then the class hierarchy that replaces it. One advantage of the class hierarchy is that is provides automated tag checking. The particular union represents a literal pool entry for a compiler symbol table. A literal is assumed to be either an int, a char, or a float. Adding new literal kinds is discussed below. First the original union and an example function that operates on it.

enum literal_kind{INT, CHAR, FLOAT};
typedef struct 
{
    literal_kind kind;
    union
    {
        int   int_value;
        char  char_value;
        float float_value;
    };
} literal_union;

print_literal_union(literal_union *l)
{
    switch(l->kind)
    {
        case INT:   printf("%s = %d\n", l->name, l->int_value); break;
        case CHAR:  printf("%s = %c\n", l->name, l->char_value); break;
        case FLOAT: printf("%s = %f\n", l->name, l->float_value); break;
    }
}

The class hierarchy replacing this union includes the pure virtual class ``literal.'' Such a class can have no instances; rather, it provides an interface. In this case, all classes derived from literal must override all pure virtual functions (those whose declarations end with = 0). This gives different types of literals the same interface. (Constructors are not shown in the code.)

class literal
{
public:
    virtual void print() = 0;
};

class int_literal : public literal
{
private:
    int value;
public:
    void print() {printf("%s = %d\n", name, value);};
};

class char_literal : public literal
{
private:
    char value;
public:
    void print() {printf("%s = %c\n", name, value);};
};

class float_literal : public literal
{
private:
    float value;
public:
    void print() {printf("%s = %f\n", name, value);};
};
The following code illustrate the violation possible with the union and how the C++ class hierarchy avoids it.

[ 1]   main()
[ 2]   {
[ 3]       literal_union lu;
[ 4]   
[ 5]       lu.kind = INT;                // should be lu.kind = FLOAT;
[ 6]       lu.float_value = 5.6;
[ 7]       print_literal_union(&lu);
[ 8]   
[ 9]       int_literal il(5);  
[10]       il.print();
[11]   
[12]       int_literal fl(5.6);          // compile time error
[13]       fl.print();
[14]   }

Notes



next up previous
Next: Polar Point Up: TECHNIQUES AND EXAMPLES Previous: Named Formal Parameters



David Binkley
Thu Feb 29 10:02:46 EST 1996