| 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" 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. |
| © 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 | | |