In my program, I find a situation where I want a UserClass
that
- is a container that can hold heterogenous types
- can call member functions of the objects held.
The set of types that are held is limited and known at compile time. In fact, all of the types are just different template
specializations.
This code illustrates the situation:
class ArrayBase { /*etc.*/ }; // definition not changeable
template <class T>
class TypedArray : public ArrayBase // definition not changeable
{
/*more functionality needed by SpecializedArray.*/
}
template<class T>
class SpecializedArray : public TypedArray<T>
{
public:
void newFunctionalityMember() { /*etc.*/ };
};
class UserClass
{
addArray( arrayElmentTypeEnum_t t)
{
switch(t) {
case float_id:
_elementArrays.push_back( new SpecializedArray<float>() );
break;
case double_id:
_elementArrays.push_back( new SpecializedArray<double>() );
break;
default:
break;
}
void doSomethingWithASpecializedArray(int num)
{
// using _elementArrays[num], call the correct newFunctionalityMember()
}
private:
std::vetor<storagePtr_t> _elementArrays;
}
Without some pleading, I don't have flexibility to change ArrayBase
or TypedArray
.
I have left storagePtr_t
type undefined, as what type it should be is a key part of my question.
I can think of one solution, illustrated below. But what a pain! This is a lot of code to have anywhere in UserClass
that I need to access the element members. Is there a better way?
boost library is fair game.
my technique:
storagePtr_t
is ArrayBase*
,
arrayElmentTypeEnum_t
would be a std::type_info*
UserClass::doSomethingWithASpecializedArray(int num)
{
// these two both uniquely identified by num.
storagePtr_t * bptr = _elementArrays[num];
arrayElmentTypeEnum_t typekey = ...
if (typekey == &typeid(SpecializedArray<float>) ) {
D<float> * dptr = static_cast<SpecializedArray<float>*>(bptr);
dptr->newFunctionalityMember();
} else if (typekey == &typeid(SpecializedArray<double>) ) {
D<float> * dptr = static_cast<SpecializedArray<double>*>(bptr);
dptr->newFunctionalityMember();
} else if (typekey == &typeid(SpecializedArray<int>) ) {
D<float> * dptr = static_cast<SpecializedArray<int>*>(bptr);
dptr->newFunctionalityMember();
}
}
You could introduce a new base class that defines the interface you want to invoke:
and then derive your array type from this base:
You can then store objects in your vector by the new base type
SpecializedArrayBase
:Since the base class defines the function you want to invoke, you can avoid all of the casting and invoke it through the base pointer: