Virtuelle operator +
can work in general, aber dafür einige Einschränkungen zu arbeiten, müssen erfüllt sein.
Der erste Grund, warum es nicht in Ihrem Fall ist, dass der Bediener
BigIntegerNumber operator+ (BigIntegerNumber row2)
ist keine Überschreibung der
virtual CharRow operator+ (CharRow row2)
aber es ist seine Überlastung (blendet den ursprünglichen Operator aus, anstatt ihn zu überschreiben).
Damit es die Überschreibung ist, müssten die Funktionssignaturen übereinstimmen. I.e. die gleichen Arten von Parametern (CharRow
und nicht BigIntegerNumber
, auch besser const ref als nach Wert übergeben), und die gleiche oder kovariante Rückgabetyp. Keine von beiden wird getroffen.
Diese Dinge werden manchmal mit einer "normalen" virtuellen Funktion erledigt, die Schnittstellenreferenzen als Parameter verwendet und nicht-virtuelle Operatoren implementiert, indem solche Funktionen aufgerufen werden.
In diesem Fall ist das Hauptproblem die Rückgabeparameter, da Sie nicht den Rückgabetyp als Nebenwert CharRow
und BigIntegerNumber
tatsächlich zurückkehren definieren können (um es in den Rückgabetyp in Scheiben geschnitten werden würde). Sie könnten mit der operator +=
glücklicher sein, die den Verweis auf sich selbst zurückgeben kann, um so polymorph arbeiten zu können.
Das Beispiel für operator +=
(was nicht das Problem mit dem Rückgabewert Typ hat):
#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;
}
Für die operator +
der Wert übergeben Ergebnistyp ist das Problem. Allerdings in C++ immer noch nicht unmöglich, aber Sie müssen dann eine Art Wrapper verwenden. Ein Beispiel für einen solchen 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;
}
Das heißt, kann die BaseWrapper verwendet werden, um die polymorphe Art von Wert zurückzukehren, und haben Umbauten an der ursprünglichen Art. Beachten Sie aber auch, dass in diesem Fall die Speicherzuordnung involviert ist.
Versuchen Sie, ein [minimales, vollständiges und verifizierbares Beispiel] zu erstellen (http: // stackoverflow.com/help/mcve) und zeigen Sie uns, anstatt einige Ausschnitte aus dem Zusammenhang. Und bitte [lesen Sie, wie gut Fragen zu stellen] (http://stackoverflow.com/help/how-to-ask) zu. –
Possible Duplikat [virtueller Zuweisungsoperator C++] (http://stackoverflow.com/questions/669818/virtual-assignment-operator-c) – Garf365