0

I have CharRow class with such fields :

protected:
 char* ptr;
 int ROW_MAX_LENGTH;

And have subclass BigIntegerNumber (char array of numbers). My operator+ in CharRow :

   virtual CharRow operator+ (CharRow row2)
{
    int row1Length = this->getRowCurrentLength();
    int row2Length = row2.getRowCurrentLength();

    CharRow tempRow(row1Length + row2Length);

    for(int i = 0; i < row1Length; i++){
        tempRow.ptr[i] = this->ptr[i];
    }

    for(int i = 0; i < row2Length; i++){
        tempRow.ptr[i + row1Length] = row2.ptr[i];
    }

    return tempRow;
}

What do I need to invoke operator+ polymorphically ?

BigIntegerNumber operator+ (BigIntegerNumber row2)
{
    BigIntegerNumber temp(this->getRowCurrentLength() + row2.getRowCurrentLength());
    temp = BigIntegerNumber::addValue(*this, row2);
    return temp;
}
Marco A.
  • 43,032
  • 26
  • 132
  • 246
ReturnedVoid
  • 185
  • 1
  • 1
  • 6
  • 2
    Please try to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) and show us, instead of some snippets out of context. And please [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask) too. – Some programmer dude Nov 18 '16 at 15:01
  • Possible duplicate of [virtual assignment operator C++](http://stackoverflow.com/questions/669818/virtual-assignment-operator-c) – Garf365 Nov 18 '16 at 15:08

2 Answers2

0

Virtual operator + can work in general, however for it to work, some constraints must be met.

The first reason why it would not work in your case is, that the operator

BigIntegerNumber operator+ (BigIntegerNumber row2)

is not an override of the

virtual CharRow operator+ (CharRow row2)

but it is its overload (hides the original operator instead of overriding it).

For it to be the override, the function signatures would have to be the same. I.e. the same types of parameters (CharRow and not BigIntegerNumber, also better to pass by const ref than by value), and the same or covariant return type. Neither of those are met.

Things like this are sometimes done by using a "regular" virtual function taking interface references as parameters, and implementing non-virtual operators by calling such func.

In this case the main issue is the return parameter, as you cannot define the return type as by-value CharRow and actually return BigIntegerNumber (it would be sliced to the return type). You might be more lucky with the operator +=, which can return the reference to itself thus be able to work polymorphically.


The example for operator += (which does not have the problem with the return value type):

#include <iostream>
using namespace std;

struct Base
{
    virtual Base& operator +=(const Base& other);  // takes Derived as well for the virtual calls
};


struct Derived: Base
{
    Derived& operator +=(const Base& other);  // override - called via virtual
    Derived& operator +=(const Derived& other); // overload - not called via virtual
                                                // remove to always call the polymorphic version
};

Base& Base::operator +=(const Base& other)
{
    cout << "Base::operator +=(Base)";
    // beware this is slow!
    const Derived* d = dynamic_cast<const Derived*>(&other);
    if (d)
        cout << " - called with Derived";
    else
        cout << " - called with Base";
    cout << endl;
    return *this;
}

Derived& Derived::operator +=(const Base& other)
{
    cout << "Derived::operator +=(Base)";
    // beware this is slow!
    const Derived* d = dynamic_cast<const Derived*>(&other);
    if (d)
        cout << " - called with Derived";
    else
        cout << " - called with Base";
    cout << endl;
    return *this;
}

Derived& Derived::operator +=(const Derived& other)
{
    cout << "Derived::operator +=(Derived)" << endl;
    return *this;
}

int main()
{
    Derived d1, d2;
    Base b, b0;
    Base& b1 = d1;
    Base& b2 = d2;

    d1 += d2;  // Derived::operator +=(Derived)
    b1 += d2;  // Derived::operator +=(Base) - called with Derived
    d1 += b1;  // Derived::operator +=(Base) - called with Derived
    b1 += b2;  // Derived::operator +=(Base) - called with Derived
    b += d2;   // Base::operator +=(Base) - called with Derived
    d1 += b;   // Derived::operator +=(Base) - called with Base
    b += b0;   // Base::operator +=(Base) - called with Base
    b1 += b;   // Derived::operator +=(Base) - called with Base

    return 0;
}

For the operator + the result type passed by value is the problem. However, in C++ still not impossible, but you then need to use some kind of wrapper. An example of such a wrapper:

#include <iostream>
#include <memory>
using namespace std;


struct Base;
struct Derived;

class BaseWrapper
{
    shared_ptr<Base> _obj;
public:
    explicit BaseWrapper(const shared_ptr<Base>& obj) : _obj(obj)
    {}
    template<class RESULT_T>
    operator RESULT_T()
    {
        // throws if type not correct
        return dynamic_cast<RESULT_T&>(*_obj);
    }
    Base& operator +=(const Base& other);
    BaseWrapper operator +(const Base& other) const;
};

struct Base
{
    virtual Base& operator +=(const Base& other);  // takes Derived as well for the virtual calls
    BaseWrapper operator +(const Base& other) const;
private:
    virtual shared_ptr<Base> copy() const
    {
        return make_shared<Base>(*this);
    }
};


struct Derived : Base
{
    Derived& operator +=(const Base& other);  // override - called via virtual
private:
    virtual shared_ptr<Base> copy() const
    {
        return make_shared<Derived>(*this);
    }
};

Base& BaseWrapper::operator += (const Base& other)
{
    return *_obj += other;
}

BaseWrapper BaseWrapper::operator +(const Base& other) const
{
    return *_obj + other;
}

BaseWrapper Base::operator +(const Base& other) const
{
    BaseWrapper result(copy());
    result += other;
    return result;
}

int main()
{
    Derived d1, d2;
    Base b, b0;
    Base& b1 = d1;
    Base& b2 = d2;

    b = b1 + b2;  // add Derived + Derived, result is Derived (typed Base)
    b = b0 + d1;  // add Base + Derived, result is Base

    // d1 = b0 + d1;  // add Base + Derived, result is Base, throws bad_cast (cannot cast to Derived)

    d1 = b1 + b2;  // add Derived + Derived, result is Derived

    return 0;
}

That is, the BaseWrapper can be used to return the polymorphic type by value, and have conversions to the original type. But also note that in this case the memory allocation is involved.

Community
  • 1
  • 1
EmDroid
  • 5,918
  • 18
  • 18
  • Can`t i somehow cast BigIntegerNumber to CharRow for overriding operator+ ? – ReturnedVoid Nov 18 '16 at 15:40
  • not directly, but note that if you pass by const reference, the `const Base&` version takes the instances of `Derived` as well - see the update. – EmDroid Nov 18 '16 at 17:18
  • Also added an example how the polymorphic `operator +` can be implemented by using a wrapper type for the result. – EmDroid Nov 18 '16 at 18:01
  • @ReturnedVoid You could define `operator+` as templated/overloaded stand-alone functions with appropriate return types, ideally implemented via `operator+=` as `{ auto tmp=left; left+=right; return tmp; }`. – Walter Nov 18 '16 at 18:14
  • @axalis Thank you very much for explanation ! – ReturnedVoid Nov 21 '16 at 15:39
-1

If you want to invoke CharRow::operator+() inside BigIntegerNumber::operator+() you can do it as:

BigIntegerNumber operator+(BigIntegerNumber row2)
{
     return CharRow::operator+(row2);
}
LynnXe
  • 57
  • 7
  • Returning a reference to a temporary object (as the operator is implemented) is a big no-no! – EmDroid Nov 18 '16 at 15:31
  • Right, I missed the line where temporary object was created. My bad – LynnXe Nov 18 '16 at 16:56
  • You're returning a `CharRow`, but the function return type is `BigIntegerNumber` -- this only works if `BigIntegerNumber` has an implicit constructor from `CharRow`. – Walter Nov 19 '16 at 09:50