Reputation: 41
I don't know how to resolve a problem with templates and inheritance.
In my code there is a templated class which looks more or less like:
template<typename T>
class Derived : public Base{
T value;
public:
Derived(T arg) { value=arg; };
T getValue() { return value;};
};
class Base{
};
The only purpose of my Base class is to group an array of objects of the Derived class. The parameter T is generally double, float or complex, although int and structs might also become useful. (There should be several more similar derived classes with a few additional functions, later.)
I can create such a group
Base** M = new Base*[numElements];
and assign elements of the derived class to them, e.g.:
M[54] = new Derived<double>(100.);
But how can I find out that the 55th element has value 100 later? I would need something like
virtual T getValue() = 0;
but T is a typename of the derived class and may be different for any two elements of this array.
Upvotes: 4
Views: 7149
Reputation: 9408
You could add overloaded has_value()
methods to the Base
class:
class Base
{
public:
virtual ~Base () {}
virtual bool has_value (int i) {return false;}
virtual bool has_value (double d) {return false;}
virtual bool has_value (const std::string& s) {return false;}
// etc.
};
one of which you which you override in the Derived
class:
template<typename T>
class Derived : public Base
{
T value;
public:
Derived(T arg) {value=arg;}
T getValue() { return value;}
virtual bool has_value (T t)
{
return t == value;
}
};
E.g.:
bool test ()
{
std::vector<Base*> bases;
bases.push_back (new Derived<double> (1.234));
bases.push_back (new Derived<int> (100));
bases.push_back (new Derived<std::string> ("zap"));
for(std::vector<Base*>::const_iterator iter = bases.begin (); iter != bases.end (); ++iter)
if ((*iter)->has_value (100))
return true;
return false;
}
Note, you can't replace the has_value methods in the Base class with a single templated method as virtual methods can't be templated.
Upvotes: 2
Reputation: 1596
use boost::any to store the objects in the array. Then when you want to operate on it, you can use boost::any_cast to the possible types you have.
Upvotes: 0
Reputation: 5225
You can use dynamic_cast to know what a type is it (in addition to what @StackedCrooked says). It would require some virtual functions defined in the base class, but you already need a virtual destructor there (to have the ability to delete values through base class pointers).
As an alternative, you might try boost::variant or boost::any :)
Upvotes: 0
Reputation: 283793
The Visitor
pattern is probably your best bet here. The code iterating the array has to provide a "Visitor" object that knows how to handle each of the various types.
struct NumericVisitor
{
virtual void visit(double) = 0;
virtual void visit(int) = 0;
virtual void visit(unsigned char) = 0;
};
struct Visitable
{
virtual void visitValue(NumericVisitor& visitor) = 0;
};
template<typename T>
class Derived : public Visitable
{
T value;
public:
Derived(const T& arg) value(arg) {}
void visitValue(NumericVisitor& visitor) { visitor.visit(value); }
};
Now you can define visitors for each operation you want to do on the collection, e.g. convert each element to a string, with a different format for each type, or store each element into a file, where each type can take up a different amount of space.
Upvotes: 4
Reputation: 70078
NO. It's not possible practically to have such function, because of 2 reasons:
Base
can't be template, as you
want a generic handle to store an
array which can contain any type of
Derived
like <int>, <double>, <float>,
any struct <abc>
.template
virtual
method inside Base
,
because language doesn't allow itPlain simple way to solve this problem is to have "getter" method for every type like get_double()
, get_int()
, get_float()
, get_abc()
and so on. However, your Base
will be cluttered with such methods.
Upvotes: 0
Reputation: 35515
Add a method "getDouble" to your base class. The derived classes must then implement this method and cast their own type to double if required.
Upvotes: 0