C++ 如何在子类中重写运算符+

C++ 如何在子类中重写运算符+,c++,operator-overloading,C++,Operator Overloading,我的CharRow类包含以下字段: protected: char* ptr; int ROW_MAX_LENGTH; 并具有子类BigIntegerNumber数字字符数组。 我的操作员+在查罗: virtual CharRow operator+ (CharRow row2) { int row1Length = this->getRowCurrentLength(); int row2Length = row2.getRowCurrentLength();

我的CharRow类包含以下字段:

protected:
 char* ptr;
 int ROW_MAX_LENGTH;
并具有子类BigIntegerNumber数字字符数组。 我的操作员+在查罗:

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

如果要在BigIntegerNumber::operator+内部调用CharRow::operator+,可以按以下方式执行:

BigIntegerNumber operator+(BigIntegerNumber row2)
{
     return CharRow::operator+(row2);
}
然而,要使Virtual operator+正常工作,必须满足一些约束条件

在您的案例中,它不起作用的第一个原因是,操作员

BigIntegerNumber operator+ (BigIntegerNumber row2)
不是对

但它的重载隐藏了原始运算符,而不是重写它

要使其成为覆盖,函数签名必须相同。即,相同类型的参数CharRow和not BigIntegerNumber,按常量ref传递比按值传递更好,且返回类型相同或协变。这两种情况都没有得到满足

这样的事情有时可以通过使用一个以接口引用为参数的常规虚函数来完成,并通过调用这样的函数来实现非虚运算符

在这种情况下,主要问题是返回参数,因为您不能将返回类型定义为按值CharRow,而实际返回BigIntegerNumber,它将被分割为返回类型。您可能更幸运的是使用运算符+=,它可以将引用返回到自身,从而能够以多态方式工作

运算符+=的示例不存在返回值类型问题:

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

也就是说,可以使用BaseWrapper按值返回多态类型,并将其转换为原始类型。但也要注意,在这种情况下涉及内存分配。

请尝试创建一个并向我们展示,而不是断章取义的片段。同样,当操作符被实现时,返回对临时对象的引用可能是重复的,这是一个很大的禁忌!对,我错过了创建临时对象的那一行。My badYou正在返回CharRow,但函数返回类型为BigIntegerNumber-这仅在BigIntegerNumber具有来自CharRow的隐式构造函数时有效。我是否可以将BigIntegerNumber强制转换为CharRow以重写运算符+?不是直接转换,但请注意,如果通过常量引用传递,const Base&version也使用派生的实例-请参阅更新。还添加了一个示例,说明如何通过使用结果的包装类型来实现多态运算符+。@ReturnedVoid您可以将运算符+定义为具有适当返回类型的模板化/重载独立函数,理想情况下通过运算符+=as实现{auto tmp=left;left+=right;return tmp;}@axalis非常感谢您的解释!
virtual CharRow operator+ (CharRow row2)
#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;
}
#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;
}