Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am working in C++ and I have this problem.

class Container {
   Container(int which_type_to_use_a_b_or_c);

   A & getData(A & prototype);
   B & getData(B & prototype);
   C & getData(C & prototype);

private:
   A a;
   B b;
   C c;
   int type_used;

}

Only one of the A,B or C datatypes is actually used in a class Container instantiation. The constructor flag decides which one to use. When it's time to get a reference to the internal object, I need a getData routine which returns the reference of the different type. In order to disambiguate, I pass a "prototype" A() B() or C().

I don't really like this pattern, but I am unable to find anything better due to my limited palette in c++. Do you have any other approach available? please note that templating Container over A, B or C is not an option due to other constraints.

share|improve this question
    
Do/Can A, B and C have a common parent? –  superM Apr 10 '13 at 8:45
    
@superM they have not, but we also can't use pointers, only references –  Stefano Borini Apr 10 '13 at 8:46
7  
Long time I didn't use C++, but wouldn't this be a typical case where you would use templates? –  thorsten müller Apr 10 '13 at 8:47
    
@thorstenmüller: it would, but I don't want to for other reasons. –  Stefano Borini Apr 10 '13 at 8:48
10  
sounds like you have a lot of constraints you haven't told us then, perhaps you should share these –  jk. Apr 10 '13 at 8:58
add comment

3 Answers

up vote 8 down vote accepted

You could use a discriminated union, like Boost.Variant

class Container {
    typedef boost::variant<A,B,C> ABC;
    enum Type { UseA, UseB, UseC };

    explicit Container(Type t);

    ABC & getData();

private:
    ABC value;
}

but frankly this feels like an X-Y problem. What are you actually trying to accomplish?


NB. you said in a comment

... we also can't use pointers, only references

you may be interested to know that runtime polymorphism works just fine with references (even if it doesn't help here).

share|improve this answer
    
Yes, but you can't leave a reference pointing to nothing, or not assign it, or have a reference to a base class as a member variable. Some patterns require that using pointers. –  Stefano Borini Apr 10 '13 at 9:25
1  
A reference has to be bound, yes, but why can't you have a reference to a base class as a member variable? Admittedly you still need to create the instance somewhere. Perhaps you could explain why you're not allowed pointers? –  Useless Apr 10 '13 at 9:27
1  
Wait, so is changing the type after initialization a requirement now? And - I have no idea what you mean by generic programming if it precludes pointers. –  Useless Apr 10 '13 at 9:50
1  
You can certainly use both runtime and compile-time polymorphism mixed together. I get the feeling there are lot of constraints & decisions going unstated in this question. –  Useless Apr 10 '13 at 12:18
2  
You prefer generic programming but don't want to use templates in the solution? –  bstamour Apr 10 '13 at 14:20
show 2 more comments

It looks a lot like Boost.Variant which might either replace your class or help implementing it easily.

Basically it provide a way to allocate memory that can contain either A, B, C which are defined at compile-time. When you need to get the data, it's easy to retrieve what you want. You can check dynamically which time is stored, and if the user code already know which type should be available, it can just extract the value and get an exception if it's not the expected type.

share|improve this answer
    
This is an interesting pattern indeed. +1 –  Stefano Borini Apr 10 '13 at 9:04
    
I was gonna suggest using union, but this looks nicer. –  Martin Wickman Apr 10 '13 at 9:05
    
@MartinWickman Yes it's basically a type-safe union. Boost.Any is basically a type-safe void*. –  Klaim Apr 10 '13 at 9:50
add comment

in addition to the concept of Boost::Variant or simple unions, this is a problem that may be better solved using a template. (and I know you don't want to use templates, but if you won't tell us why, I'm going to answer anyway - it might help someone else new to C++ get the right answer)

So you'd create a class where the type you're containing is not passed in as a flag, but is passed as a 'compiler instruction' to generate a class specifically for the type you want to use.

eg.

template <class T>
class Container{
    T the_type_thats_used;
  public:
    T & getData(T & prototype);
    typedef T type_used;
};

this is what templates are used for, a good example is the STL that has a load of container classes that work this way.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.