Здесь отсутствует фраза ковариантный тип возврата . В C ++ переопределенному методу разрешено возвращать производную (и, следовательно, ковариантную) ссылку или тип указателя. следовательно
Complex& Complex::operator=(const Multinumber &rhs)
является допустимым методом переопределения Multinumber& Multinumber::operator=(const Multinumber&)
К сожалению, я думаю, что вы также хотите иметь ковариацию по типу параметра. Это не разрешено стандартом C ++, IFAIK. В этот момент вы, вероятно, должны подумать, действительно ли вы хотите этот полиморфизм. Это означает, что у вас должны быть средства для преобразования между типами. Вы хотите поддерживать преобразование между типами Pair и Complex? Если так, то подход Стива dynamic_cast
кажется правильным. В противном случае вы должны удалить такие методы, как operator =, из переопределяемых методов Multinumber и разрешить объявление только значимых методов там, где они принадлежат производным типам.
Обновление
В ответ на дальнейшие комментарии: Ковариация типа возврата применяется только к ссылкам и указателям. Возврат по значению не работает, поскольку требования к хранилищу будут отличаться для каждого типа (в отличие от указателей). Таким образом, Multinumber& operator+(Multinumber&)
является допустимым методом, который можно переопределить, но он, вероятно, не будет работать так, как ожидалось, поскольку вы не можете вернуть ссылку на вновь созданный тип, поскольку он будет уничтожен после завершения функции. Один из способов обойти это - заменить этот метод на Multinumber& operator+=(const Multinumber&)
. Для Complex
вы можете реализовать его следующим образом:
Complex& Complex::operator+=(const Multinumber &rhs){
const Complex & _rhs = dynamic_cast<const Complex &>(rhs);
imag+=_rhs.imag;
real+=_rhs.real;
return *this;
}
Альтернативным подходом было бы полностью разобраться с указателями и заставить operator+
вернуть копию new
указателя. Но это просто ужасно, и я настоятельно рекомендую вам держаться подальше от таких ужасов - это как C с структурами до появления C ++. Вы могли бы улучшить вещи с помощью некоторой формы полиморфного подхода pimpl (заметьте, я не проверял следующее, это просто для того, чтобы дать вам идею, и это, безусловно, можно улучшить):
class Multinumber
{
public:
virtual Multinumber* operator+(const Multinumber&);
virtual Multinumber& operator=(const Multinumber&);
virtual bool operator==(const Multinumber&) const;
// etc.
};
class MultinumberOuter
{
std::unique_ptr<Multinumber> impl_;
public:
explicit MultinumberOuter(Multinumber* pimpl) : impl_(pimpl) {}
MultinumberOuter operator+(const MultinumberOuter& src) const {
return MultinumberOuter(impl_->operator+(*(src.impl_)));
}
MultinumberOuter& operator=(const MultinumberOuter& src) {
impl_->operator=(*(src.impl_));
return *this;
}
bool operator==(const MultinumberOuter& src) const {
return impl_->operator==(*(src.impl_));
}
// etc.
};
Но прежде чем идти по этому пути, долго думайте о том, оправдана ли такая сложность. Возможно, уровень полиморфизма, к которому вы стремитесь, не оправдан поставленной вами проблемой.