Comment surcharger l'opérateur ++ de deux manières différentes pour postfix a ++ et prefix ++ a?

Réponses:

165

Devrait ressembler à ceci:

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
la source
15
Ce code montre également la différence de performances entre préfixe et suffixe. Si l'objet que vous renvoyez ne rentre pas dans un registre CPU, vous effectuez une opération de copie coûteuse. C'est bien si vous devez utiliser la valeur pré-incrémentée, mais si vous ne le faites pas, postfix est bien meilleur. Un exemple serait un itérateur où vous utilisez généralement: for (pos = c.begin (); ...; ++ pos) {} au lieu de pos ++
Eric
22
@Eric: Vous l'avez correct tout au long, sauf une phrase au milieu où vous mélangez. Son préfixe qui est meilleur.
Martin York
6
Pourquoi Number operator++ (int)prend un intcomme paramètre même si vous ne l'utilisez pas?
Sean Letendre
10
@SeanLetendre: Il ne prend en fait pas de paramètre int. C'est un faux paramètre. Mais les concepteurs du langage C ++ ont dû définir un moyen de distinguer les définitions de fonctions de préfixe et de suffixe. C'est la décision de conception qu'ils ont prise.
Martin York
2
@EnricoMariaDeAngelis: La syntaxe distingue les deux. ++xest le préfixe et appelle donc operator++() while x++est un suffixe et appelle doncoperator++(int)
Martin York
34

La différence réside dans la signature que vous choisissez pour votre (vos) surcharge (s) de operator ++.

Cité à partir de l' article pertinent sur ce sujet dans la FAQ C ++ (allez-y pour plus de détails):

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

PS: Quand j'ai découvert cela, tout ce que j'ai vu au départ était le paramètre factice, mais les différents types de retour sont en fait plus intéressants; ils pourraient expliquer pourquoi ++xest considéré comme plus efficace qu'en x++ général .

stakx - ne contribue plus
la source
17

Vous avez deux façons de surcharger les deux opérateurs (prefix / postfix) ++ pour un type T:

Méthode objet:

C'est le moyen le plus simple, en utilisant un langage POO "commun".

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

Fonction non membre d'objet:

C'est une autre façon de faire ceci: tant que les fonctions sont dans le même espace de noms que l'objet qu'elles font référence aussi, elles seront prises en compte lorsque le compilateur recherchera une fonction à gérer ++t ;ou à t++ ;coder:

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

Il est important de se rappeler que, d'un point de vue C ++ (y compris un point de vue de compilateur C ++), ces fonctions non membres font toujours partie de l'interface de T (tant qu'elles sont dans le même espace de noms).

Il y a deux avantages potentiels de la notation de fonction non membre:

  • Si vous parvenez à les coder sans les rendre amis de T, alors vous avez augmenté l'encapsulation de T
  • vous pouvez l'appliquer même aux classes ou structures dont vous ne possédez pas le code. Il s'agit d'une manière non intrusive d'améliorer l'interface d'un objet sans modifier sa déclaration.
Paercebal
la source
1

Déclarez comme ceci:

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

};

Mettre en œuvre correctement - ne pas jouer avec ce que tout le monde sait faire (incrémenter puis utiliser, utiliser puis incrémenter).

Kate Gregory
la source
-2

Je sais qu'il est tard, mais j'ai eu le même problème et j'ai trouvé une solution plus simple. Ne vous méprenez pas, c'est la même solution que celle du haut (publiée par Martin York). C'est juste un peu plus simple. Juste un peu. C'est ici:

class Number
{
        public:

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

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

La solution ci-dessus est un peu plus simple car elle n'utilise pas d'objet temporaire dans la méthode postfix.

X. Mora
la source
6
Ce n'est pas standard. L'opérateur postfix ++ devrait renvoyer la valeur avant l'incrémentation, pas après.
Kuilin Li
Cette réponse est incorrecte. Le temporaire est obligatoire.
Rian Quinn