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 Ba开发者_运维问答se*[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.
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.
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.
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.
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 ofDerived
like<int>, <double>, <float>, any struct <abc>
.- You can not have a
template virtual
method insideBase
, because language doesn't allow it
Plain 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.
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 :)
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.
精彩评论