c++ : template member addition function
-
23-12-2019 - |
Domanda
I have an interface IOperand
:
class IOperand
{
public:
virtual IOperand * operator+(const IOperand &rhs) const = 0;
virtual std::string const & toString() const = 0;
}
And the class Operand
:
template <class T>
class Operand : public IOperand
{
public:
virtual IOperand * operator+(const IOperand &rhs) const;
virtual std::string const & toString() const;
T value;
}
The IOperand
class and the members functions operator+
and toString
prototype cannot be modified.
The member function operator+ has to add 2 values contained in 2 IOperand
. My issue is that this value can be an int, a char or a float but I don't know how to do that with templates. I have tried this :
template <typename T>
IOperand * Operand<T>::operator+(const IOperand &rhs) const
{
Operand<T> *op = new Operand<T>;
op->value = this->value + rhs.value;
return op;
}
my toString
method :
template <typename T>
std::string const & Operand<T>::toString() const
{
static std::string s; // Provisional, just to avoid a warning for the moment
std::ostringstream convert;
convert << this->value;
s = convert.str();
return s;
}
But the compiler does not find this->value
and rhs.value
because they're not in IOperand
.
EDIT : As advice in the comments, I added the toString
method in Operand
and Ioperand
, I don't really know if it could help.
Soluzione
Welcome to the wonderful word of binary operators. What do you want to happen when you do this:
IOperand* foo = new Operand<Matrix<Complex>>;
IOperand* bar = new Operand<Polynomial<FiniteField<5>>>;
IOperand* baz = *foo + *bar;
?
There are basically two possible answers. You want a compilation error, or you want a runtime error. The latter is easily doable with a dynamic_cast, the former is easily doable by throwing away your design, taking a CS university course, then PhD, then creating your own theory of binary operations and inventing your own OO language.
Of course don't neglect mundane things like memory leaks while doing all that.
Altri suggerimenti
If IOperand
is really untouchable, you'll have to resort to dynamic_cast
:
template <typename T>
IOperand * Operand<T>::operator+(const IOperand &rhs) const
{
if (const Operand<T> *arg = dynamic_cast<const Operand<T>*>(&rhs))
{
Operand<T> *op = new Operand<T>;
op->value = this->value + arg->value;
return op;
}
else
return NULL; // Or any other sensible "error occured"
}
The dynamic_cast
will succeed only if rhs
is actually an instance of the same Operand<T>
as the one on which operator +
is called. This is then checked in the if
.
However, let me state that this is horrible design. Operators should be overloaded to behave as much as the built-in ones as possible (unless you're using them in domain-language style). Using +
on std::string
s doesn't result in a pointer to a dynamically allocated std::string
either.
Code legibility aside, the primary reason why it's so wrong is that it's very easy to leak memory - the only sensible implementation of this operator+
will allocate memory dynamically, and since it returns a raw pointer, it's left up to the caller to ensure that memory is not leaked. Bad stuff.
define IOperandas template class with typename T
add T get_value()
in class IOperand
should work,
overload this function Operand, so you can fetch the data defined in child class