Wie kann man den Operator ++ auf zwei verschiedene Arten für Postfix a ++ und Präfix ++ a überladen?

Antworten:

165

Sollte so aussehen:

class Number 
{
    public:
        Number& operator++ ()     // prefix ++
        {
           // Do work on this.   (increment your object here)
           return *this;
        }

        // You want to make the ++ operator work like the standard operators
        // The simple way to do this is to implement postfix in terms of prefix.
        //
        Number  operator++ (int)  // postfix ++
        {
           Number result(*this);   // make a copy for result
           ++(*this);              // Now use the prefix version to do the work
           return result;          // return the copy (the old) value.
        }
}; 
Martin York
quelle
15
Dieser Code zeigt auch den Leistungsunterschied zwischen Präfix und Postfix. Wenn das Objekt, das Sie zurückgeben, nicht in ein CPU-Register passt, führen Sie einen teuren Kopiervorgang durch. Dies ist in Ordnung, wenn Sie den vorinkrementierten Wert verwenden müssen. Wenn Sie dies nicht tun, ist Postfix viel besser. Ein Beispiel wäre ein Iterator, in dem Sie normalerweise Folgendes verwenden: for (pos = c.begin (); ...; ++ pos) {} anstelle von pos ++
Eric
22
@Eric: Du hast es bis auf einen Satz in der Mitte, in dem du mischst, richtig korrigiert. Sein Präfix ist besser.
Martin York
6
Warum wird Number operator++ (int)ein intals Parameter verwendet, obwohl Sie ihn nicht verwenden?
Sean Letendre
10
@ SeanLetendre: Es wird kein int-Parameter benötigt. Es ist ein gefälschter Parameter. Die Entwickler der C ++ - Sprache mussten jedoch einen Weg definieren, um zwischen Präfix- und Postfix-Funktionsdefinitionen zu unterscheiden. Dies ist die Designentscheidung, die sie getroffen haben.
Martin York
2
@EnricoMariaDeAngelis: Die Syntax unterscheidet die beiden. ++xist Präfix und ruft somit auf, operator++() während x++Postfix ist und somit anruftoperator++(int)
Martin York
34

Der Unterschied liegt darin, welche Signatur Sie für Ihre Überladung (en) von wählen operator ++.

Zitiert aus dem entsprechenden Artikel zu diesem Thema in den C ++ - FAQ (weitere Informationen finden Sie dort):

class Number {
  public:
    Number& operator++ ();     // prefix ++: no parameter, returns a reference
    Number  operator++ (int);  // postfix ++: dummy parameter, returns a value
};

PS: Als ich davon erfuhr, sah ich anfangs nur den Dummy-Parameter, aber die verschiedenen Rückgabetypen sind tatsächlich interessanter. Sie könnten erklären, warum dies ++xals effizienter als x++ allgemein angesehen wird .

stakx - nicht mehr beitragen
quelle
17

Sie haben zwei Möglichkeiten, die beiden (Präfix / Postfix) ++ - Operatoren für einen Typ T zu überladen:

Objektmethode:

Dies ist der einfachste Weg, wenn Sie die "allgemeine" OOP-Sprache verwenden.

class T
{
    public :
        T & operator++() // ++A
        {
            // Do increment of "this" value
            return *this ;
        }

        T operator++(int) // A++
        {
           T temp = *this ;
           // Do increment of "this" value
           return temp ;
        }
} ;

Objekt Nichtmitgliedsfunktion:

Dies ist eine andere Möglichkeit, dies zu tun: Solange sich die Funktionen im selben Namespace befinden wie das Objekt, auf das sie sich beziehen, werden sie berücksichtigt, wenn der Compiler nach einer Funktion sucht, die verarbeitet ++t ;oder t++ ;codiert werden soll:

class T
{
    // etc.
} ;


T & operator++(T & p_oRight) // ++A
{
   // Do increment of p_oRight value
   return p_oRight ;
}

T operator++(T & p_oRight, int) // A++
{
   T oCopy ;
   // Copy p_oRight into oCopy
   // Do increment of p_oRight value
   return oCopy ;
}

Es ist wichtig, sich daran zu erinnern, dass diese Nicht-Mitgliedsfunktionen aus Sicht von C ++ (einschließlich eines C ++ - Compilers) immer noch Teil der Schnittstelle von T sind (solange sie sich im selben Namespace befinden).

Es gibt zwei mögliche Vorteile der Nicht-Mitgliedsfunktionsnotation:

  • Wenn Sie es schaffen, sie zu codieren, ohne sie mit T befreundet zu haben, haben Sie die Kapselung von T erhöht
  • Sie können dies sogar auf Klassen oder Strukturen anwenden, deren Code Sie nicht besitzen. Dies ist eine nicht aufdringliche Methode, um die Schnittstelle eines Objekts zu verbessern, ohne seine Deklaration zu ändern.
paercebal
quelle
1

Erklären Sie wie folgt:

class A
{
public:
    A& operator++();    //Prefix (++a)
    A operator++(int); //Postfix (a++)

};

Richtig implementieren - nicht mit dem herumspielen, von dem jeder weiß, dass er es tut (inkrementieren, dann verwenden, verwenden, dann erhöhen).

Kate Gregory
quelle
-2

Ich weiß, dass es spät ist, aber ich hatte das gleiche Problem und fand eine einfachere Lösung. Versteh mich nicht falsch, dies ist die gleiche Lösung wie die Top-Lösung (gepostet von Martin York). Es ist nur ein bisschen einfacher. Nur ein wenig. Hier ist es:

class Number
{
        public:

              /*prefix*/  
        Number& operator++ ()
        {
            /*Do stuff */
            return *this;
        }

            /*postfix*/
        Number& operator++ (int) 
        {
            ++(*this); //using the prefix operator from before
            return *this;
        }
};

Die obige Lösung ist etwas einfacher, da in der Postfix-Methode kein temporäres Objekt verwendet wird.

X. Mora
quelle
6
Dies ist nicht Standard. Der Postfix-Operator ++ sollte den Wert vor dem Inkrementieren zurückgeben, nicht danach.
Kuilin Li
Diese Antwort ist falsch. Das temporäre ist erforderlich.
Rian Quinn