Endentendo C++
Sobrecarga de operador

No tutorial anterior nós implementamos uma versão da classe Mint, e finalizamos com o código que calcula elementos da seqüência Fibonacci. O código usado para executar o cálculo era
void main()
{
Mint max("100");
Mint counter("1"), one("1");
Mint t1("0"), t2("1");
Mint d;
 
do
{
d.Add(t1,t2);
t1=t2;
t2=d;

counter.Add(counter,one);
} while (!counter.Equal(max));
d.Print();
}
O desejável é que pudéssemos escrever esse mesmo código de modo semelhante a um código normal. Como o seguinte:
void main()
{
Mint max("100");
Mint counter("1");
Mint t1("0"), t2("1");
Mint d;
 
do
{
d = t1 + t2;
t1=t2;
t2=d;
counter = counter + "1";
} while (! (counter==max));
cout << d << endl;
}
C++ permite esse tipo de operação com novos tipos de dados usando um processo denominado sobrecarga de operador. Os operadores normais, como +, == e << são sobrecarregados e passam a manejar também os novos tipos de dados.

Alguns casos de sobrecarga de operador envolvem o uso de funções friend. Uma função friend é como uma função C normal, mas tem a permissão de acessar membros private da classe dentro da qual é declarada. O fato de ser como uma função C significa que ela não tem acesso ao pointer this, e também que pode ser chamada sem que se identifique a classe para a qual ela opera. Por exemplo, uma função membro normal, tal como a função Insert da classe List, requer um instanciação de List para que possa ser chamada.

List lst;
...
lst.Insert(5);
Uma função friend não requer necessariamente a instanciação de uma classe porque ela não tem acesso ao pointer this.

Quase todos os operadores em C++ podem ser sobrecarregados:

+ - * / % ^ & |
~ ! , = < > <= >=
++ -- << >> == != && ||
+= -= /= %= ^= & = |= *=
<<= >>= [ ] ( ) -> ->* new delete
Alguns desses operadores são usados raramente, e mais raramente ainda são sobrecarregados. Mas sobrecarregando os operadores mais comuns, como + e == você pode dar à suas classes interfaces mais simples e auto-explicativas.

O código seguinte mostra a classe Mint reformulada para usar os operadores +, == e << sobrecarregados, e ainda um trecho de código para testar o uso desses três operadores.

class Mint: public List
{
public:
Mint():List() {}
Mint(char *s):List()
{
char *p;
for (p=s; *p; p++)
AddToEnd(*p-'0');
}
 
friend Mint operator+ (Mint & a, Mint & b)
{
int carry, temp;
int erra, errb, na, nb;
Mint x;
 
carry=0;
erra=a.GetLast(na);
errb=b.GetLast(nb);
while (!erra || !errb)
{
if (erra)
temp=nb+carry;
else if (errb)
temp=na+carry;
else
temp=na+nb+carry;
x.AddToFront(temp%10);
carry=temp/10;
erra=a.GetPrevious(na);
errb=b.GetPrevious(nb);
}
if (carry> 0)
x.AddToFront(carry);
return x;
}
 
int operator==(Mint & a)
{
if (a.Size()!=Size())
return 0;
else
{
int i, na, nb;
a.GetFirst(na);
GetFirst(nb);
for (i=0; i < a.Size(); i++)
if (na!=nb)
return 0;
else
{
a.GetNext(na);
GetNext(nb);
}

return 1;
}
}
 
friend ostream&  operator << (ostream&  s, Mint & m)
{
int n, err;
 
err=m.GetFirst(n);
while( !err )
{
s << n;
err=m.GetNext(n);

return s;
}
};
 
void main()
{
// add two numbers
Mint a("1234567");
Mint b("1234");
Mint c;
 
c = a + b;
cout << "it's fine " << c << "...really" << endl;
cout << a + "3333" << endl;
 
// find the 100th Fibonacci number
Mint counter;
Mint t1, t2;
Mint d;
 
t1 = "0";
t2 = "1";
counter = "1";
do
{
d = t1 + t2;
t1 = t2;
t2 = d;
counter = counter + "1";
} while (! (counter == "100") );
cout << d << endl;
}
Vamos começar examinando a função ==:

int operator== (Mint & a)

Porque esta é uma função membro da classe Mint, esse cabeçalho da função indica que o operador deve retornar um inteiro, que usa o que está a esquerda de == como this, e que usa o que está a direita de == como um a. Dentro do código para a função do operador ==, quando nós usamos diretamente uma outra função, como GetFirst, nós estamos nos referindo ao valor a esquerda de ==. Ao contrário, uma chamada de função no formato a.GetFirst refere-se ao que está à direita de ==:

Mint b, m;
...
if (b == m)
O restante do código é idêntico ao da função Equal que vimos no Tutorial 5. O valor inteiro de retorno é usado como resultado da comparação. Uma vez implementada essa função, nosso operador == é chamado sempre que o compilador encontra um operador == entre dois valores do tipo Mint.

O operador + sobrecarregado é uma função friend:

friend Mint operator+ (Mint & a, Mint & b)

Essa função é declarada como uma friend porque nós não queremos que ela use automaticamente o lado esquerdo do sinal de soma, porque essa função limpa a variável destinada ao resultado da soma, como já vimos no Tutorial 5. Uma vez definida como uma função friend, ela se comporta como uma função C normal, sem acesso ao pointer this. Ela apenas soma os dois números mint que lhe forem passados, e retorna o resultado no formato de um número mint.

Na função main há vários comandos com a seguinte forma:

c = "3333"

ou

c = c + "1"

Como o compilador sabe o que fazer? Como ele sabe converter um "1" para um mint? Uma vez que tenhamos um construtor que aceita um tipo char*, o construtor é automaticamente invocado na tentativa de fazer a combinação de tipos para o operador +. Se nós criarmos outro construtor que aceite um parâmetro do tipo inteiro longo, então poderemos escrever comandos como

c = c + 1;

A conversão do valor inteiro 1 será automática. O seguinte comando não vai funcionar:

c = "2222" + "3333";

porque o compilador não tem nada que lhe diga que + significa a adição de mints, portanto ele não pode fazer a conversão de tipos - um dos lados de + deve ser um mint para alertar o compilador.

O operador << também está sobrecarregado. A função para sobrecarregá-lo deve ser uma friend porque o parâmetro a esquerda não é do mesmo tipo da classe. A função deve aceitar uma referência para um parâmetro ostream e um parâmetro do tipo da classe. Deve ainda retornar uma referência para ostream.

Com essa função implementada, qualquer operação de saída em C++ vai funcionar normalmente com números mint.

O operador >> é sobrecarregado de modo similar:

friend istream& operator >> (istream& s, Mint&  m)
{
buf[100];
 
s >> buf;
m = buf; // calls the constructor
return s;
}
Outros operadores, tais como ++, +=, !=, etc podem ser facilmente sobrecarregados usando os exemplos acima.
Topo Índice
© 1998 Interface Technologies, Inc by Marshall Brain
Tradução de Dagoberto Haele Arnaut

| Home | Bookmarks | Universidades | Para Saber mais | Universidades | WEB Directory | Mapa do site |