You are on page 1of 6

Professora Isabel Harb Manssour Linguagem de Programao C++

44

12. SOBRECARGA DE OPERADOR


Uma forma de C++ alcanar o polimorfismo por meio do uso de sobrecarga de funo. A sobrecarga, simplificadamente, consiste na redefinio de itens j existentes. Em outras palavras, ela permite que sejam definidas duas ou mais funes com o mesmo nome, desde que suas listas de argumentos sejam suficientemente diferentes para as chamadas a serem resolvidas. Nesta situao, quando diversas declaraes de funes diferentes so especificadas por um nico nome no mesmo escopo, diz-se que as funes que compartilham o mesmo nome esto sobrecarregadas. Quando esse nome utilizado, a funo correta selecionada pela comparao dos tipos dos argumentos reais com os tipos dos argumentos formais. Um exemplo prtico de sobrecarga de funes ilustrado pelo programa a seguir. C e C++ no contm funes de bibliotecas que pedem ao usurio para digitar e aguardar uma resposta. Entretanto, este programa cria trs funes chamadas "prompt()" que efetuam essa tarefa para dados do tipo int, double e long:
#include <iostream> using namespace std; void prompt (char *str, int *i); void prompt (char *str, double *d); void prompt (char *str, long *l); main() { int i; double d; long l; prompt("Digite um inteiro: ", &i); prompt("Digite um double: ", &d); prompt("Digite um long: ", &l); cout << i << " " << d << " " << l; } void prompt (char *str, int *i) { cout << str; cin >> *i; } void prompt (char *str, double *d) { cout << str; cin >> *d; } void prompt (char *str, long *l) { cout << str; cin >> *l; }

A sobrecarga de funes importante porque pode ajudar a gerenciar a complexidade. Para compreender como, considere o seguinte exemplo. O Borland C++ contm as funes "atoi()", "atof()" e "atol()" em sua biblioteca padro. Coletivamente, essas funes convertem uma string para diferentes tipos de nmeros equivalentes (int, double e long). Embora estas funes realizem aes quase idnticas, em C trs nomes diferentes precisam ser usados para representar essas tarefas, o que torna a situao mais complexa do que realmente . Em outras palavras, mesmo que o conceito subjacente de cada funo seja o mesmo, o programador deve lembrar de trs nomes. Entretanto, em C++ possvel usar o mesmo nome para todas as trs funes. Assim, o nome representa a ao geral que est sendo realizada e o compilador escolhe a verso especfica para uma determinada circunstncia. Portanto, aplicando-se sobrecarga, trs nomes para memorizar so reduzidos a um. Esta seo apresenta a sintaxe e a semntica para a sobrecarga de operadores. Baseando-se nos conceitos definidos, a sobrecarga de operador consiste na redefinio de seu significado para tipos diferentes daqueles com os quais ele tinha sido previamente definido. Por meio da sobrecarga de operadores, o programador pode redefinir o significado da maior parte dos operadores de C++, quando pelo menos um operando um objeto de classe. Isto , em geral, pode-se sobrecarregar os operadores de C++ definindo o que eles significam em relao a uma classe especfica [2, 9, 10].

Professora Isabel Harb Manssour Linguagem de Programao C++

45

Torna-se importante salientar, tendo em vista que, para qualquer tipo "T", um "T" e um "T&" aceitam o mesmo conjunto de valores de inicializadores, funes com tipos de argumentos que diferem apenas por esse aspecto no podem ter o mesmo nome. Exemplo [2]:
int F (int i) { ... } int F (int& r) { ... } // erro: tipos de funes no so // suficientemente diferentes

Antes da descrio de sobreposio de operadores, til rever alguns conceitos sobre operadores. O que um operador algo trivial. Por exemplo, o sinal de mais (+) um operador que adiciona dois valores, e o sinal de menos (-) um operador que subtrai dois valores. Estes e outros operadores semelhantes so denominados operadores binrios, porque operam sobre dois argumentos. Alguns outros, tais como o operador de negao (!), so unrios, pois eles requerem apenas um nico argumento [4]. Um dos grandes poderes do C/C++, o seu pequeno tamanho, muito se deve utilizao da sobrecarga de operadores. Por exemplo, o operador "*" pode significar, dependendo do contexto, multiplicao, contedo de ponteiro ou declarao de ponteiro. Esta sobrecarga no operador "*" inerente linguagem C e no pode ser modificada pelo programador, ou seja, no se pode acrescentar novas definies ao smbolo "*". Infelizmente, a linguagem C no permite tambm a utilizao direta do operador de adio "+" para tipos criados pelo usurio. Assim, considerando estes tipos, deve-se executar uma declarao como:
s = soma (a, b);

Contudo, a forma mais clara de se realizar a operao seria:


s = a + b;

Em C++, possvel implementar esta ltima declarao. Para tal, deve-se sobrecarregar o operador de adio "+" [9]. Uma restrio que deve-se conhecer, que no se pode criar operadores. O C++ permite apenas novas definies para os operadores j existentes. Alm disso, nem todos os operadores podem ser sobrecarregados. A tabela a seguir mostra os operadores passveis de sobrecarga em C++. Operadores unrios so aplicveis a somente um operando, enquanto operadores binrios envolvem dois operandos. Em C++ no existem operadores sobrecarregveis de ordem maior que dois. Operadores Unrios ++ -~ ! Operadores Binrios * / + % ^ & | = < > , /= += -= *= %= ^= &= |= << >> >>= <<= != <= >= == [] () || && -> ->* new delete Operadores Unrios ou Binrios & * + Alm de no se poder criar operadores e s poder sobrecarregar aqueles que a linguagem permite, h mais restries que devem ser conhecidas. Primeira, o operador sobrecarregado no pode alterar as regras de precedncia e associatividade que o C e o C++ estabeleceram para a definio original. Segunda, ao menos um dos parmetros da funo operadora dever ser objeto de classe, o que significa que no se pode redefinir as operaes para os tipos da linguagem. Terceira, no se pode combinar sobrecargas para gerar uma terceira funo operadora.

Professora Isabel Harb Manssour Linguagem de Programao C++

46

Existe duas formas de se definir sobrecarga de operadores em C++: declarando-a como funo membro ou friend da classe que a utilizar. H uma pequena diferena entre as sintaxes de declarao e definio da sobrecarga em cada forma. Inicialmente, sero observadas as sintaxes gerais e, posteriormente, sero discutidas estas diferenas. As sintaxes so as seguintes: Sobrecarga como funo membro Declarao:
class Nome_Classe { ... <tipo_retorno> operator op (<lista_de_parametros>); };

Definio:
<tipo_retorno> Nome_Classe :: operator op (<lista_de_parametros>) { // definio da funo membro }

Sobrecarga como funo amiga Declarao:


class Nome_Classe { ... friend <tipo_retorno> operator op (<lista_de_parametros>); };

Definio:
<tipo_retorno> operator op (<lista_de_parametros>) { // definio da funo friend }

Observando-se as declaraes de sobrecarga, conclui-se que elas so muito semelhante sintaxe de declarao de qualquer funo membro. A diferena est na incluso da palavra-chave operator e no nome da funo ("op") que, na sobrecarga, o operador sobrecarregado. A palavra reservada operator identifica uma funo operadora. <tipo_retorno> consiste em algum tipo conhecido da linguagem, porm, geralmente, a prpria classe para a qual o operador est sendo redefinido. Deve-se ter cuidado com o retorno do operador e lembrar-se de como este utilizado originalmente. Por exemplo, se o operador de atribuio "=" for sobrecarregado para uma classe String, possvel que se queira continuar fazendo atribuies encadeadas, tais como:
String str1, str2, str3("Exemplo"); str1 = str2 = str3;

Se a sobrecarga declarar o retorno como void, ser impossvel fazer esta atribuio encadeada [9]. Torna-se importante salientar que o significado de operadores aplicados a tipos que no sejam classes no pode ser redefinido. A inteno tornar C++ extensvel, mas no mutvel. Isso protege o programador de C++ dos abusos mais bvios da sobrecarga de operadores, tais como redefinir + em inteiros para indicar subtrao [2]. Os nomes das funes sobrepostas podem ser, por exemplo, "operador+", "operador-" e "operador*". Normalmente, no permitido usar smbolos como +, - e * em identificadores, porm, para o caso especial de sobreposio de operadores, o C++ permite que o nome de funo consista na palavra reservada operator e em um dos smbolos apresentados na tabela anterior. Um exemplo prtico de uma classe que utilize operadores sobrepostos ajudar a ilustrar os conceitos apresentados nesta seo. A listagem a seguir (strop1.cpp) mostra o incio de uma classe que pode armazenar valores inteiros no formato de strings. Usando operadores sobrepostos, declarados como funo friend, o programa pode avaliar expresses que adicionam strings sem precisar convert-las para valores numricos.

Professora Isabel Harb Manssour Linguagem de Programao C++


// strop1.cpp # include <iostream> # include <stdlib.h> # include <string.h> using namespace std; class strop { char value[12]; public: strop(); strop(const char *s); friend long operator+ (strop a, strop b); friend long operator- (strop a, strop b); }; strop::strop() { value[0] = 0; } strop::strop(const char *s) { strncpy (value, s, 11); value[11] = 0; } void main () { strop a = "1234"; strop b = "4321"; cout << "\n a + b + 6 == " << (a + b + 6); cout << "\n a - b + 10 ==" << (a - b + 10); } long operator+ (strop a, strop b) { return ( atol(a.value) + atol(b.value) ); } long operator- (strop a, strop b) { return ( atol(a.value) - atol(b.value) ); }

47

O programa "strop1.cpp" apenas um exemplo simples de sobreposio de operadores e o programa demandaria um trabalho extenso para se tornar prtico. Porm, ele ilustra diversas regras importantes. A classe "strop" armazena caracteres num pequeno vetor de tipo char, que grande o suficiente para armazenar 11 dgitos e um delimitador NULL - espao para o menor valor possvel do tipo long, -2147483648, no formato de um string. Os dois construtores fornecem os meios para inicializar novas instncias do tipo "strop". O primeiro construtor cuida da definio de uma varivel default. O segundo permite a criao de variveis a partir de linhas como as definidas no incio da main. As duas funes friend sobrepem os operadores de adio e subtrao para instncias do tipo da classe e retornam um tipo long. Tipicamente, funes de operadores sobrepostos retornam o mesmo tipo que suas classes (ou uma referncia a uma instncia da classe). Mas isto no obrigatrio, funes de operadores sobrepostos podem retornar qualquer tipo de dado. Em primeiro lugar o programa define duas instncias "a" e "b" do tipo da classe, atribuindo a essas instncias os strings "1234" e "4321", respectivamente. As instrues de fluxo de sada de dados usam estas instncias nas expresses "a + b + 6" e "a - b + 10". Estas expresses somam e subtraem strings e valores inteiros, o que normalmente os operadores de mais e menos no podem fazer. As funes de operadores sobrepostos foram declaradas como friends e no como funes membro. Por isso suas implementaes so idnticas a de outras funes comuns do C++. As nicas diferenas so os nomes de funo especiais "operator+" e "operator-", que permitem ao compilador avaliar expresses com os operadores de mais e de menos e instncias da classe "strop". Em "strop1.cpp", ento, as duas funes de operadores sobrepostos, "operator+" e "operator-", so declaradas como amigas em comum. Um outro modo de alcanar o mesmo objetivo de sobrepor os operadores de mais e menos (e outros) listar as funes como membro da classe. A prxima listagem, "strop2.cpp", similar a anterior, porm mostra como sobrepor operadores como funes membro. Comparar os dois programas ajudar na deciso de qual dos dois mtodos apropriado para cada aplicao.

Professora Isabel Harb Manssour Linguagem de Programao C++


// strop2.cpp # include <iostream> # include <stdlib.h> # include <string.h> using namespace std; class strop { char value[12]; public: strop(); strop(const char *s); long operator+ (strop b); long operator- (strop b); }; strop::strop() { value[0] = 0; } strop::strop(const char *s) { strncpy (value, s, 11); value[11] = 0; } long strop :: operator+ (strop b) { return ( atol(value) + atol(b.value) ); } long strop :: operator- (strop b) { return ( atol(value) - atol(b.value) ); } void main () { strop a = "1234"; strop b = "4321"; cout << "\n a + b + 6 == " << (a + b + 6); cout << "\n a - b + 10 ==" << (a - b + 10); }

48

Os prottipos das funes de operadores sobrepostos da classe "strop" podem ser comparados com as funes friend equivalentes de "strop1.cpp". Como as funes em "strop2.cpp" so membros, elas j possuem acesso aos campos privados e protegidos da classe. Alm disso, recebem um ponteiro this para a instncia que chama as funes. Assim sendo, precisam apenas de parmetros individuais. Para adicionar dois strings "values", as funes combinaro "this->value" com "b.value". No h necessidade de passar dois parmetros para as funes como existia em "strop1.cpp". De fato, faz-lo um erro, pois operadores binrios tais como + e - requerem dois e apenas dois parmetros. No "strop1.cpp" os dois parmetros so necessrios porque as funes friend no so membros e, portanto, no recebem ponteiros this para instncias da classe. Pode-se notar que a funo main() de "strop2.cpp" exatamente a mesma de "strop1.cpp". No importando se as funes de operadores sobrepostos sejam declaradas como amigas ou como membros da classe, isso no afeta o modo desses operadores serem utilizados em expresses. J as implementaes de funo sobrepostas em "strop2.cpp" diferem muito pouco daquelas encontradas em "strop1.cpp". Como as novas funes so membro, so rotuladas com o nome de classe "strop::". Alm dessa mudana, as instrues agora fazem referncias diretas ao campo "value" das instncias para qual as funes foram chamadas. A referncia ao segundo argumento, "b.value", a mesma de antes. Operadores unrios, tais como o sinal de menos unrio e !, operam sobre um argumento. Assim como operadores binrios, pode-se declarar uma funo de operador unrio sobreposto como friend ou membro da classe. Para sobrepor um operador unrio com uma funo friend, deve-se listar apenas um parmetro do tipo da classe. Por exemplo, pode-se acrescentar a seguinte declarao em "strop1.cpp" na declarao da classe, junto com as outras funes friend:
friend long operator- (strop a);

Ainda que a funo friend declarada anteriormente na classe j faa uma sobreposio ao operador de subtrao, como a nova declarao especifica apenas um parmetro, no h conflito. Essa no uma regra especial. apenas uma conseqncia da sobreposio de funes que, como j citado anteriormente, permite que vrias funes compartilhem o mesmo nome desde que as declaraes de funo difiram em pelo menos um parmetro.

Professora Isabel Harb Manssour Linguagem de Programao C++

49

A implementao da funo sobreposta retorna a negao do campo "value" do parmetro "a". As linhas abaixo tambm podem ser acrescentadas em "strop1.cpp" para exemplificar o funcionamento de sobreposio de operadores unrios.
main() { : cout << "\n -a ==" << -a; } long operator- (strop a) { return -atol (a.value); }

Assim como operadores binrios sobrepostos, pode-se tambm declarar operadores unrios sobrepostos como funes membros. Para ilustrar pode-se colocar o seguinte comando na declarao da classe em "strop2.cpp":
long operator-(void);

Isto equivalente funo unria friend acrescentada a "strop1.cpp" anteriormente. Mas, nesse caso, a funo declarada como membro da classe "strop". Como todas as funes membro recebem um ponteiro this para a instncia para a qual as funes foram chamadas, a funo "operator-" pode operar diretamente sobre o campo "value" de uma instncia "strop". Por essa razo, a funo no necessita de quaisquer parmetros. Ela no deve ter nenhum parmetro, ou o C++ no reconhecer a funo como sendo um operador unrio sobreposto. Para implementar a funo, as seguintes linhas devem ser acrescentadas em "strop2.cpp":
long strop :: operator- (void) { return -atol (value); } main() { : cout << "\n -a ==" << -a; }

No importa se declarada uma funo de operador unrio sobreposto como friend ou como membro da classe, pode-se usar essa funo da mesma maneira. Como a classe define uma operao para o menos unrio, o C++ pode avaliar a expresso "-a" para gerar a negao de um valor long representado como um string de caracteres [4].

You might also like