Como sobrecarregar o operador ++ de duas maneiras diferentes para postfix a ++ e prefix ++ a?

Respostas:

165

Deve ser assim:

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
fonte
15
Este código também mostra a diferença de desempenho de prefixo vs. pós-correção. Se o objeto que você está retornando não se encaixa em um registro da CPU, você está fazendo uma operação de cópia cara. Isso é bom se você precisa usar o valor pré-incrementado, mas se não o fizer, o postfix é muito melhor. Um exemplo seria um iterador em que você normalmente usa: for (pos = c.begin (); ...; ++ pos) {} em vez de pos ++
Eric,
22
@Eric: Você tem tudo correto, exceto uma frase no meio onde você mistura. Seu prefixo é melhor.
Martin York,
6
Por que Number operator++ (int)considera um intcomo parâmetro, embora você não o use?
Sean Letendre,
10
@SeanLetendre: Na verdade, não leva um parâmetro int. É um parâmetro falso. Mas os designers da linguagem C ++ tiveram que definir uma maneira de distinguir entre as definições de função de prefixo e pós-fixação. Esta é a decisão de design que eles tomaram.
Martin York,
2
@EnricoMariaDeAngelis: A sintaxe distingue os dois. ++xé prefixo e, portanto, chama operator++() while x++é pós-fixo e, portanto, chamaoperator++(int)
Martin York
34

A diferença está na assinatura que você escolhe para sua (s) sobrecarga (s) operator ++.

Citado do artigo relevante sobre este assunto no C ++ FAQ (vá lá para mais detalhes):

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

PS: Quando descobri sobre isso, tudo que vi inicialmente foi o parâmetro fictício, mas os diferentes tipos de retorno são na verdade mais interessantes; eles podem explicar por que ++xé considerado mais eficiente do que x++ em geral .

stakx - não contribui mais
fonte
17

Você tem duas maneiras de sobrecarregar os dois (prefixo / postfix) operadores ++ para um tipo T:

Método de objeto:

Esta é a maneira mais fácil, usando o idioma OOP "comum".

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

Função de não membro do objeto:

Esta é outra maneira de fazer isso: Contanto que as funções estejam no mesmo namespace que o objeto ao qual estão se referindo, elas serão consideradas quando o compilador procurar uma função para manipular ++t ;ou 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 ;
}

É importante lembrar que, do ponto de vista C ++ (incluindo um ponto de vista do compilador C ++), essas funções não-membros ainda fazem parte da interface de T (desde que estejam no mesmo namespace).

Existem duas vantagens potenciais da notação de função de não membro:

  • Se você conseguir codificá-los sem torná-los amigos de T, então você aumentou o encapsulamento de T
  • você pode aplicar isso até mesmo a classes ou estruturas cujo código você não possui. Esta é uma forma não intrusiva de aprimorar a interface de um objeto sem modificar sua declaração.
paercebal
fonte
1

Declare assim:

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

};

Implemente corretamente - não mexa com o que todos sabem que eles fazem (incremente e depois use, use e depois incremente).

Kate Gregory
fonte
-2

Sei que é tarde, mas tive o mesmo problema e encontrei uma solução mais simples. Não me interpretem mal, esta é a mesma solução que a principal (postada por Martin York). É um pouco mais simples. Só um pouco. Aqui está:

class Number
{
        public:

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

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

A solução acima é um pouco mais simples porque não usa um objeto temporário no método postfix.

X. Mora
fonte
6
Isso não é padrão. O operador Postfix ++ deve retornar o valor antes do incremento, não depois.
Kuilin Li
Esta resposta está incorreta. O temporário é obrigatório.
Rian Quinn