I know, but my tutor insist on doing it as overriding pure virtual operator as exercising in abstract classes, but I really don't get it.
Well, you can learn about two things from this:
- How virtual functions work in general (and a custom operator is just nothing else than an ordinary function, solely calling syntax differs).
- Virtual functions aren't the Holy Grail to solve anything.
The problem is that the classes Integer
and Real
most likely have differing internal representation – so you won't be able to do the addition/multiplication/... without knowing about the concrete type you received as second operand. Additionally, it is pretty unclear what the return type of mixed operand types should be.
I don't really need atm to add real+int only real+real, int+int
Well, OK, we can catch this:
class Number
{
public:
virtual ~Number() { } // in any case, a virtual base class should have a virtual destructor!
// fine so far:
virtual Number& operator+(Number const&) const = 0;
// we are not going to change the ^
// own instance, so we'd rather have this operator const
// (in contrast to operator+=)
};
class Integer : public Number
{
public:
Integer& operator+(Number const& other) const override
// ^ co-variant return type, so that's fine
{
// at very first, we make sure that we actually received
// an instance of type Integer
auto o = dynamic_cast<Integer const*>(&other);
if(!o)
// if not, throwing an exception is a good candidate
// for error handling...
throw std::invalid_argument("argument must be of type Integer");
// now as we know it IS an Integer:
return Integer(this->value + o->value); // or whatever...
// OOPS - the returned object gets lost when the function is left...
}
};
If you want to be able to add Real
s, too, then you'd have another type cast. Assuming Integer + Real
results in Real
, you'd then have to change the return type back to Number
, though.
However, yet a great problem contained: The returned object gets destroyed as soon as the function is left, so the reference returned is dangling.
We'll have to fix this by some means. References aren't suitable, though, so we might opt for a smart pointer:
class Number
{
virtual std::unique_ptr<Number> operator+(Number const&) const = 0;
};
class Integer : public Number
{
std::unique_ptr<Number> operator+(Number const& other) const override
// ^
// unfortunately, now, as ordinary struct, no co-variance possible any more
{
return std::make_unique<Integer>(this->value + o->value);
}
};
This problem again illustrates how inappropriate the approach chosen actually is...
Integer
s andReal
s this way – but unless you have some common representation for numbers, you'll need to know about the type... On the other hand, if you had such common representation, then why not already use in Number base class? – AconcaguaInteger
andReal
to inherit from a base class in order to enableInteger + Integer
andReal + Real
– 463035818_is_not_a_number