2016-11-18 3 views
0

I CharRow Klasse mit solchen Bereichen haben:Wie Operator außer Kraft zu setzen + in der Unterklasse

protected: 
char* ptr; 
int ROW_MAX_LENGTH; 

Und Unterklasse BigIntegerNumber (char-Array von Zahlen) haben. Mein Betreiber + 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; 
} 

Was benötige ich operator+ polymorph aufgerufen werden?

BigIntegerNumber operator+ (BigIntegerNumber row2) 
{ 
    BigIntegerNumber temp(this->getRowCurrentLength() + row2.getRowCurrentLength()); 
    temp = BigIntegerNumber::addValue(*this, row2); 
    return temp; 
} 
+2

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

+0

Possible Duplikat [virtueller Zuweisungsoperator C++] (http://stackoverflow.com/questions/669818/virtual-assignment-operator-c) – Garf365

Antwort

0

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.

+0

Can't i irgendwie BigIntegerNumber werfen für zwingende Operator + auf CharRow? – ReturnedVoid

+0

nicht direkt, aber beachten Sie, dass wenn Sie mit dem const Verweis übergeben, die 'const Base &' Version die Instanzen von 'Derived' nimmt auch - siehe Update. – axalis

+0

hinzugefügt auch ein Beispiel, wie der polymorphe 'Operator +' kann unter Verwendung einer Wrapper für das Ergebnis realisiert werden. – axalis

-1

Wenn Sie CharRow aufrufen :: operator +() innerhalb BigIntegerNumber :: operator +() Sie können es tun, wie:

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

eine Referenz auf ein temporäres Objekt Zurückgeben (wie es die Bedienungsperson durchgeführt wird) ist ein großer nein -Nein! – axalis

+0

Richtig, ich habe die Zeile verfehlt, in der das temporäre Objekt erstellt wurde. Mein Fehler – LynnXe

+0

Sie geben eine 'CharRow' zurück, aber die Funktion return type ist' BigIntegerNumber' - dies funktioniert nur, wenn 'BigIntegerNumber' einen impliziten Konstruktor aus' CharRow' hat. – Walter

Verwandte Themen