Jak przeciążyć operator ++ na dwa różne sposoby dla postfiksu a ++ i prefiksu ++ a?


Odpowiedzi:


165

Powinien wyglądać tak:

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

15
Ten kod pokazuje również różnicę w wydajności przedrostka i postfiksa. Jeśli zwracany obiekt nie mieści się w rejestrze procesora, oznacza to, że wykonujesz kosztowną operację kopiowania. Jest to w porządku, jeśli chcesz użyć wstępnie zwiększonej wartości, ale jeśli tego nie zrobisz, postfix jest znacznie lepszy. Przykładem może być iterator, w którym zazwyczaj używasz: for (pos = c.begin (); ...; ++ pos) {} zamiast pos ++
Eric

22
@Eric: Masz wszystko poprawne, z wyjątkiem zdania w środku, w którym miksujesz. Jego przedrostek jest lepszy.
Martin York

6
Dlaczego Number operator++ (int)przyjmuje się intparametr jako parametr, mimo że go nie używasz?
Sean Letendre

10
@SeanLetendre: W rzeczywistości nie przyjmuje parametru int. To fałszywy parametr. Ale projektanci języka C ++ musieli zdefiniować sposób rozróżniania między definicjami funkcji przedrostków i postfiksów. To jest decyzja projektowa, którą podjęli.
Martin York

2
@EnricoMariaDeAngelis: Składnia rozróżnia te dwa elementy. ++xjest prefiksem i dlatego wywołuje, operator++() gdy x++jest postfiksem, a zatem wywołujeoperator++(int)
Martin York

34

Różnica polega na tym, jaki podpis wybierzesz dla swojego przeciążenia operator ++.

Cytowane z odpowiedniego artykułu na ten temat w C ++ FAQ (przejdź tam, aby uzyskać więcej informacji):

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

PS: Kiedy się o tym dowiedziałem, początkowo zobaczyłem tylko parametr zastępczy, ale różne typy zwracanych danych są w rzeczywistości bardziej interesujące; mogą wyjaśnić, dlaczego ++xjest uważany za bardziej skuteczny niż x++ ogólnie .


17

Istnieją dwa sposoby na przeciążenie dwóch operatorów (prefiks / postfiks) ++ dla typu T:

Metoda obiektu:

To najłatwiejszy sposób, używając „powszechnego” idiomu OOP.

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

Funkcja niebędąca elementem obiektu:

Jest to inny sposób: tak długo, jak funkcje znajdują się w tej samej przestrzeni nazw, co obiekt, do którego się odwołują, będą one brane pod uwagę, gdy kompilator będzie szukał funkcji do obsługi ++t ;lub t++ ;kodu:

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

Należy pamiętać, że z punktu widzenia C ++ (w tym punktu widzenia kompilatora C ++) te funkcje niebędące składnikami są nadal częścią interfejsu T (o ile znajdują się w tej samej przestrzeni nazw).

Istnieją dwie potencjalne zalety notacji funkcji niebędącej składową:

  • Jeśli uda ci się je zakodować bez zaprzyjaźniania się z T, to zwiększyłeś hermetyzację T.
  • możesz to zastosować nawet do klas lub struktur, których kodu nie jesteś właścicielem. Jest to nieinwazyjny sposób na ulepszenie interfejsu obiektu bez modyfikowania jego deklaracji.

1

Zadeklaruj tak:

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

};

Wdrażaj poprawnie - nie mieszaj do tego, co wszyscy wiedzą, że robią (zwiększaj, a potem używaj, używaj, a potem zwiększaj).


-2

Wiem, że jest późno, ale miałem ten sam problem i znalazłem prostsze rozwiązanie. Nie zrozumcie mnie źle, jest to to samo rozwiązanie, co najlepsze (opublikowane przez Martina Yorka). To jest trochę prostsze. Tylko trochę. Oto ona:

class Number
{
        public:

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

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

Powyższe rozwiązanie jest nieco prostsze, ponieważ nie wykorzystuje tymczasowego obiektu w metodzie postfix.


6
To nie jest standardowe. Operator przyrostka ++ powinien zwracać wartość przed inkrementacją, a nie po.
Kuilin Li,

Ta odpowiedź jest nieprawidłowa. Wymagane jest tymczasowe.
Rian Quinn
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.