简体   繁体   中英

How to override operator+ in subclass

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;
}

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. Ie 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.

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

BigIntegerNumber operator+(BigIntegerNumber row2)
{
     return CharRow::operator+(row2);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM