Making Operator<< Virtual

How can i overload operator as virtual

Only member functions can be virtual, but these operator<< and operator>> cannot be member functions of your class because their first argument is a stream, not the class that overloads these operators.

You can overload operator<< and operator>> adaptor functions for your class, which forward the call into the corresponding virtual functions of your class (the 2nd argument):

#include <iostream>

struct Base {
virtual std::ostream& output(std::ostream&) const = 0;
virtual std::istream& input(std::istream&) = 0;
virtual ~Base() = default;
};

inline std::ostream& operator<<(std::ostream& os, const Base& obj) { return obj.output(os); }
inline std::istream& operator>>(std::istream& is, Base& obj) { return obj.input(is); }

virtual insertion operator overloading for base and derived class

Virtual functions work by calling the correct function through a pointer in something called the vtable. So, some offset from this gives a pointer to the vtable, and some offset into the vtable gives the address of the function for that actual type of object.

However, this won't work (directly) with an overload of operator<< for inserting an object into a stream. A virtual function must be a member function--but when you're overloading a member function, its left operand must be an object of the type for which you're providing an overload. That is, with an overloaded member function, a << b is invoked as a.operator<<(b);. For stream insertion that won't work, because the left operand is always the stream rather than the type you're going to insert into the stream.

To get around that, you do make the operator itself a friend (which is never a member).

To get virtual behavior, you have that invoke a virtual member function:

class base { 
public:
virtual std::ostream &write(std::ostream &os) const {
// write myself to the passed stream
return os;
}

friend std::ostream &operator<<(std::ostream &os, base const &b) {
return b.write(os);
}
};

class derived : public base {
public:
std::ostream &write(std::ostream &os) const override {
// write myself to the passed stream
return os;
}
};

Now the overloaded operator gets called for the correct types. It, in turn, just invokes the correct virtual function for the object that was actually passed (base, derived, or some other derived class if you choose to create one).

Overriding operator in C++11, pure virtual in base class and different implementations in each derived class

One possibly solution is the following. Implement your << operator as a functions that calls a member function that you make virtual.

std::ostream& operator<<(std::ostream& stream, const Base& base) {
base.my_print_function(stream);
return stream;
}

And then make my_print_function a virtual function that you give different implementations off in your derived classes.

The reason you need to do it this way, is that when you call the operator<<, dynamic dispatch won't be used. By implementing it this way, when operator<< calls my_print_function, you do get dynamic dispatch.

virtual operator overloading c++

If you want to override a virtual function in a child-class, then you need to declare the function override in the child class.

So yes, the declaration is needed.


Think about it this way: The class declaration could be used in many places and many source files, how else would the compiler know that the function has been overridden?

Overloading pure virtual operators


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:

  1. How virtual functions work in general (and a custom operator is just nothing else than an ordinary function, solely calling syntax differs).
  2. 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 Reals, 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...

Pure virtual operator

As other posters have pointed out, the assignment is far from
trivial, and operator+ isn't normally a member. There are two
issues which should be addressed:

  1. If you support `FigAbs + Coord`, then you should also support
    `Coord + FigAbs`. The first can be a member (there's no real
    problem there); the second, if it is to be a member, must be
    a member of `Coord`, which is probably not what is wanted.
  2. Any reasonable implementation of `operator+` must return by
    value. And you can't (normally) return a polymorphic class by
    value; you need something like the letter-envelope idiom for
    this to work: the base class must look something like:


    class Figure : BinaryOperators<Figure, Coord>
    {
    Figure* myImpl;
    public:
    Figure& operator+=( Coord const& translation )
    {
    myImpl->operator+=( translation );
    return *this;
    }
    };
    Of course, you'll need factory methods for correctly
    instantiating `Figure` for each different type, a virtual
    `clone` function, and copy constructor, assignment and
    destructor which support deep copy. (`BinaryOperators` is
    a template class which implements `operator+` in terms of
    `operator+=`; this is the usual way to provide the binary
    operators.)

Finally, I would argue that this is operator overloading abuse.
The notion of addition doesn't apply to geometrical figures.
What you're doing is called translation, and the logical
solution is to provide a member function which does it, not to
overload addition.



Related Topics



Leave a reply



Submit