Frage

Gibt es ein kanonisches oder empfohlenen Muster für die Durchführung arithmetische Operator Überlastung in C ++ Zahl ähnliche Klassen?

Von der C ++ FAQ, haben wir eine Ausnahme sichere Zuweisungsoperator, dass die meisten Probleme vermeidet:

class NumberImpl;

class Number {
   NumberImpl *Impl;

   ...
};

Number& Number::operator=(const Number &rhs)
{
   NumberImpl* tmp = new NumberImpl(*rhs.Impl);
   delete Impl;
   Impl = tmp;
   return *this;
}

Aber für andere Operatoren (+, + =, etc ..) sehr wenig Ratschläge andere gegeben, als sie wie die Betreiber auf eingebauten Typen verhalten zu machen.

Gibt es eine standardisierte Möglichkeit, diese zu definieren? Dies ist, was ich habe kommen mit - gibt es Fallen Ich sehe nicht

// Member operator
Number& Number::operator+= (const Number &rhs)
{
    Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
    return *this;
}

// Non-member non-friend addition operator
Number operator+(Number lhs, const Number &rhs)
{
     return lhs += rhs;
}
War es hilfreich?

Lösung

In Bjarne Stroustrup Buch " The C ++ Programming Language ", in Kapitel 11 (die zu Überladen von Operatoren gewidmet) er geht durch eine Klasse für eine komplexe Nummerntyp (Abschnitt 11.3) witting.

Eine Sache, die ich von diesem Abschnitt bemerken, ist, dass er gemischte Operationen implementiert ... ist dies wahrscheinlich erwartet für jede numerische Klasse.

In der Regel, was du hast sieht gut aus.

Andere Tipps

Die große Sache, die bei jedem Betreiber schriftlich, dass die Mitgliedsbetreiber ist nicht unterziehen Konvertierungen auf dem linken Parameter:

struct example {
  example(int);
  example operator + (example);
};

void foo() {
  example e(3), f(6);
  e + 4; // okay: right operand is implicitly converted to example
  e + f; // okay: no conversions needed.
  6 + e; // BAD: no matching call.
}

Das ist, weil Konvertierung nie für Elementfunktionen this gilt, und dies reicht für die Betreiber. Wenn der Betreiber statt im globalen Namespace example operator + (example, example) wurde, wäre es zu kompilieren (oder wenn pass-by-const-ref verwendet wurde).

Als Ergebnis symmetrische Operatoren wie + und - werden als Nicht-Mitglieder im Allgemeinen implementiert, während die Verbindung Zuweisungsoperatoren wie += und -= als Mitglieder umgesetzt werden (sie auch Daten ändern, das heißt, sie sollten Mitglieder). Und da Sie Code Doppelarbeit vermeiden möchten, die symmetrischen Operatoren können in Bezug auf die Verbindung Zuordnung diejenigen implementiert werden (wie in Ihrem Codebeispiel, obwohl Konvention empfiehlt innerhalb der Funktion die temporäre machen).

Die Konvention ist operator+(const T&) und operator-(const T&) in Bezug auf operator+=(const T&) und operator-=(const T&) zu schreiben. Wenn es Sinn macht, zu addieren und subtrahieren zu / von primitiven Typen, dann sollten Sie einen Konstruktor schreiben, die das Objekt aus dem primitiven Typ konstruiert. Dann werden die überladene Operatoren werden auch für primitive Typen arbeiten, weil der Compiler implizit den entsprechenden Konstruktor aufrufen wird.

Wie Sie selbst erwähnt, sollten Sie vermeiden, Zugriffsrechte auf Funktionen, die es nicht brauchen. Aber in Ihrem Code oben für operator+(Number, const Number&) würde ich persönlich beide Parameter const Referenzen machen und eine temporäre verwenden. Ich denke, es ist den Kommentator nicht überraschend unter Ihrer Frage dies verpaßt; es sei denn, Sie haben einen guten Grund nicht zu vermeiden Überraschungen und Tricks und so offensichtlich wie möglich sein.

Wenn Sie Ihren Code wollen mit anderen numerischen Typen zu integrieren, sagen std::complex, achten Sie auf zyklische Konvertierungen. Das heißt, nicht operator OtherNumeric() in Numeric liefern, wenn OtherNumeric einen Konstruktor liefert, die einen Numeric Parameter annimmt.

Es ist traditionell der Bediener X in Bezug auf den Betreiber = X zu schreiben
Es ist auch traditionell die alle Parameter auf die Standard-Operatoren const sind

// Member operator
// This was OK
Number& Number::operator+= (Number const& rhs) 
{
    Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
    return *this;
}

// Non-member non-friend addition operator
Number operator+(Number const& lhs,Number const& rhs)
{
     // This I would set the lhs side to const.
     // Make a copy into result.
     // Then use += add the rhs
     Number result(lhs);
     return result += rhs;
}

Sie erwähnen Zuweisungsoperator.
Aber Sie haben nicht den Kopierkonstruktor erwähnen. Da Ihre Klasse Besitz eines RAW-Zeiger hat, würde ich erwarten, dass Sie dies auch definieren. Der Zuweisungsoperator wird dann traditionell in Bezug auf das Copykonstruktor geschrieben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top