Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++, Union vs Class Inheritance

I have a certain problem and I was stuck at which approach is better than the other:

A structure with an enum that defines the data in union member OR A group of classes with inheritance

Sample code is given below:

Union based Structure

  typedef union TokenValue{
   bool bValue;
   long lvalue;
   double dvalue;
   std::string svalue;
   }

  class Token{
  public:
   TokenType type;
   TokenValue value;
   };

Class Inheritance

class TokenBase{
public:
  TokenType type;
  };



class TokenNumber: public TokenBase{
public:
bool isInt;
long lvalue;
double dvalue;
};

class TokenString: public TokenBase{
 public:
  std::string svalue;
 };
like image 312
Simple Fellow Avatar asked Aug 23 '12 15:08

Simple Fellow


2 Answers

This type of design is known as a discriminated union or tagged union. You can Google for "C++ discriminated union" to see several examples of and approaches to this type of design.

A C union is usually considered a bit low-level and unsafe for C++. As Pete Becker said, your union-based solution should provide accessors instead of directly exposing the unsafe union member. unions also have the disadvantage that, prior to C++11, they can't contain non-POD data structures (so no std::string).

An inheritance-based solution has the advantage that you can start using polymorphism (e.g., add a virtual PrintTo method). (You can, of course, accomplish similar results by adding a PrintTo method to a union-based solution that does a switch over TokenType, but that's non-OO.)

A union-based solution would probably be lighter-weight than an inheritance-based solution (no vtable). That might be preferable for something as low-level as lexer tokens.

If third-party libraries are permitted, I'd strongly recommend taking a look at Boost.Variant for a more C++ approach to discriminated unions.

like image 191
Josh Kelley Avatar answered Sep 28 '22 06:09

Josh Kelley


Your class Token implements what's known as a "discriminated union". But its members shouldn't be public; that makes it too easy to change the type stored in the union without updating the type flag. Instead, provide overloaded accessors to store and read values. The accessor that stores a bool value should also set the type flag; similarly for the other accessors.

like image 33
Pete Becker Avatar answered Sep 28 '22 06:09

Pete Becker