У меня есть интерфейс IOperand
:
class IOperand
{
public:
virtual IOperand * operator+(const IOperand &rhs) const = 0;
virtual std::string const & toString() const = 0;
}
И класс Operand
:
template <class T>
class Operand : public IOperand
{
public:
virtual IOperand * operator+(const IOperand &rhs) const;
virtual std::string const & toString() const;
T value;
}
IOperand
класс и функции членов operator+
а также toString
прототип не может быть изменен.
Оператор-член + должен добавить 2 значения, содержащиеся в 2 IOperand
, Моя проблема в том, что это значение может быть int, char или float, но я не знаю, как это сделать с помощью шаблонов. Я попробовал это:
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;
}
мой toString
метод:
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;
}
Но компилятор не находит this->value
а также rhs.value
потому что они не в IOperand
,
РЕДАКТИРОВАТЬ: Как совет в комментариях, я добавил toString
метод в Operand
а также Ioperand
Я не знаю, может ли это помочь.
Добро пожаловать в чудесное слово бинарных операторов. Что ты хочу произойдет, когда вы сделаете это:
IOperand* foo = new Operand<Matrix<Complex>>;
IOperand* bar = new Operand<Polynomial<FiniteField<5>>>;
IOperand* baz = *foo + *bar;
?
Есть в основном два возможных ответа. Вам нужна ошибка компиляции или ошибка времени выполнения. Последнее легко выполнимо с помощью dynamic_cast, первое легко выполнимо, если отбросить свой дизайн, пройти курс обучения в университете CS, затем получить степень доктора наук, затем создать собственную теорию бинарных операций и придумать собственный язык OO.
Конечно, не пренебрегайте мирскими вещами, такими как утечки памяти, делая все это.
Если IOperand
действительно неприкасаемый, вам придется прибегнуть к 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"}
dynamic_cast
будет успешным, только если rhs
на самом деле является примером того же Operand<T>
как тот, на котором operator +
называется. Затем это проверяется в if
,
Тем не менее, позвольте мне заявить, что это какой ужас дизайн. Операторы должны быть перегружены, чтобы вести себя как можно более встроенными (если вы не используете их в стиле доменного языка). С помощью +
на std::string
s не приводит к указателю на динамически распределяемый std::string
или.
Если не принимать во внимание удобочитаемость кода, то основная причина, по которой он так ошибочен, заключается в том, что очень легко утечку памяти — единственная разумная реализация этого operator+
будет выделять память динамически, и, поскольку он возвращает необработанный указатель, он остается на усмотрение вызывающей стороны, чтобы гарантировать, что память не просочилась. Плохие вещи.
определить класс шаблона IOperandas с именем типа T
добавлять T get_value()
в class IOperand
должно сработать,
перегружаем эту функцию операндом, чтобы вы могли получить данные, определенные в дочернем классе