S
OBRECARGA DE
O
PERADORES
A sobrecarga de operadores é, talvez, o recurso mais poderoso que a linguagem C++
disponibiliza ao usuário. É um recurso que torna a manipulação de objetos muito mais intuitiva ao
permitir operações utilizando os operadores (o que normalmente seria realizado utilizando
métodos e/ou funções).
Nesta aula, os aspectos básicos, bem como exemplos de sobrecarga de operadores serão
apresentados.
A linguagem C++ permite sobrecarregar seus operadores para classes criadas pelo usuário.
Por exemplo, para concatenar dois objetos strings, bastava escrever
str1 + str2
. Este é um
exemplo de sobrecarga de operador. Nele, o operador adição (+) foi sobrecarregado para suportar
objetos do tipo string. Nessa aula, veremos como isso é possível.
Existem duas formas básicas de sobrecarregar operadores na linguagem C++: Utilizando
métodos ou funções amigas. Estudaremos ambos os casos. Porém, é necessário primeiramente
apresentar a palavra-chave
this
.
O
PONTEIRO THIS
O ponteiro
this
é um ponteiro que é utilizado quando uma função membro de um objeto
é chamada. O ponteiro
this
é um parâmetro implícito de todas as funções membro. O ponteiro
this
referencia a próprio objeto chamador da função. Portanto, quando um método
manipula
um atributo da classe (por exemplo:
RSE = 0
), na verdade o programa está realizando a operação
this->RSE = 0
, pois o método está manipulando um atributo de seu próprio objeto.
S
OBRECARGA DE
O
PERADORES
U
TILIZANDO
F
UNÇÕES
M
EMBRO
Para sobrecarregar um operador na linguagem C++, deve-se utilizar uma construção
semelhante a apresentada abaixo:
tipo nome_da_classe::operator<símbolo>(lista_de_parâmetros) {
Operações }
Na construção acima, o tipo é o tipo que a operação retornaria (que usualmente é um
objeto da classe, mas não necessariamente). O campo <símbolo> deve ser substituído pelo
operador o qual se deseja sobrecarregar. Por exemplo, para sobrecarregar o operador de adição, a
construção seria:
tipo nome_da_classe::operator+(lista_de_parâmetros) {
Operações }
Da mesma maneira, caso se desejasse sobrecarregar o operador de atribuição:
tipo nome_da_classe::operator=(lista_de_parâmetros){
Operações }
Deve-se deixar claro que, em uma operação, o próprio objeto da esquerda chama a função
de operador sobrecarregado. O responsável pela chamada é o operando da esquerda do
operador. Por exemplo, na operação
obj1 + obj2
o
obj1
seria o objeto chamador da função de
operador (assim, seria a sua função-membro a ser executada).
O modo mais fácil de entender como a sobrecarga de operadores é realizada é através de
um exemplo simples. Estude o Programa 1.
#include <iostream> using namespace std; class complexo
{
int Re, Im; public:
complexo(int r, int i) { Re = r; Im = i; } //construtor
complexo(void) { Re = 0; Im = 0; } //construtor
void imprimeNum(void) {
cout << "Parte Real: " << Re;
cout << "\nParte Imaginaria: " << Im << endl << endl; }
complexo operator=(complexo aux) //sobrecarga de =
{
this->Re = aux.Re; //o ponteiro this pode ser omitido aqui
this->Im = aux.Im; //o ponteiro this pode ser omitido aqui
return *this; }
complexo operator+(complexo aux) {
complexo aux2;
aux2.Re = this->Re + aux.Re; aux2.Im = this->Im + aux.Im; return aux2;
}
complexo operator-(complexo aux) {
complexo aux2;
aux2.Re = this->Re - aux.Re; aux2.Im = this->Im - aux.Im; return aux2; } }; int main(void) { complexo n1(10,10), n2(23,54), n3; n3 = n1 + n2; n3.imprimeNum(); system("PAUSE"); return 0;
Perceba que, quando a expressão
n1 + n2
é avaliada,
n2
é passado para a função de
operador explicitamente – através do objeto
aux
(
n1
é passado implicitamente). Todos os
ponteiros
this
(com exceção do ponteiro da função do operador
=
) podem ser omitidos. Não o
foram para demonstrar que o operando
n1
é passado implicitamente, i.e., é a sua função-membro
que é executada.
Exercício 1
Desenvolva e adicione a classe complexo a sobrecarga para o operador de
multiplicação.
É possível ainda sobrecarregar as funções de operadores para aceitar outros tipos. Observe
o exemplo abaixo.
#include <iostream> using namespace std; class complexo {
int Re, Im; public:
complexo(int r, int i) { Re = r; Im = i; } //construtor
complexo(void) { Re = 0; Im = 0; } //construtor
void imprimeNum(void) {
cout << "Parte Real: " << Re;
cout << "\nParte Imaginaria: " << Im << endl << endl; }
complexo operator=(complexo aux) //sobrecarga de =
{
this->Re = aux.Re; //o ponteiro this pode ser omitido aqui
this->Im = aux.Im; //o ponteiro this pode ser omitido aqui
return *this; }
complexo operator+(complexo aux) {
complexo aux2;
aux2.Re = this->Re + aux.Re; aux2.Im = this->Im + aux.Im; return aux2;
}
complexo operator+(int aux) //sobrecarga para int
{
complexo aux2;
aux2.Re = this->Re + aux; aux2.Im = this->Im + aux; return aux2; } }; int main(void) { complexo n1(10,10), n2(23,54), n3; n3 = n1 + n2; n3.imprimeNum(); n3 = n3 + 10; n3.imprimeNum(); system("PAUSE"); return 0; }
Programa 2 Sobrecarga de funções de Operadores.
O erro ocorrido se deve ao fato que é o operador da esquerda do operando quem realiza a
chamada a função de operador. Quando
10
+ n3 é avaliado, percebe-se que 10, sendo um tipo
interno, não possui uma função de operador definida para somar um objeto da classe complexo.
Porém, é possível contornar este problema utilizando as funções amigas.
S
OBRECARGA DE
O
PERADORES
U
TILIZANDO
F
UNÇÕES
A
MIGAS
É possível ainda realizar a sobrecarga de operadores utilizando funções amigas. Nesse caso,
ambos os operandos devem ser passados de forma explicita para a função. Observe o exemplo
abaixo.
#include <iostream> using namespace std; class complexo
{
int Re, Im; public:
complexo(int r, int i) { Re = r; Im = i; } complexo(void) { Re = 0; Im = 0; }
void imprimeNum(void) {
cout << "Parte Real: " << Re;
cout << "\nParte Imaginaria: " << Im << endl << endl; }
friend complexo operator+(complexo aux1, complexo aux2); };
complexo operator+(complexo aux1, complexo aux2) {
complexo aux3;
aux3.Re = aux1.Re + aux2.Re; aux3.Im = aux1.Im + aux2.Im; return aux3; } int main(void) { complexo n1(10,10), n2(23,54), n3; n3 = n1 + n2; n3.imprimeNum(); system("PAUSE"); return 0; }
Programa 3 Sobrecarga de Operadores utilizando funções amigas.
No exemplo acima, quando a função amiga é chamada o operando da esquerda é passado
para
aux1
e o operando da direita para
aux2
. Assim, é possível sobrecarregar a função para
aceitar os mais variados tipos de dados aparecendo em ambos os lados do operador. Observe o
próximo programa.
#include <iostream> using namespace std; class complexo
{
int Re, Im; public:
complexo(int r, int i) { Re = r; Im = i; } complexo(void) { Re = 0; Im = 0; }
void imprimeNum(void) {
cout << "Parte Real: " << Re;
cout << "\nParte Imaginaria: " << Im << endl << endl; }
friend complexo operator+(complexo aux1, complexo aux2); friend complexo operator+(complexo aux1, int aux2); friend complexo operator+(int aux1, complexo aux2); };
complexo operator+(complexo aux1, complexo aux2) {
complexo aux3;
aux3.Re = aux1.Re + aux2.Re; aux3.Im = aux1.Im + aux2.Im; return aux3;
}
complexo operator+(int aux1, complexo aux2) {
complexo aux3;
aux3.Re = aux1 + aux2.Re; aux3.Im = aux1 + aux2.Im; return aux3;
}
complexo operator+(complexo aux1, int aux2) {
complexo aux3;
aux3.Re = aux1.Re + aux2; aux3.Im = aux1.Im + aux2; return aux3; } int main(void) { complexo n1(10,10), n2(23,54), n3; n3 = n1 + n2; n3.imprimeNum(); n3 = n3 + 10; n3.imprimeNum(); n3 = 10 + n3; n3.imprimeNum(); system("PAUSE"); return 0; }
Programa 4 Sobrecarga de Operadores utilizando funções amigas 2.
Observe mais um exemplo de sobrecarga de operadores utilizando funções amigas no
Programa 5.
#include <iostream> #include <cmath> using namespace std; class complexo
{
int Re, Im; public:
complexo(int r, int i) { Re = r; Im = i; } complexo(void) { Re = 0; Im = 0; }
void imprimeNum(void) {
cout << "Parte Real: " << Re;
cout << "\nParte Imaginaria: " << Im << endl << endl; }
friend bool operator>(complexo aux1, complexo aux2); };
//sobrecarregando operador >
bool operator>(complexo aux1, complexo aux2) {
float mod1, mod2;
mod1 = sqrt( pow( aux1.Re , 2.0 ) + pow( aux1.Im , 2.0 ) ); mod2 = sqrt( pow( aux2.Re , 2.0 ) + pow( aux2.Im , 2.0 ) ); if( mod1 > mod2 ) return true;
else return false; }
int main(void) {
complexo n1(30,20), n2(23,20);
if(n1 > n2) cout << "n1 e' maior que n2\n"; else cout << "n1 e' menor que n2\n";
system("PAUSE"); return 0;
}
Programa 5 Outro exemplo.