Conteúdo do Curso
C++ Poo
C++ Poo
Sobrecarga de Operadores
Sobrecarga de operadores é um recurso poderoso em linguagens de programação orientadas a objetos que permite redefinir o comportamento dos operadores para classes
definidas pelo usuário. Ao sobrecarregar operadores, é possível fornecer implementações personalizadas para operações envolvendo objetos da sua class
, tornando o código mais intuitivo e expressivo.
Sintaxe da sobrecarga de operadores
A sobrecarga é realizada por meio da definição de funções membro especiais ou funções friend que implementam o comportamento desejado para o operador. A sintaxe para sobrecarregar operadores varia dependendo do operador que se deseja sobrecarregar. A forma geral é a seguinte:
overloading.h
return_type operator operator_symbol(parameters);
A sintaxe, ou mais especificamente, o número de parâmetros e o tipo de retorno, também depende se a sobrecarga de operadores está sendo feita como funções membro ou funções friend.
Member.h
Friend.h
class Example { public: Example operator+ (const Example& other) { // Define behavior for operator+ } };
Tabela de operadores que podem ser sobrecarregados
Aqui está uma tabela listando todos os operadores que podem ser sobrecarregados. No entanto, é importante observar que, embora seja possível sobrecarregar esses operadores, não é de forma alguma necessário sobrecarregar todos eles para suas classes
.
Sobrecarga dos operadores de inserção de fluxo
Para sobrecarregar os operadores <<
e >>
para uma class
, normalmente define-se uma função amiga ou uma função membro que recebe um fluxo de saída (std::ostream&
) ou fluxo de entrada (std::istream&
) como operando à esquerda e um objeto da sua class
como operando à direita. Essa função então formata os dados do objeto e os envia para o fluxo ou os lê do fluxo.
Point.h
class Point { public: friend std::ostream& operator<<(std::ostream& out, const Point& point); friend std::istream& operator>>(std::istream& in, Point& point); private: int x, y; }; std::ostream& operator<<(std::ostream& out, const Point& point) { return out << "x: " << point.x << ", y: " << point.y << std::endl; } std::istream& operator>>(std::istream& in, Point& point) { return in >> point.x >> point.y; }
A sobrecarga dos operadores de inserção de fluxo, como o <<
, permite definir um comportamento de saída personalizado para objetos das suas classes
quando são enviados para um fluxo de saída como o std::cout
. Esse recurso é especialmente útil para melhorar a legibilidade e usabilidade do seu código ao trabalhar com tipos de dados personalizados.
A sobrecarga do operador <<
para fluxo de saída é mais comum do que a sobrecarga do operador >>
para fluxo de entrada, pois operações de entrada com >>
podem ser mais propensas a erros.
Sobrecarga de operadores aritméticos
É possível sobrecarregar outros operadores aritméticos (-
, *
, /
, %
) de maneira semelhante para realizar operações personalizadas com seus tipos definidos pelo usuário.
main.cpp
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} Point operator+(const Point& other) { return Point(x + other.x, y + other.y); } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p = Point(2, 4) + Point(2, 6); std::cout << p.getX() << ' ' << p.getY() << std::endl; }
O operador é sobrecarregado como uma função membro da Point
class
. Ele recebe outro objeto Point
como parâmetro e retorna um novo objeto Point
que representa a soma dos dois pontos. O operador +
pode ser substituído por -
, *
, /
ou %
, com os devidos ajustes na lógica de implementação.
Incremento e Decremento
Tanto os operadores de incremento e decremento prefixados e postfixados (++
e --
) podem ser sobrecarregados para classes
personalizadas. Vamos começar com a versão prefixada:
main.cpp
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} // Prefix increment operator (++point) Point& operator++() { ++x; ++y; return *this; } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p(2, 2); ++p; std::cout << p.getX() << ' ' << p.getY() << std::endl; }
O operador de decremento é sobrecarregado de maneira semelhante ao operador de incremento, utilizando o operador --
e a operação de subtração.
Como pode ser visto, a sobrecarga dos operadores de incremento e decremento prefixados é direta. No entanto, torna-se mais complexo com as versões posfixadas. Lembre-se de que há uma diferença na ordem de execução entre as operações prefixadas e posfixadas.
Ao sobrecarregar os operadores de incremento e decremento posfixados, também é necessário implementar a característica de ordem de execução. Isso ficará semelhante ao seguinte:
main.cpp
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} // Postfix increment operator (point++) Point operator++(int) { Point temp = *this; // Creating a temp variable ++(this->x); // Incrementing original Point's x ++(this->y); // Incrementing original Point's y return temp; // Returning created temp variable } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p(2, 2); p++; std::cout << p.getX() << ' ' << p.getY() << std::endl; }
O parâmetro inteiro é passado sem nome apenas para sinalizar ao compilador que o operador de incremento pós-fixado está sendo sobrecarregado. Isso é necessário porque as declarações para os operadores prefixado e pós-fixado seriam, de outra forma, idênticas.
Na implementação do operador de incremento pós-fixado, o valor original do objeto é armazenado em uma variável temporária (temp
). O objeto atual é então incrementado, mas o operador retorna o valor armazenado em temp
. Isso significa que a variável é incrementada, mas a alteração só tem efeito na próxima expressão, pois o operador retorna o valor original.
Obrigado pelo seu feedback!