¿Cómo sobrecargar el operador ++ de dos formas diferentes para el sufijo a ++ y el prefijo ++ a?

Respuestas:

165

Debería verse así:

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
fuente
15
Este código también muestra la diferencia de rendimiento entre prefijo y postfijo. Si el objeto que está devolviendo no encaja en un registro de CPU, entonces está realizando una operación de copia costosa. Esto está bien si necesita usar el valor preincrementado, pero si no lo hace, postfix es mucho mejor. Un ejemplo sería un iterador donde normalmente usa: for (pos = c.begin (); ...; ++ pos) {} en lugar de pos ++
Eric
22
@Eric: Lo tiene todo correcto, excepto una oración en el medio donde mezcla. Su prefijo es mejor.
Martin York
6
¿Por qué Number operator++ (int)toma an intcomo parámetro aunque no lo use?
Sean Letendre
10
@SeanLetendre: En realidad, no toma un parámetro int. Es un parámetro falso. Pero los diseñadores del lenguaje C ++ tuvieron que definir una forma de distinguir entre las definiciones de funciones de prefijo y sufijo. Esta es la decisión de diseño que tomaron.
Martin York
2
@EnricoMariaDeAngelis: La sintaxis distingue a los dos. ++xis prefix y por lo tanto llama operator++() while x++is postfix y por tanto llamaoperator++(int)
Martin York
34

La diferencia radica en qué firma elige para su (s) sobrecarga (s) de operator ++.

Citado del artículo relevante sobre este tema en las preguntas frecuentes de C ++ (vaya allí para obtener más detalles):

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

PD: Cuando me enteré de esto, todo lo que vi inicialmente fue el parámetro ficticio, pero los diferentes tipos de retorno son en realidad más interesantes; podrían explicar por qué ++xse considera más eficiente que x++ en general .

stakx - ya no contribuye
fuente
17

Tiene dos formas de sobrecargar los dos operadores (prefijo / sufijo) ++ para un tipo T:

Método de objeto:

Esta es la forma más sencilla, utilizando el modismo de programación orientada a objetos "común".

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

Función de objeto no miembro:

Esta es otra forma de hacer esto: siempre que las funciones estén en el mismo espacio de nombres que el objeto al que se refieren también, se considerarán cuando el compilador busque una función para manejar ++t ;o t++ ;codificar:

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 importante recordar que, desde el punto de vista de C ++ (incluido el punto de vista del compilador de C ++), esas funciones que no son miembros siguen siendo parte de la interfaz de T (siempre que estén en el mismo espacio de nombres).

Hay dos ventajas potenciales de la notación de función no miembro:

  • Si logras codificarlos sin hacerlos amigos de T, entonces aumentaste la encapsulación de T
  • puede aplicar esto incluso a clases o estructuras cuyo código no es de su propiedad. Esta es una forma no intrusiva de mejorar la interfaz de un objeto sin modificar su declaración.
paercebal
fuente
1

Declare así:

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

};

Implemente correctamente: no se meta con lo que todos saben que hacen (incremente y luego use, use y luego incremente).

Kate Gregory
fuente
-2

Sé que es tarde, pero tuve el mismo problema y encontré una solución más simple. No me malinterpretes, esta es la misma solución que la principal (publicada por Martin York). Es un poco más simple. Solo un poco. Aquí está:

class Number
{
        public:

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

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

La solución anterior es un poco más simple porque no usa un objeto temporal en el método postfix.

X. Mora
fuente
6
Esto no es estándar. El operador de sufijo ++ debe devolver el valor antes de incrementar, no después.
Kuilin Li
Esta respuesta es incorrecta. Se requiere el temporal.
Rian Quinn