Programar em C++/Sobrecarga de operadores

Modificando operadores

editar

A linguagem C++ possui os mesmos operadores presentes na linguagem C. Estes têm funções padronizadas e comportamentos semelhantes a seus parentes diretos em C. Esta característica a traz compatibilidade que é um requisito fundamental e adiciona uma nova funcionalidade chamada sobrecarga de operadores.

Quando operamos tipos nativos da linguagem, fazemos com funções específicas predefinidas e padronizadas. Como poderemos operar os nossos objetos que definimos com nossas classes? Simples: criamos as funcionalidades e as atribuimos a operadores já conhecidos, de forma a manter a idéia básica da operação embutida na simbologia.

Ao definir novas funções para os operadores padrão, na verdade não substituimos a sua função, apenas adicionamos mais uma função ao mesmo operador. Esta operação é chamada de sobrecarga de operador. O nome parece um pouco fora do comum, mas apenas reflete o comportamento da linguagem quando esta lida com a definição de vários tratamentos para o mesmo identificador, que, neste caso, é o símbolo do operador. Portanto, sobrecarga de operador é a definição de novas tarefas para o mesmo operador.

Definindo novas operações

editar

Digamos que temos uma classe chamada ponto, que define dois inteiros para um plano hipoteticamente definido. Este par de inteiros poderá representar uma coordenada neste plano formado por pontos espaçados um do outro. Sob estas condições, cada objeto desta classe será uma coordenada neste plano:

class ponto
{
    int x,y;
public:

    ponto(int a, int b)
    {
       x = a;
       y = b;
    } 
};

Se quisermos operar estes objetos não teremos como fazê-lo, pois não há meios de operar os objetos do tipo ponto. Nenhuma operação é possivel, pois a linguagem não define como operá-los. Cabe ao programador dizer ao compilador como ele deve efetuar a operação do novo tipo criado.

ponto p1(1,5), p2(3,4), Soma;

Soma = p1 + p2;

Ao tentar compilar este trecho de código o compilador retornará um erro por não conhecer a maneira de como operar este tipo de dado. Como criamos o tipo de dado, precisamos definir como fazer a soma do mesmo. Podemos fazer a seguinte definição:

class ponto
{
    int x,y;
public:

    ponto(int a, int b)
    {
       x = a;
       y = b;
    }
    ponto operator+(ponto p);
};

ponto ponto::operator+(ponto p)
{
    int a, b;
    a = x + p.x;
    b = y + p.y;
    
    return ponto(a, b);
}

A sintaxe desta definição, muitas vezes causa confusão, mas poderá ser facilmente entendida depois que tenhamos assimilado as idéias básicas por trás dela. Ela opera, aparentemente, apenas um dado de entrada, porém o operador deve somar dois. Como isto é possível? Observando mais atentamente o código poderemos entender:

Verificamos que, no código, nos referimos a x e y sem definir a qual objeto pertence. Acontece que a operação está ocorrendo dentro de um dos objetos, aquele imediatamente antes do operador. Esta é a primeira coisa a ter em mente: O operador "pertence" a um dos objetos que está sendo operado, sendo sempre aquele que o antecede. Com isso, só precisamos declarar o segundo dado a operar.

Podemos visualizar isto melhor, da seguinte forma:

P3 = P1 + P2;

Que pode ser entendido como a invocação da função:

P3 = P1.operator+( P2);

Agora podemos entender como acontece a invocação da função que define o operador. Observe que P1 contém o operador que recebe P2, fazendo o cálculo e devolvendo uma cópia do objeto resultante para P3. A sintaxe esconde o mecanismo para tornar o código mais simples de ser entendido quando tiver que ser lido.