Reputation: 4082
Let's assume we have a class like the following:
class AbstractContainer{
...
};
template <typename T>
class Container : public AbstractContainer {
T someFunction();
};
Now there is another class which has a member variable that shall store one of these containers. However, the template type shall not be fixed. Therefore, instead of declaring the member variable as of type Container
, it's declared as of type AbstractContainer*
, so a pointer at the base class. This pointer should be able to store all types of Container
classes, regardless of the template parameter.
class Interface{
public:
Interface();
void doSth();
private:
AbstractContainer* container;
};
Let's assume the container is constructed in the constructor of the Interface
class like this:
Interface::Interface(){
if (/* some condition */)
this->container = new Container<int>(25);
} else {
this->container = new Container<float>(25);
}
//here I'd need to remember of which type container is: int or float
}
So here I'd need to somehow store of which type my container is (int
or float
). I know it at this point of my program and it's totally deterministic. I need to store it, because later I might have to cast my AbstractContainer*
back to a Container<int>*
or a Container<float>*
, for example in another function:
void Interface::doSth(){
//here I have to recall what the type was
if(/* type was int */) {
dynamic_cast<Container<int>&>(*(this->container)).someFunction();
} else {
dynamic_cast<Container<float>&>(*(this->container)).someFunction();
}
}
I have thought about using an enum
that contains values for all different supported types and saving the type in an additional member variable of that enum type. Then I'd have to make a switch
statement that checks for all the different possibilities and performs the correct cast. However, I wondered if there might not be an easier way.
What I'd basically like to do, is store the type used in the constructor of Interface
and then recall it in Interface::doSth
.
EDIT: I have to make clear that the function someFunction
depends on the template parameter T
. So it is not an option to make it virtual.
Upvotes: 2
Views: 1448
Reputation: 1209
class AbstactObject {
public:
virtual ~AbstractObject() = 0;
virtual AbstractObject &doSomething() = 0;
}
template<class T>
class Object : AbstactObject {
public:
virtual ~Object();
virtual Object<T> &doSomething();
T &get();
private:
T t;
}
class AbstractContainer {
public:
virtual ~AbstractObject() = 0;
virtual AbstractObject &doSomething();
private:
AbstractObject *obj;
};
template<class T>
class Container : AbstactContainer {
public:
virtual ~Container();
virtual Object<T> &doSomething() {
return obj->doSomething();
};
}
class Interface {
public:
Interface();
void doSth();
private:
AbstractContainer* container;
};
Interface::Interface() {
if (/* some condition */)
container = new Container<int>(25);
} else {
container = new Container<float>(25);
}
}
void Interface::doSth() {
auto obj = container->doSomething();
auto val = obj.get();
}
when you want to get the T value
auto obj = container->doSomething();
auto val = obj.get();
Please check: Covariant return type https://en.wikipedia.org/wiki/Covariant_return_type
Upvotes: 0
Reputation: 217448
You may do
void Interface::doSth(){
if (auto* c_int = dynamic_cast<Container<int>*>(this->container)) {
c_int->someFunction();
} else if (auto* c_float = dynamic_cast<Container<float>*>(this->container)) {
c_float->someFunction();
}
}
But why not move someFunction()
into the base class ? and use virtual method ?
Upvotes: 2
Reputation: 10001
Another alternative:
template <class T>
T doSth(Container<T> &container){
return container.someFunction(); //assume someFunction returns a T
}
You don't need a base class, no inheritance, no casts.
Upvotes: 0
Reputation: 1209
May be your answer is Curiously recurring template pattern.
template<class T, template<class> class U>
class AbstractContainer
{
void interface()
{
static_cast<U<T> *>(this)->implementation();
}
};
template<class T>
class Container : public AbstractContainer<T, Container>
{
void implementation()
{
}
};
Upvotes: 1
Reputation: 13025
Though Jarod42's answer is better, one way to do it is by using typeid
:
void doSth()
{
if (typeid(*container).hash_code() == typeid(Container<int>).hash_code())
{
cout << "int" << endl;
}
else if (typeid(*container).hash_code() == typeid(Container<float>).hash_code())
{
cout << "float" << endl;
}
}
But you'll need at least a virtual function in the base class. You can make a virtual destructor, for example.
Upvotes: 1