The missing phrase here is covariant return types. In C++ an overridden method is allowed to return a derived (and therefore covariant) reference or pointer type. Hence
Complex& Complex::operator=(const Multinumber &rhs)
is a valid overriding method of Multinumber& Multinumber::operator=(const Multinumber&)
Unfortunately I think you also want to have covariance on the parameter type. That's not allowed by the C++ standard, IFAIK. At this point you should probably consider whether you really want this polymorphism. It means that you must have a means to convert between types. Do you wish to support conversion between Pair and Complex types? If so, Steve's dynamic_cast
approach seems the way to go. Otherwise you should remove methods such as operator= from Multinumber's overrideable methods and allow only the meaningful methods to be declared where they belong in the derived types.
Update
In response to further comments: Return type covariance only applies to references and pointers. Return by value doesn't work, since the storage requirements will differ for each type (unlike pointers). So Multinumber& operator+(Multinumber&)
is a valid method that can be overridden, but it probably won't work as one would expect, since you can't return a reference to a newly created type, since it would be destroyed when the function completes. One way to get around this would be to replace that method with Multinumber& operator+=(const Multinumber&)
. For Complex
you could then implement it as:
Complex& Complex::operator+=(const Multinumber &rhs){
const Complex & _rhs = dynamic_cast<const Complex &>(rhs);
imag+=_rhs.imag;
real+=_rhs.real;
return *this;
}
An alternative approach would be to deal completely with pointers, and make operator+
return a copy of a new
pointer. But that's just plain awful, and I strongly recommend you keep away from such horrors - that's like C with structs before C++ came along. You could improve things with some form of polymorphic pimpl approach (note I haven't checked the following, it's just to give you an idea, and it certainly could be improved):
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.
};
But, before going down this road, have a long think about whether such complexity is justified. Perhaps the level of polymorphism you're after is not warranted by the problem you've been set.