0

I have a bit of code somewhat like this:

class Token{
   public:

    union tester{
        double literal;
        string name;

        tester(double op) : literal(op) {};
        tester(string val) : name(val) {};
        tester(): tester(0.0) {};
    };

    void setUp(){
      //the literal and name members of tester should be initialized here
    };
    /*other functions are below, two of which require that the values of literal 
      and name can be changed*/
};

I need to initialize both the literal and name members, but I'm not sure how. I have tried making a variable of type tester and doing this: tester test(45.0);, but then I can only set one of the member variables, and simply using tester(45.0); doesn't work either I tried this: Token thing; thing.name = "Elly", that didn't work. My class doesn't use constructors either. So, my questions are, how can I set and then later change the values of the member variables in tester in Token?

I am using the C++11 compiler.

(I apologize in advance if this question has been answered already or is too silly, I have been looking around, but I really don't understand how I can get this to work. I'm missing something, but I'm not quite sure what.)

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 3
    You do realize that members of a `union` share the same memory? Is it possible that you actually want a `struct`? –  Feb 16 '14 at 08:03

2 Answers2

1

In a nutshell: don't do it.

Unions are really best used when representing data that has the same binary representation, e.g.:

union v4f {
    float f[4];
    struct {
      float x;
      float y;
      float z;
      float t;
    };
};

v4f v;
v.f[1] = 2.f;
v.t = 0.f;

Assuming you do actually want to use a union here, and not a struct, i.e. a token contains a name OR a literal, but never both at the same time, and you really need to save on the extra storage that a using struct would cost:
Before C++11, you couldn't have a union member with a non=trivial destructor, such as your tester.name string field. See this question for more details.

Now, this is possible, although I would recommend not doing it unless you really know what's going on. To do that, you need to define your union's destructor, because it the compiler cannot decide which, if any of the non-trivial union members to delete. I think you are better off avoiding this, because this is not an easy question to answer, without any additional information:

~tester() {
// delete name member or not ?
// very hard to decide without additional data
}

As for how to access your union member, since your union is not anonymous, it can't be accessed anonymously, so you need to actually create a member of your class with this union type, and refer to that class member.

class Token {
public:
    union tester {
        double literal;
        string name;

        tester(double op) : literal(op) {};
        tester(string val) : name(val) {};
        tester(): tester(0.0) {};
        ~tester() {}
    };
    tester data;
    ...
};

...
Token t;
t.data.name = "Elly";
Community
  • 1
  • 1
Martin J.
  • 5,028
  • 4
  • 24
  • 41
  • Okay, it makes more sense now, Thank You! (and for the reference link too). Then if I created a member for union in my class, like data, I could do this: `data.name = "Elly";` and then at another point do this `data.name = "Fred";` inside my class too? and things would be better if the types were more similar, such as if I was using an `enum class` type instead? – user3314717 Feb 16 '14 at 10:37
0

Another use case of a union is to allocate 'enough' memory for all possible objects which must be stored, but only one at a time.

Example: Having a state machine which represents each state as a instance of a class. The state machine it self contains a union which is set up of all classes. Entering a state will simple be done by new at operator at the address of the union while leaving a state will be done by manually call of the destructor.

And there is also an often seen use case: casting via union. I think that is a very terrible anti pattern :-)

Coming back to the question: Initializing two members at the same! time is never possible inside a union. The second init will overwrite the data of the first initialized object. Maybe you want a struct or you have to think again for your design.

Klaus
  • 24,205
  • 7
  • 58
  • 113
  • Oh! okay then, that makes sense. Then, if the other member was an enum class type, say `enum class Oper{OPP, ERR};`, so `Oper name;` instead of a string and `srting name;`, then, as long as I'm not trying to have both members initialized at once, I could set one, say name, to some vlue from the enum class and then later come and change things and set the value for literal instead? – user3314717 Feb 16 '14 at 10:34
  • In principle, you can store only one item at a time in a union. And in respect, please avoid unions in c++ code. There are only very few real world use cases for unions. Unions tends your code to split data from functionality which breaks the basic idea of object oriented programming. It sounds that you are thinking in procedural ideoms. I would advice you to start reading a good book for object oriented design. Maybe you should start a new question with your design problem and don't ask for the problems with a bad solution ;) – Klaus Feb 16 '14 at 10:44
  • Okay, that's good to know, though in this case the union is part of a skeleton class we were given to complete for an assignment, so I might loose marks by taking it out. Though it might be easier to do without it. This isn't wasn't the exact code from the assignment either, the assignment doesn't use a string in the union. But yeah, the code I gave wasn't very good, now that I can look back and appreciate it. ^_^; Thanks for your help :) – user3314717 Feb 16 '14 at 10:53