Sobrecarga de operadores
Produzido por Gustavo BarbosaTeoria
E aí galera, aqui é o Juan do Responde Aí, e hoje eu vou falar de uma das coisas mais legais de orientação a objetos: a sobrecarga de operadores!
Imagina que pra sua aula de álgebra linear você fez uma classe chamada que contém os atributos e e um construtor que recebe esses valores.
Agora você quer criar dois objetos o e o e quer somar estes dois vetores usando a soma vetorial:
Mas o que acontece se você utilizar a expressão ? Você vai esbarrar em um erro! Pois o operador não sabe o que fazer com a classe .
Mas não se preocupe. Existe uma forma de ensinar os operadores a trabalhar com as classes que nós criamos: é a sobrecarga de operadores (em inglês, operators overload).
Uma breve revisão de operadores
Quando a gente viu operadores, nos concentramos naquilo que eles eram capazes de fazer, e nas regras de precedência e associatividade. Vimos que existem os operadores binários que trabalham com dois valores, e os operadores unários que trabalham com um valor.
Mas o que a gente não sabia na época é que operadores, a grosso modo, são um tipo especial de função. A diferença é que a gente pode escrever assim: em vez de assim .
Para um operador binário o primeiro parâmetro fica na esquerda e o segundo parâmetro na direita: equivale a .
E para um operador unário o único parâmetro recebido é o da direita: equivale a
Sobrecarregando operadores binários
Você sobrecarrega um operador da mesma forma que sobrecarrega uma função. A diferença é que o “nome da função” é a palavra-chave seguido do símbolo do operador.
Por exemplo, vamos sobrecarregar o operador binário para funcionar com a nossa classe :
Na linha 12 nos iniciamos a sobrecarga avisando que o tipo da função retorna um vetor. Depois usamos a palavra chave e o símbolo para informar que estamos sobrecarregando o operador de adição.
Na linha 13 criamos um novo objeto da classe Vetor para armazenar o resultado. Nas linhas 15 a 18 efetuamos as etapas da soma vetorial e retornamos o resultado.
Agora que temos um operador sobrecarregado, vamos colocar esse operador em prática:
Na linha 24 colocamos nosso operador sobrecarregado em prática e somamos os vetores e e guardamos o valor em . E pra garantir que deu tudo certo, na linha 26 e 27 imprimimos as componentes do vetor C.
Sobrecarregando operadores unários
Mas e se você quiser usar o operador de negativo para inverter o valor do vetor? Este é um operador unário e só recebe um parâmetro. Vamos voltar no nosso exemplo e adicionar uma sobrecarga pro operador .
Fazemos quase a mesma coisa que no exemplo anterior, porém como o operador é unário, passamos apenas um parâmetro para função. Agora vamos executar esse operador dentro da
Na linha 33 aplicamos o operador de negativo no , e nas linhas 35 e 36 imprimimos as componentes de . E observando o resultado percebemos que deu tudo certo!
Com o que você viu até aqui, você já é capaz de responder quase todas as questões sobre sobrecarga de operadores! Porém, pra garantir aquele 10, vamos nos aprofundar mais.
Sobrecarga de operadores dentro da classe
Uma outra forma de sobrecarregar um operador, é fazendo isso dentro de uma classe. Nesse caso, o operador sobrecarregado será um método da classe. Fazendo dessa forma o seu código ficar mais organizado. Outra vantagem é ter acesso aos parâmetros privados da classe.
Uma diferença é que por padrão um dos parâmetros é a própria classe. Isso quer dizer que se o operador for binário a função recebe 1 parâmetro e se o operador for unário não recebe nenhum parâmetro.
Vamos refazer o exemplo anterior do operador binário e do unário , mas dessa vez vamos criar a sobrecarga como um método da classe.
Vamos escrever a nossa classe :
Agora vamos sobrecarregar o operador
Na linha 11 começamos o método de sobrecarga dizendo que vamos retornar um Vetor, depois usamos a palavra-chave seguida do símbolo para indicar o operador que estamos sobrecarregando. O diferencial é que já está implícito que um dos parâmetros é a própria classe, então só precisamos declarar um parâmetro chamado do tipo vetor.
Na linha 12 criamos uma variável auxiliar. Nas linhas 14 e 15 fazemos as contas. Note que podemos acessar os atributos e da classe diretamente, e somamos eles com os atributos do Vetor v.
Agora vamos sobrecarregar o operador unário . A função dele é transformar valores positivos em negativos, e vice versa.
E fazemos um processo semelhante, na linha 29 começamos o método de sobrecarga dizendo que vamos retornar um , usamos a palavra-chave seguida do símbolo , porém como é um operador unário não precisamos adicionar nenhum parâmetro.
Agora vamos colocar nossos operadores em prática:
E podemos ver que deu tudo certo! A sobrecarga funciona direitinho.
Sobrecarga () e ()
Uma das coisas mais legais que podemos fazer com a sobrecarga é modificar o comportamento do e do pra facilitar a entrada e saída de dados.
Mas antes, você precisa saber que o é um objeto da classe e o é um objeto da classe . Em poucas palavras, quando a gente chama o cabeçalho no início dos nossos programas, o que estamos fazendo é informando que queremos usar as classes e .
Um detalhe importante é que os operadores e só podem ser sobrecarregados FORA da classe. Ou seja, eles não podem ser sobrecarregados como membros da classe. Não podem ser métodos da classe!
Sobrecarga do e
Vamos considerar a mesma classe que vimos até aqui:
Para sobrecarregar o operador e o objeto fazemos da seguinte forma:
Na linha 12 usamos a palavra-chave e o símbolo . A novidade está no uso do termo no começo da linha e do como primeiro parâmetro, que são necessários para que o método funcione corretamente! O segundo parâmetro da função é o Vetor , que é o objeto que queremos imprimir no
Dentro da função, na linha 14, é só a gente usar o comando e escrever o que queremos imprimir normalmente.
E finalizamos na linha 15 retornando o parâmetro . Novamente, é algo necessário para o funcionar da maneira correta.
Agora vamos testar a nossa sobrecarga:
Viu só?! Na linha 20 a gente só enfiou o no comando e a mensagem que queríamos imprimiu sem problemas.
Mas a grande vantagem é que podemos fazer mensagens mais complexas! Por exemplo, vamos modificar um pouco a sobrecarga do operador :
Fizemos uma mensagem bem complexa, que vai se comportar de maneira diferente de acordo com o valor da componente . Veja como fica o resultado:
Sobrecarga do e
O processo de sobrecarregar o operador e o objeto é muito semelhante. Porém devemos usar a classe .
Na linha 22 declaramos a função com a classe a palavra-chave , o símbolo e com os parâmetros para garantir o funcionamento correto do objeto , e com o Vetor .
Importante: note que passamos o Vetor por referencia usando o operador . Isso é necessário para a gente poder inserir as informações do usuário diretamente no objeto de destino!
Agora vamos conferir o funcionamento da sobrecarga:
Detalhes da sobrecarga de operadores
Praticamente todos os operadores podem ser sobrecarregados, com algumas poucas exceções. Mas aqui está uma lista dos operadores que podem ser sobrecarregados:
Limitações
- Não da pra mudar a ordem de precedência e associatividade dos operadores
- Não dá pra criar operadores novos! Você só pode modificar os existentes.
Boas práticas
- Sobrecarregue os operadores das suas classes sempre que fizer sentido.
- Utilize os símbolos de maneira lógica. Por exemplo, não use o símbolo para operações que que não tenham relação com soma. Não use o símbolo para efetuar divisões, e etc.
- Sempre que você sobrecarregar um operador, um dos parâmetros deve ser uma classe que você criou.
- Use um operador sobrecarregado para sobrecarregar os outros operadores! Por exemplo, use a sobrecarga que você criou do operador para sobrecarregar o operador . Isso garante a consistência das operações.
Erros comuns
- Tentar alterar o comportamento padrão do C++. Por exemplo, tentar fazer a soma de dois inteiros se comportar diferente.
- Sobrecarregar o operador NÃO implica em sobrecarregar o operador . Se quiser, você precisa sobrecarregar os dois operadores!
Por hoje é só, pessoal!
Sei que foi bastante coisa então não esquece de dar uma conferida nos exercícios pra isso tudo ficar bem guardadinho aí! 😉