Home
Capítulo 7 - iscte-iul
Contents
1. include lt fstream gt Programa de teste do TAD Racional eda fun o mdc int main assert mdc 0 0 assert mdc 10 0 10 assert mdc 0 10 10 assert mdc 10 10 10 assert mdc 3 7 1 assert mdc 8 6 2 assert mdc 8 6 2 assert mdc 8 6 2 assert mdc 8 6 2 Racional r1 2 6 assert rl numerador 1 and r1l denominador 3 Racional r2 3 Uma das caracter sticas das instru es de asser o que pode ser desactivadas facilmente bastando para isso definir a macro NDEBUG No entanto n o muito boa ideia desactivar as instru es de asserc o Ver discuss o sobre o assunto no citar cap tulo sobre tratamento de erros 348 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C assert r2 numerador 3 and r2 denominador 1 Racional r3 assert r3 numerador 0 and r2 denominador 1 assert r2 3 assert 3 r2 assert r3 0 assert 0 r3 assert rl lt r2 assert r2 gt rl assert rl lt r2 assert r2 gt rl assert rl lt rl assert 12 gt r2 assert r2 12 assert rl Racional 1 3 assert r1 Racional 2 3 assert rl Racional 2 3 assert rl Racional 2 3 assert rl Racional 5 3 assert rl Racional 7 20 Racional 7 12 assert rl Ra
2. Incrementa o racional recebido como argumento devolvendo o seu valor an tes de incrementado pre this r post operator r A this r 1 Racional const operator Racional amp r int valor_a_ignorar 7 11 CONST NCIA VERIFICANDO ERROS DURANTE A COMPILA O 387 Racional const c pia r r return c pia Decrementa o racional recebido como argumento devolvendo o seu valor an tes de decrementado pre this r postoperator r this r 1 Racional const operator Racional amp r int Racional const c pia r r return c pia Ficaram a faltar ao TAD Racional os operadores e un rios Come ar se pelo segundo O operador un rio pode ser sobrecarregado quer atrav s de uma opera o da classe C Racional class Racional public Devolve sim trico do racional pre V post operator this Racional const operator const Racional const Racional operator const 388 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C assert cumpreInvariante Racional r r numerador numerador_ r denominador denominador assert r cumpreInvariante returns quer atrav s de uma fun o normal Racional const operator Racional const amp r return Racional r numerador r denominador Embora a segunda vers o seja muito mais simples ela implica a invoca o do construtor mais complicado da classe C que verif
3. assert cumpreInvariante return numerador_ int Racional denominador assert cumpreInvariante assert cumpreInvariante return denominador s opera es de uma classe C que se limitam a devolver propriedades das suas inst ncias chama se inspectores Invoc las tamb m se diz interrogar a inst ncia Os inspectores permitem obter os valores de propriedades de um inst ncia sem que se exponham as suas partes privadas manipula o pelo p blico em geral de notar que a introdu o destes novos operadores trouxe um problema pr tico As novas opera es t m naturalmente o nome que antes tinham os atributos da classe Repare se que n o se decidiu dar outros nomes s opera es para evitar os conflitos que produz uma classe deve estar preparado para em nome do fornecimento de uma interface t o clara e intuitiva quanto poss vel fazer alguns sacrif cios Neste caso o sacrif cio o de alterar o nome dos atributos aos quais comum acrescentar um sublinhado para os distinguir de opera es com o mesmo nome e sobretudo alterar os nomes desses atributos em todas as opera es entretanto definidas e note se que j s o algumas 7 10 2 Operadores de igualdade e diferen a Os inspectores definidos na sec o anterior s o providenciais pois permitem resolver facil mente o problema do acesso aos atributos Basta recorrer a eles para comparar os dois racio nais Indica se dois
4. Vector b for int i 0 i 3 i Vector cout lt lt Existem lt lt Vector n meroDeInst ncias lt lt inst ncias lt lt endl static Vector d 438 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C cout lt lt Existem lt lt Vector n meroDeInst ncias lt lt inst ncias lt lt endl cout lt lt Existem lt lt C n meroDeInst ncias lt lt inst ncias lt lt endl de notar que a invoca o da opera o de classe C Vector n meroDeInst ncias faz se n o atrav s do operador de selec o de membro o que implicaria a invoca o da ope ra o atrav s de uma qualquer inst ncia da classe C mas atrav s do operador de resolu o de mbito No entanto tamb m poss vel se bem que in til invocar opera es de classe atrav s do operador de selec o de membro As mesmas observa es se podem fazer no que diz respeito aos atributos de classe A execu o do programa acima teria como resultado Existem inst ncias Existem inst ncias Existem inst ncias Existem inst ncias NO 4 a G Existem inst ncias De aqui em diante utilizar se a express o membro como significando membro de inst n cia i e membros dos quais cada inst ncia da classe C a que pertencem possui uma c pia pr pria usando se sempre a express o membro de classe para os membros partilhados entre todas as inst
5. Racional const amp r2 Racional const amp r2 Racional const amp r2 cional const r Racional amp r 430 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C r extraiDe entrada return entrada tifdef TE STE tinclude lt fstream gt Programa de teste do TAD Racional eda fun o mdc int main assert mdc 0 0 assert mdc 10 O assert mdc 0 10 assert mdc 10 10 assert mdec 3 7 assert mdc 8 6 assert mdc 8 6 assert mdc 8 6 assert mdc 8 6 Racional r1 2 6 assert r1 numerado Racional r2 3 assert r2 numerado Racional r3 assert r3 numerado assert 12 3 assert 3 r2 assert r3 O assert 0 r3 assert rl lt r2 assert r2 gt rl assert rl lt r2 assert r2 gt rl assert rl lt rl assert r2 gt r2 NI m NI NP T r 1 and rl denominador 3 r 3 and r2 denominador 1 r 0 and r2 denominador 1 7 16 C DIGO COMPLETO DO TAD RACIONAL assert r2 r2 assert rl Racional 1 3 assert r1 Racional 2 3 assert rl Racional 2 3 assert rl Racional 2 3 assert rl Racional 5 3 assert rl Racional 7 20 Racional 7 12 assert rl Racional 3 4 Racional 7 9 assert rl Racional 11 6 Racional 47 18 assert rl Raciona
6. class Racional public Extrai do canal um novo valor para o racional na forma de dois inteiros suces sivos Opre this r post Se entrada e entrada tem dois inteiros n e d dispon veis para lei tura com d 0 ent o this Z A entrada sen o 406 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C this rA entrada void extraiDe istream amp entrada y void Racional extraiDe istream amp entrada assert cumpreInvariante nt DA if entrada gt gt n gt gt d if d 0 entrada setstate ios_base failbit else numerador d lt 0 n n denominador d lt 0 d d reduz assert cumpreInvariante assert numerador_ d n denominador and cin return assert cumpreInvariante assert not entrada Extrai do canal um novo valor para o racional na forma de dois inteiros sucessivos Qpre r r postSe entrada e entrada tem dois inteiros n e d dispon veis para leitu ra com d 0 ent o XE j A entrada sen o r rhA entrada istream amp operator gt gt istreams entrada Racional amp r r extraiDe entrada 7 14 OPERADORES DE INSER O E EXTRAC O 407 return entrada Neste caso a vantagem de implementar a rotina operator gt gt custa de uma opera o corres pondente na classe C fica mais clara Como a rotina operator gt gt n o pode ser membro da classe e no entanto necessita de alterar os atributos d
7. importante pois as verifica es da pr condi o e da condi o objectivo podem obrigar invoca o de outras opera es p blicas da classe que por sua vez verificam a condi o invariante de classe se a ordem fosse outra o erro surgiria durante a execu o dessas outras opera es 2Parece haver aqui uma contradi o N o ser toda a documenta o parte da interface A resposta sim plesmente n o Para uma classe podem se gerar tr s tipos de documenta o A primeira diz respeito de facto interface e inclui todos os membros p blicos a documenta o necess ria ao programador consumidor A segunda diz respeito categoria de acesso protected e deixar se para mais tarde A terceira diz respeito implementa o e inclui os membros de todas as categorias de acesso a documenta o necess ria ao programa dor produtor ou pelo menos assist ncia t cnica i e aos programadores que far o a manuten o do c digo existente Assim a condi o invariante de classe deveria ser parte apenas da documenta o de implementa o Excepto para opera es de classe 7 4 CLASSES C COMO M DULOS 337 e Separaram se as instru es de asser o relativas a pr condi es condi es objectivo e condi es invariantes de classe de modo a ser mais bvia a raz o do erro no caso de o programa abortar e A fun o membro privada cumpreInvariante n o tem qualquer instru o de a
8. inline int Racional numerador const assert cumpreInvariante return numerador_ inline int Racional denominador const assert cumpreInvariante return denominador_ 423 424 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C inline Racional const amp Racional operator const assert cumpreInvariante return this inline Racional const Racional operator const assert cumpreInvariante Racional r r numerador_ numerador_ r denominador_ denominador_ assert r cumpreInvariante return E inline void Racional insereEm ostream amp sa da const assert cumpreInvariante sa da lt lt numerador_ if denominador 1 sa da lt lt lt lt denominador_ void Racional extraiDe istream amp entrada assert cumpreInvariante int n int d 1 if entrada gt gt n if entrada peek numerador_ n denominador 1 else if entrada get and isdigit entrada peek and entrada gt gt d and d 0 7 16 C DIGO COMPLETO DO TAD RACIONAL 425 numerador d lt 0 n n denominador_ d lt 0 d d reduz else if entrada entrada setstate ios_base failbit assert cumpreInvariante assert numerador_ d n denominador_ or not entrada Racionals Racional operator Racional const amp r2 assert cumpreInvariante and r2 cumpreInvaria
9. o DTESTE Este assunto ser visto com rigor no Cap tulo 9 onde se ver tamb m como se pode preparar um TAD como o tipo Racional para ser utilizado em qualquer programa onde seja necess rio trabalhar com racionais 7 7 Devolu o por refer ncia Come ar se o desenvolvimento dos operadores para o TAD Racional pelo operador de incrementa o prefixo Uma quest o nesse desenvolvimento saber o que que devolve esse operador e de uma forma mais geral todos os operadores de incrementa o e decrementa o prefixos e especiais de atribui o 7 71 Mais sobre refer ncias Na Sec o 3 2 11 viu se que se pode passar um argumento por refer ncia a um procedimento se este tiver definido o par metro respectivo como uma refer ncia Por exemplo void troca int amp a int amp b int auxiliar a a b b auxiliar um procedimento que troca os valores das duas vari veis passadas como argumento Este procedimento pode ser usado no seguinte tro o de programa 350 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C int x 1 y 2 troca x y Conti lt lt x lt lt T lt p X lt endL que mostra no ecr O conceito de refer ncia pode ser usado de formas diferentes Por exemplo int i 1 inte j i apartirdaqui j sin nimo de i j a cout lt lt i lt lt endl mostra no ecr pois alterar a vari vel j o mesmo que alterar a vari vel i
10. r Defineo TAD Racional e uma vari vel r numa nica instru o M ideia mas pos s vel Note se que esta possibilidade deve ser evitada na pr tica 7 2 TIPOS ABSTRACTOS DE DADOS E CLASSES C 307 nome da classe Racional a atributos numerador int gi denominador int tipo nome Figura 7 2 Nota o usada para representar a classe C Racional das classes com a diferen a de que no caso das classes essa informa o pode ser de tipos diferentes As vari veis de um TAD definem se como qualquer vari vel do C TAD nome express o ou TAD nomel express o Por exemplo Racional rl r2 define duas vari veis r1 e r2 n o inicializadas i e contendo lixo mais tarde se ver como se podem evitar constru es sem inicializa o em TAD Para classes C que representem meros agregados de informa o poss vel inicializar cada membro da mesma forma como se inicializam os elementos de uma matriz cl ssica do C Racional rl 6 9 Racional r2 7 3 Note se no entanto que esta forma de inicializac o deixar de ser poss vel e desej vel quan do se equipar a classe C com um construtor como se ver mais frente As instru es apresentadas constroem duas novas vari veis do tipo Racional r1 e r2 cada uma das quais com vers es pr prias dos atributos numerador e denominador s vari veis de um TAD tamb m comum chamar se objec
11. simples class Racional public Multiplica por um racional Qpre this r post operator thisA this rxr2 Racional amp operator Racional r2 y Racionals Racional operator Racional const r2 assert cumpreInvariante and r2 cumpreInvariante numerador r2 numerador denominador r2 denominador reduz assert cumpreInvariante return this O corpo do m todo definido limita se a efectuar o produto da forma usual para as frac es i e o numerador do produto o produto dos numeradores e o denominador do produto o produto dos denominadores Como os denominadores s o ambos positivos o seu produto tamb m o ser Para que o resultado cumpra a condi o invariante de classe falta apenas garantir que no final do m todo mdc n d 1 Como isso n o garantido pense se por exemplo o produto de 3 por 2 necess rio reduzir a frac o resultado Tal como no caso dos 364 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C operadores de incrementa o e decrementa o prefixo tamb m aqui se termina devolvendo a vari vel impl cita i e o primeiro operando O operador sobrecarrega se da mesma forma embora tenha de haver o cuidado de garantir que o segundo operando n o zero class Racional public Divide por um racional Opre this rAr2 0 post operator this A this r r2 Racional amp operator Racional r2 y Racional
12. void Racional extraiDe istream amp entrada Extrai do canal um novo valor para o racional na for ma de uma frac o 416 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C pre r r post Se entrada e entrada cont m n d ou ape nas n assumindo se d 1 em que n e d s o inteiros com d 0 ent o r Mentrada sen o r rA zentrada istream amp operator gt gt istream entrada Racional amp r assert r cumpreInvariante int n int d 1 if entrada gt gt n if entrada peek r numerador_ n r denominador_ 1 else if entrada get and isdigit entrada peek and entrada gt gt d and d 0 r numerador d lt 0 2 n nm r denominador_ d lt 0 d d reduz else if entrada entrada setstate ios base failbit assert r cumpreInvariante assert r numerador_ d n r denominador or not canal return entrada Como a rotina definida n o membro da class C Racional n o tem acesso aos seus mem bros privados Para resolver este problema pode se usar o conceito de amizade se a classe C Racional declarar que amiga e por isso confia nesta rotina ela passa a ter acesso total s suas partes ntimas Para o conseguir basta colocar o cabe alho da rotina em qualquer ponto da defini o da classe C precedendo a do qualificador friend Para o compilador irrelevante se a
13. 336 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C return CIC Implementa o da opera o opera o m todo tipo Classe opera o privada par metros assert PO Implementa o assert CO Tetu que S o de notar os seguintes pontos importantes e A condic o invariante de classe foi inclu da na documentac o da classe que parte da sua interface apesar de antes se ter dito que esta condic o era essencialmente uma ques t o de implementac o de facto infeliz que assim seja mas os programas que extraem automaticamente a documentac o de uma classe e g Doxygen requerem este posicio namento e A documentac o das operac es n o inclui a condic o invariante de classe visto que esta foi posta em evid ncia ficando na documentac o da classe e A implementa o das opera es i e o respectivo m todo inclui instru es de asser o para verificar a condi o invariante de classe para todas as inst ncias da classe em jogo que incluem a inst ncia impl cita par metros inst ncias locais ao m todo etc quer no in cio do m todo quer no seu final e Asinstru es de asser o para verificar a veracidade da condi o invariante de classe s o anteriores quer instru o de asser o para verificar a pr condi o da opera o quer instru o de asser o para verificar a condi o objectivo da opera o Esse posiciona mento
14. Por exemplo o inspector Racional numerador deve ser qualificado como n o alterando a inst ncia impl cita class Racional public Devolve numerador da frac o can nica correspondente ao racional Qpre V numerador _ _ 4 post genominadorO this int numerador const int Racional numerador const assert cumpreInvariante 7 11 CONST NCIA VERIFICANDO ERROS DURANTE A COMPILA O 383 assert cumpreInvariante return numerador importante perceber que o compilador verifica se no m todo correspondente a uma opera o constante que o nome que se d a uma opera o que garante a const ncia da inst ncia im pl cita se executa alguma instru o que possa alterar a constante impl cita Isso significa que o compilador pro be a invoca o de opera es n o constantes atrav s da constante impl cita e tamb m que pro be a altera o dos atributos pois os atributos de uma constante assumem se tamb m constantes o facto de a const ncia da inst ncia impl cita ser agora claramente indicada atrav s do qua lificador const e garantida pelo compilador que permitiu deixar de explicitar essa const ncia atrav s de um termo extra na pr condi o e na condi o objectivo a const ncia da inst n cia impl cita continua a estar expressa no contrato destas opera es mas agora n o na pr condi o e na condi o objectivo mas na pr pria sintaxe do cabe alho d
15. existentes Pelo contr rio os construtores s o invocados justamente para construir uma nova vari vel Do ponto de vista sint ctico os construtores t m algumas particularidades A pri meira que t m o mesmo nome que a pr pria classe Os construtores s o como que fun es membro pois t m como resultado uma nova vari vel da classe a que pertencem No entanto n o s n o se pode indicar qualquer tipo de devolu o no seu cabe alho como no seu cor po n o permitido devolver qualquer valor pois este age sobre uma inst ncia impl cita em constru o Quando uma inst ncia de uma classe constru da por exemplo devido defini o de uma vari vel dessa classe invocado o construtor da classe compat vel com os argumentos usados na inicializa o I e poss vel que uma classe tenha v rios construtores sobrecarregados facto de que se tirar partido em breve Os argumentos s o passados aos construtores colocando os entre par nteses na defini o das inst ncias Por exemplo as instru es Racional r Racional r 0 Racional r 0 1 deveriam todas construir uma nova vari vel racional com o valor zero muito embora para j s a primeira instruc o seja v lida pois a classe ainda n o possui construtores com argumentos Note se que as instru es 7 4 CLASSES C COMO M DULOS 327 Racional r Racional r n o s o equivalentes Esta irregularidade sint ctica do C deve se ao facto de
16. nico argumento da classe C Racional ie O segundo construtor usando se um segundo argumento tendo valor por omiss o um Essa convers o explicitada no caso do terceiro elemento de m2 J para o quarto e o quinto ele mentos eles s o constru dos por c pia a partir de um racional constru do usando o construtor por omiss o no primeiro caso e o construtor completo com dois argumentos no segundo ca so Note se que se a classe C em causa n o possuir construtores por omiss o obrigat rio inicializar todos os elementos da matriz explicitamente 7 17 7 Convers es para outros tipos Viu se j que ao se definir numa classe C um construtor pass vel de ser invocado com um nico argumento se fornece uma forma de convers o impl cita de tipo ver Sec o 7 9 2 Por exemplo a classe C Racional fornece um construtor que pode ser invocado com um nico argumento inteiro o que possibilita a convers o impl cita de tipo entre valores do tipo int e valores da classe Racional Racional r 1 3 if r lt 1 1convertido implicitamente de int para Racional sem haver necessidade de explicitar essa convers o Racional r 1 3 if r lt Racional 1 n o necess rio E se se pretendesse equipar a classe C Racional com uma convers o impl cita desse tipo para double i e se se pretendesse tornar o seguinte c digo v lido Racional r 1 2 double x r cout lt lt r lt lt lt lt x lt
17. o de sobrecarregar os operadores de atribui o especiais Depois definir se o os operadores aritm ticos normais Ali s no caso do operador ser uma re implementa o 7 8 1 Operadores de atribui o especiais Comecar se pelo operador de implementa o muito simples Tal como os operadores de incrementa o e decrementa o tamb m os operadores de atri bui o especiais s o mal comportados S o definidos custas de rotinas que s o mistos de fun o e procedimento ou fun es com efeitos laterais O operador n o excep o Ir ser sobrecarregado custa de uma opera o da classe C Racional pois necessita de alterar os atributos da classe Como o operador tem dois operandos o primeiro ser usado com inst ncia ali s vari vel impl cita e o segundo ser passado como argumento A opera o ter pois um nico par metro Todos os operadores de atribui o especiais devolvem uma re fer ncia para o primeiro operando tal como os operadores de incrementa o e decrementa o prefixo isso que permite escrever o seguinte peda o de c digo muito pouco recomend vel mas id ntico ao que se poderia tamb m escrever para vari veis dos tipos b sicos do C 7 8 MAIS OPERADORES PARA O TAD RACIONAL 363 Racional a 4 DL 2 v a b b Deve ser claro que este c digo multiplica a por 5 duas vezes ficando a com o valor 1 A implementa o do operador produto e atribui o
18. ou operatort a consoante o operador esteja definido como membro da classe a que a pertence ou esteja defi nido como rotina normal n o membro importante notar que 1 Quando a sobrecarga de um operador se faz por interm dio de uma opera o rotina membro de uma classe C o primeiro operando e nico no caso de uma opera o un ria numa express o que envolva esse operador n o sofre nunca convers es impl citas de tipo Em todos os outros casos as convers es impl citas s o poss veis 2 Nunca se deve alterar a sem ntica dos operadores Imagine se os problemas que traria sobrecarregar o operador para a classe C Racional como significando o produto 7 6 TESTES DE UNIDADE 345 3 Nemtodos os operadores podem ser sobrecarregados por interm dio rotinas n o membro Os operadores atribui o indexa o invoca o e gt selec o s podem ser sobrecarregados por meio de opera es rotinas membro Para todas as classes que n o os redefinam os operadores atribui o amp un rio endere o de e sequenci amento s o definidos implicitamente por isso poss vel atribuir inst ncias de classes C como a classe Racional sem para isso ter de sobrecarregar o operador de atribui o Falta agora a tarefa algo penosa de sobrecarregar todos os operadores aplic veis a racionais Porqu Porque apesar de o programa da soma das frac es n o necessitar sen o dos opera
19. 7 15 poderem admitir que os atributos das vari veis da classe C com que trabalham verificam inicialmente a condi o o que normalmente as simplifica bastante I e a condi o invariante de classe pode ser vista como parte da pr condi o quer de m todos correspondentes a opera es p blicas quer de rotinas amigas da classe C Claro que para serem bem comportadas as rotinas membro e n o membro tamb m devem garantir que a condi o se verifica para todas as vari veis da classe C criadas ou alteradas por essas rotinas Ou seja a condi o invariante de classe para cada inst ncia da classe criada ou alterada pelas mesmas rotinas pode ser vista tamb m como parte da sua condi o objectivo Tal como sucedia nos ciclos em que durante a execu o do passo a condi o invariante muitas vezes n o se verificava embora se verificasse garantidamente antes e ap s o passo tamb m a condi o invariante de classe pode n o se verificar durante a execu o dos m todos p blicos ou das rotinas amigas da classe C em causa embora se verifique garantidamente no seu in cio e no seu final Durante os per odos em que a condi o invariante de classe n o ver dadeira pode ser conveniente invocar alguma rotina auxiliar que portanto ter de lidar com inst ncias que n o verificam a condi o invariante de classe e que poder tamb m n o garantir que a mesma condi o se verifica para as inst ncias por si criadas
20. lt A soma de escreveFraccao nl cout lt lt com ts escreveFrac o n2 DAS cout e Ti escreveFracc o n dl d2 d cout lt lt lt lt endl A utiliza o de duas vari veis inteiras independentes para representar cada frac o n o per mite a defini o de uma fun o para proceder soma visto que as fun es em C podem devolver um nico valor De facto a utiliza o de m ltiplas vari veis independentes para re presentar um nico valor torna o c digo complexo e dif cil de perceber O ideal seria poder reescrever o c digo da mesma forma que se escreveria se o seu objectivo fosse ler e somar inteiros e n o frac es Sendo as frac es representa es dos n meros racionais pretende se escrever O programa como se segue int main numerador denominador cout lt lt Introduza duas frac es Racional rl r2 cin gt gt rl gt gt r2 if not cin cerr lt lt Opps A leitura dos racionais falhou lt lt en dl return 1 7 2 TIPOS ABSTRACTOS DE DADOS E CLASSES C 305 Racional r rl r2 cout lt lt A soma de lt lt rl lt lt com lt lt r2 lt lt lt lt r lt lt lt lt endl Este objectivo ir ser atingido ainda neste cap tulo 7 2 Tipos Abstractos de Dados e classes C Como representar cada n mero racional com uma vari vel apenas necess rio definir um novo tipo que se c
21. n denominador and cin return assert not cin 322 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C void Racional reduz dl assert denominador 0 int k mdc numerador denominador numerador k denominador k assert denominador 0 and mdc numerador denomina Ler frac es cout lt lt Introduza duas frac es numerador denominador Racional rl r2 r1 1g8 r2 18 if not cin cerr lt lt Opps A leitura dos racionais falhou lt lt en return 1 Calcular racional soma Racional r rl somaCom r2 Escrever resultado cout lt lt A soma de rl escreve cout lt lt com r2 escreve cout lt lt M Mm r escreve cout lt lt lt lt endl Na opera o Racional somaCom soma se a inst ncia impl cita com o argumento passa do opera o Na programa acima por exemplo a vari vel r1 da fun o main funciona como inst ncia impl cita durante a execu o do m todo correspondente opera o Racio nal somaCom e r2 funciona como argumento 7 4 CLASSES C COMO M DULOS 323 O procedimento reduz foi transformado em opera o privada da classe C que representa o TAD em desenvolvimento Tomou se tal decis o por n o haver qualquer necessidade de o consumidor do TAD se preocupar directamente com a representa o em frac o dos racionais O consumidor do TAD limita s
22. ncias da classe C Para que o resultado do programa acima seja claro necess rio recordar que e inst ncias autom ticas i e vari veis e constantes locais sem o qualificador static s o constru das quando a instru o da sua defini o executada e destru das quando o bloco de instru es na qual foram definidas termina e inst ncias est ticas globais s o constru das antes de o programa come ar e destru das depois do seu final depois de terminada a fun o main e e inst ncias est ticas locais s o constru das quando a instru o da sua defini o execu tada pela primeira vez e destru das depois do final do programa depois de terminada a fun o main 7 17 5 Construtores por omiss o Todas as classes C t m construtores A um construtor que possa ser invocado sem qualquer argumento porque n o tem qualquer par metro ou porque todos os par metros t m valo res por omiss o chama se construtor por omiss o Se o programador n o declarar qualquer 7 17 OUTROS ASSUNTOS ACERCA DE CLASSES C 439 construtor fornecido implicitamente sempre que poss vel um construtor por omiss o Por exemplo no c digo class C private Racional rl Racional r2 int is TE Jy C c nova inst ncia construtor por omiss o invocado fornecido implicitamente pelo compilador um construtor por omiss o para a classe C C Este construtor invoca os construtores por omiss o de t
23. o escreve resulte numa representa o can nica dos racionais Logo o problema poderia ser resolvido alterando apenas o m todo escreve de modo a reduzir a frac o deixando o restante c digo de se preocupar com a quest o Ou seja poder se ia relaxar a condi o invariante de classe para denominador 0 No entanto a escolha de uma condi o invariante de classe mais forte trar algumas vanta gens A primeira vantagem tem a ver com a unicidade de representa o garantida pela condi o invariante de classe escolhida a cada racional corresponde uma e uma s representa o na forma de uma frac o can nica Dessa forma muito f cil comparar dois racionais dois ra cionais s o iguais sse as correspondentes frac es can nicas tiverem o mesmo numerador e o mesmo denominador Note se que construtor e opera o construtora n o significam for osamente a mesma coisa A no o de opera o construtora mais geral e refere se a qualquer opera o que construa novas vari veis da classe C E claro que os construtores s o opera es construtoras mas uma fun o membro p blica que devolva um valor da classe C em causa tamb m o 7 4 CLASSES C COMO M DULOS 333 A segunda vantagem tem a ver com as limita es dos tipos b sicos do C Sendo os valores do tipo int limitados em C como se viu no Cap tulo 2 a utiliza o de uma representa o em frac es n o can nicas p e alguns probl
24. 1 cout lt lt lt lt r denominador main Ler frac es cout lt lt Introduza duas frac es numerador denominador Racional rl r2 l rl 16 12 if not cin cerr lt lt Opps A leitura das frac es dos racionais fa lhou lt lt endl return 1 Calcular racional soma Racional r somaDe rl r2 Escrever resultado cout lt lt A soma de escreve rl Cout lt lt com T escreve 12 cout lt lt escreve r cout lt lt lt lt endl Ao escrever este pedaco de c digo o programador assumiu dois papeis produtor e consumi dor Quando definiu a classe C Racional e a func o somaDe que opera sobre vari veis dessa classe C fez o papel de produtor Quando escreveu a fun o main assumiu o 316 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C papel de consumidor 7 3 4 Encapsulamento e categorias de acesso O leitor mais atento ter reparado que o c digo acima tem pelo menos um problema a classe Racional n o tem qualquer mecanismo que impe a o programador de colocar O zero no denominador de uma frac o Racional rl r numerador 6 r denominador 0 ou Racional rl 6 0 Isto claramente indesej vel e tem como origem o facto do produtor ter tornado p blicos os membros numerador e denominador da classe esse o significado do especificador de acesso public De facto os membros de uma cl
25. Arbitraram que para as assinaturas entre os operadores de incrementa o e decrementa o prefixo serem diferentes das respectivas vers es sufixo es tas ltimas teriam como que um operando adicional inteiro impl cito e cujo valor deve ser ignorado um pouco como se os operadores sufixo fossem bin rios Por raz es que ficar o claras mais frente definir se o os operadores de incrementa o e decrementa o sufixo como rotinas normais n o membro Comece se pelo operador de incrementa o sufixo Sendo sufixo a sua defini o assume que o operador bin rio tendo como primeiro operando o racional a incrementar e como segundo operando um inteiro cujo valor deve ser ignorado Como o operador ser sobrecarregado atrav s de uma rotina normal ambos os operandos correspondem a par metros da rotina sendo o primeiro corresponde ao racional a incrementar passado por refer ncia Incrementa o racional recebido como argumento devolvendo o seu valor an tes de incrementado Qpre this r post operator rA this r 1 Racional operator Racional r int valor a ignorar Racional const c pia r r return c pia 7 7 DEVOLU O POR REFER NCIA 361 Como a par metro valor a ignorar arbitr rio servindo apenas para compilador perce ber que se est a sobrecarregar o operador sufixo e n o o prefixo n o necess rio sequer dar lhe um nome pelo que a defini o pode ser si
26. M DULOS 329 Uma observa o atenta dos tr s construtores revela que os dois primeiros s o quase iguais enquanto o terceiro mais complexo pois necessita verificar o sinal do denominador recebido no par metro d e al m disso tem de se preocupar com a redu o dos termos da frac o Assim surge naturalmente a ideia de condensar os dois primeiros construtores num nico n o se fazendo o mesmo relativamente ao ltimo construtor custa do qual poderiam ser obtidos os dois primeiros por raz es de efici ncia A condensa o dos dois primeiros construtores num nico faz se recorrendo aos par metros com argumentos por omiss o vistos na Sec o 3 6 Representa n meros racionais class Racional public Constr i racional com valor inteiro Construtor por omiss o Qpre V Qpost this n 0 lt denominador A mdc numerador denominador 1 Racional int const n 0 Constr i racional correspondente a n d Opre d 0 Opost this A 0 lt denominador A mdc numerador denominador 1 Racional int const n int const d private Racional Racional int const n numerador n denominador 1 assert 0 lt denominador and mdc numerador denomina dor 1 and numerador n denominador Racional Racional int const n int const d numerador d lt 0 n n denominador d lt 0 d d assert d 0 reduz 330 CAP TULO 7 TIPOS A
27. O DE RACIONAIS POR FRAC ES 313 onde reduz um procedimento para reduzir a frac o que representa o racional i e uma adapta o do procedimento reduzF rac o O programa pode agora ser reescrito ser na ntegra para usar a nova classe C devendo se ter o cuidado de colocar a defini o da classe C Racional antes da sua primeira utiliza o no programa Pode se aproveitar para alterar os nomes das rotinas onde o sufixo Frac o se torna desnecess rio dado o tipo dos respectivos par metros include lt iostream gt include lt cassert gt using namespace std Devolve o m ximo divisor comum dos inteiros passados como argumento Oprem mAn n _ mdc m n mA40vnA40 post mac 1 Ri A QN int mdc int m int n Ey Representa n meros racionais class Racional public Isto magia por enquanto int numerador int denominador y Reduz a frac o que representa o racional recebido como argumento Qpre r denominador O A r r post r denominador 4 0Amdc r numerador r denominador 1Ar r void reduz Racional amp r assert r denominador 0 int k mdc r numerador r denominador r numerador k r denominador k as sert r denominador 0 and mdc r numerador r denominador 1 L do teclado um racional na forma de dois inteiros sucessivos pre r r postSe cin e cin tem dois inteiros n e d disp
28. a defini o do m todo Racional operator para inline Racional amp Racional operator Racional const amp r2 1 assert cumpreInvariante and r2 cumpreInvariante int nld2 int n2dl mdc r2 numerador_ denominador mdc numerador_ r2 denominador_ numerador_ numerador_ nld2 r2 numerador_ n2d1 denominador denomina dor n2d1 r2 denominador_ nld2 assert cumpreInvariante return this 7 13 OPTIMIZA O DOS C LCULOS COM RACIONAIS 399 7 13 3 Divis o O caso da divis o de frac es nina n X do A 0 da do di X na Emo muito semelhante ao da multiplica o sendo mesmo poss vel usar os m todos acima para a calcular Em primeiro lugar necess rio garantir que n2 0 Se no 0 a divis o n o est definida Admitindo que no 0 ent o a divis o equivalente a uma multiplica o Mm n mo do d d dina No entanto necess rio verificar se no positivo pois de outra forma o resultado da multipli ca o n o estar no formato can nico uma vez que ter denominador negativo Se 0 lt na a divis o calculada multiplicando as frac es can nicas t e 2 Se nz lt 0 multiplicam se as frac es can nicas Tt e Para garantir que o resultado est no formato can nico usa se a mesma t cnica que para a multiplica o Pode se agora actualizar a defini o do m todo Racional operator para inline Racional amp Racional operator R
29. a possibilidade de o racional n o ter denominador expl cito nomea damente quando tamb m um valor inteiro excelente ideia que o operador de extrac o consiga extrair racionais em qualquer dos formatos produzidos pelo operador de inser o Para o conseguir necess rio complicar um pouco o m todo Racional extraiDe e indicar claramente o novo formato admiss vel no contrato das rotinas envolvidas class Racional public Extraido canal um novo valor para o racional na forma de uma frac o Qpre this r 2 Tamb m se pode limpar o estado de erro de um canal usando se para isso a opera o istream clear entrada clear 410 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C postSe entrada e entrada cont m n d ou apenas n assumindo se d 1 em que n e d s o inteiros com d 4 0 ent o this entrada sen o this rA entrada void extraiDe istream amp entrada void Racional extraiDe istream amp entrada assert cumpreInvariante int n int d 1 if entrada gt gt n if entrada peek numerador n denominador_ 1 else if entrada get and isdigit entrada peek and entrada gt gt d and d 0 numerador d lt 0 n n denominador_ d lt 0 d d reduz else if entrada entrada setstate ios_base failbit assert cumpreInvariante assert numerador_ d n denominador_ or
30. algumas das t cnicas j apresentadas Estes operadores ser o sobrecarregados usando rotinas n o membro de modo a se tirar partido das convers es impl citas de int para Racional e tentar se que sejam implementados custa de outros m dulos pr existentes por forma a minimizar o impacte de poss veis alterac es na representac o interna dos n meros racionais Os primeiros operadores a sobrecarregar ser o o operador igualdade e o operador diferen a Viu se na Sec o 7 4 4 que o facto de as inst ncias da classe C Racional cumprirem PSA 3 numerador z Ani a condi o invariante de classe i e de denominador Ser uma fracc o no formato can nico permitia simplificar muito a comparac o entre racionais De facto assim pois dois racio nais s o iguais sse tiverem representa es em frac es can nicas iguais Assim uma primeira tentativa de definir o operador poderia ser Indica se dois racionais s o iguais Qpre V post operator r1 r2 bool operator Racional const rl Racional const r2 return rl numerador r2 numerador and rl denominador r2 denominador O problema deste c digo que sendo o operador uma rotina n o membro n o tem acesso aos membros privados da classe C Por outro lado se o operador fosse uma opera o da classe C embora o problema do acesso aos membros se resolvesse deixariam de ser poss veis convers es impl ci
31. amp Racional operator Racional const r2 assert cumpreInvariante and r2 cumpreInvariante assert r2 0 if r2 numerador lt O numerador r2 denominador denominador r2 numerador else numerador r2 denominador denominador r2 numerador T reduz assert cumpreInvariante return this 7 8 MAIS OPERADORES PARA O TAD RACIONAL 365 H neste c digo algumas particularidades que preciso estudar A divis o por zero imposs vel pelo que a pr condic o obriga r2 a ser diferente de zero A instruc o de asserc o reflecte isso mesmo embora contenha um erro por ora n o poss vel comparar dois racionais atrav s do operador quanto mais um racional e um inteiro 0 um do tipo int Pede se ao leitor que seja paciente pois dentro em breve este problema ser resolvido sem ser necess rio alterar em nada este m todo O c lculo da divis o muito simples o numerador da divis o o numerador do primeiro operando multiplicado pelo denominador do segundo operando e vice versa Uma vers o simplista do c lculo da divis o seria numerador r2 denominador denominador r2 numerador Este c digo no entanto n o s n o garante que o resultado esteja reduzido e da a invoca o de reduz no c digo mais acima tal como acontecia para o operador como tamb m n o garante que o denominador resultante seja positivo visto que o numerador de r2 po
32. como uma constante e n o o contr rio e pode mesmo ser sin nimo de uma vari vel ou constante tempor ria Por outro lado este tipo de passagem de argumentos semelhante passagem de argumentos por refer ncia simples pois n o obriga realiza o de c pias Ou seja a passagem de argumentos por refer ncia constante tem a vantagem das passagens por refer ncia ou seja a sua maior efici ncia na passagem de tipos n o b sicos e a vantagens da passagem por valor ou seja a impossibilidade de altera o do argumento atrav s do res pectivo par metro e a possibilidade de passar inst ncias vari veis ou constantes tempor rias ou n o Assim como regra geral sempre recomend vel a passagem de argumentos por refe r ncia constante em detrimento da passagem por valor quando estiverem em causa tipos n o b sicos e quando n o houver necessidade por alguma raz o de alterar o valor do par metro durante a execu o da rotina em causa Esta regra deve ser aplicada de forma sistem tica s rotinas membro e n o membro desenvol vidas no caso deste cap tulo s rotinas associadas ao TAD Racional em desenvolvimento A t tulo de exemplo mostra se a sua utiliza o na sobrecarga dos operadores e para a classe C Racional class Racional public Adiciona de um racional Qpre this r post operator thisA this r r2 Racional amp operator Racional const amp 12 Divide por um racion
33. constru da iguala r1 Racional r3 E3 gols ovalorde r1 atribu doa r3 ficando as vari veis iguais Da mesma forma est o bem definidas as devolu es e a passagem de argumentos por valor para valores de uma classe C as inst ncias de um TAD concretizado por interm dio de uma classe C podem ser usadas exactamente da mesma forma que as inst ncias dos tipos b sicos poss vel por isso usar uma fun o e n o um procedimento para calcular a soma de dois racionais no programa em desenvolvimento Antes de o fazer no entanto far se uma digress o sobre as formas de representa o de n mero racionais 7 3 Representa o de racionais por frac es Qualquer n mero racional pode ser representado por uma frac o que um par ordenado de n meros inteiros n d em que n e d s o os termos da frac o Ao segundo termo d se o nome de denominador o que d o nome frac o e ao primeiro numerador diz a quantas frac es nos referimos Por exemplo 3 4 significa tr s quartos Normalmente os racionais representam se graficamente usando uma nota o diferente da anterior n d ou Uma frac o G s representa um n mero racional se d 0 Por outro lado importante sa ber se frac es diferentes podem representar o mesmo racional ou se pelo contr rio frac es diferentes representam sempre racionais diferentes A resposta quest o inversa evidente H re
34. da programa o orientada por objectos em cap tulos posteriores ver se co mo se podem desenhar classes e hierarquias de classes e quais as suas aplica es na resolu o de problemas de maior escala 7 1 De novo a soma de frac es Na Sec o 3 2 20 desenvolveu se um pequeno programa para ler duas frac es do teclado e mostrar a sua soma Neste cap tulo desenvolver se esse programa at construir uma pe quena calculadora Durante esse processo aproveitar se para introduzir uma quantidade consider vel de conceitos novos O programa apresentado na Sec o 3 2 20 pode ser melhorado Assim apresenta se abaixo uma vers o melhorada nos seguintes aspectos 7 1 DE NOVO A SOMA DE FRAC ES 301 e A no o de m ximo divisor comum facilmente generaliz vel a inteiros negativos ou nulos O nico caso complicado o de mdc 0 0 Como bvio todos os inteiros po sitivos s o divisores comuns de zero pelo que n o existe este m ximo divisor comum No entanto de toda a conveni ncia estender a defini o do m ximo divisor comum arbitrando o valor 1 como resultado de mdc 0 0 Ou seja por defini o mdc 0 0 1 Assim a fun o mdc foi flexibilizada tendo se enfraquecido a respectiva pr condi o de modo a ser aceitar argumentos arbitr rios A utilidade da cobertura do caso mdc 0 0 ser vista mais tarde e O enfraquecimento da pr condi o da fun o mdc permitiu enfraqu
35. de membro colocando como primeiro operando a inst ncia a cujo membro se pretende aceder depois o s mbolo e finalmente o nome do membro pretendido inst ncia membro Por exemplo Racional rl r2 rl numerador 6 II to rl denominador r2 numerador 7 r2 denominador Il w constr i duas novas vari veis do tipo Racional e atribui valores aos respectivos atributos Os nomes dos membros de uma classe s t m visibilidade dentro dessa classe pelo que poderia existir uma vari vel de nome numerador sem que isso causasse qualquer problema Racional r 6 9 int numerador 1000 7 2 3 Alguma nomenclatura s inst ncias i e vari veis ou constantes de uma classe C comum chamar se objectos sendo essa a raz o para as express es programa o baseada em objectos e programa o orientada para os objectos No entanto reservar se o termo objecto para classes C que sejam concretiza es de classes propriamente ditas e n o para classes C que sejam concre tiza es de TAD As vari veis e constantes membro de uma classe C tamb m se chama atributos Podem tamb m existir rotinas membro de uma classe C A essas fun es ou procedimentos chama se opera es No contexto das classes propriamente ditas em vez de se dizer invocar uma opera o para uma inst ncia de uma classe diz se por vezes enviar uma mensagem a um objecto Como se ver mais tarde que
36. denominador_ numerador_ dn denominador_ dd numerador_ numerador_ d2 dd r2 numerador_ dn denominador_ dd mdc numerador_ dd numerador dn numerador_ dd denominador_ d2 dd assert cumpreInvariante return this Racional amp Racional operator Racional const amp r2 assert cumpreInvariante and r2 cumpreInvariante int dn int dd mdc numerador_ r2 numerador_ mdc denominador_ r2 denominador_ Devidoa r r int d2 r2 denominador_ numerador_ dn denominador_ dd numerador_ numerador_ d2 dd r2 numerador_ dn denominador_ dd mdc numerador_ dd 398 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C numerador dn numerador_ dd denominador d2 dd assert cumpreInvariante return this Uma vez que ambos os m todos ficaram bastante extensos decidiu se retirar lhes o qualifica dor inline 7 13 2 Multiplica o Relativamente multiplica o de frac es n na ny X N2 d d hh apesar de o denominador ser for osamente positivo poss vel que o resultado n o esteja no formato can nico bastando para isso que existam divisores n o unit rios comuns a n e da ou a dy e nz f cil verificar que sendo k mdc n1 do e mdc na dy a frac o n n2 m k x n2 1 32 da do dy 1 x do k est de facto no formato can nico Pode se agora actualizar
37. dores gt gt e lt lt de extrac o e inser o em canais instrutivo preparar a classe para utiliza es futuras ainda dif ceis de antecipar Pretende se pois equipar o TAD Racional com todos os operadores usuais para os tipos b sicos do C e Operadores aritm ticos bin rios adi o subtrac o produto e divis o N o t m efeitos laterais i e n o alteram os operandos e Operadores aritm ticos un rios identidade e sim trico N o t m efeitos laterais lt lt gt gt Operadores relacionais bin rios menor menor ou igual maior e maior ou igual N o t m efeitos laterais e Operadores de igualdade e diferen a bin rios N o t m efeitos laterais e Operadores de incrementa o e decrementa o prefixo un rios T m efeitos laterais pois alteram o operando Ali s s o eles a sua principal raz o de ser e Operadores de incrementa o e decrementa o sufixo un rios T m efeitos laterais e Operadores especiais de atribui o adi o e atribui o subtrac o e atribui o produto e atribui o e divis o e atribui o bin rios T m efeitos laterais pois alteram o primeiro operando gt gt e lt lt Operadores de extrac o e inser o de um canal bin rios Ambos alteram o ope rando esquerdo que um canal mas apenas o primeiro altera o operando direito T m efeitos laterais 7 6 Testes de unidade Na
38. duas interface distintas A primeira mais pequena a interface dispon vel para utiliza o com constantes dessa classe e consiste no conjunto das opera es que garantem a const ncia da inst ncia impl cita A segunda que engloba a primeira a interface dispon vel para utiliza o com vari veis da classe Finalmente muito importante pensar logo nas opera es de uma classe como sendo ou n o constantes ou melhor como garantindo ou n o a const ncia da inst ncia impl cita e n o faz lo posteriori como neste cap tulo O desenvolvimento do TAD Racional feito neste cap tulo n o feito pela ordem mais apropriada na pr tica para isso ver o pr ximo cap tulo mas sim pela ordem que se julgou mais conveniente pedagogicamente para introduzir os muitos conceitos associados a classes C que o leitor tem de dominar para as desenhar com profici ncia 7 11 3 Devolu o por valor constante Outro assunto relacionado com a const ncia a devolu o de constantes O conceito parece primeira vista mas repare se no seguinte c digo Racional r1 1 2 12 3 2 11 12 Que faz este c digo Define duas vari veis r1 e r2 soma as e finalmente incrementa a vari vel tempor ria devolvida pelo operador Tal c digo mais provavelmente fruto de erro do programador do que algo desejado Al m disso semelhante c digo seria proibido se em vez de racionais as classes fossem do tipo int Como se preten
39. e que exijam uma inicializa o expl cita Mas neste caso a solu o a que cheg mos n o a mais adequada Se todos os vectores devem ter a mesma dimens o porqu fornecer cada inst ncia da classe C com a sua pr pria constante dimens o O ideal seria partilhar essa constante entre todas as inst ncias da classe 7 17 2 Membros de classe At agora viu se apenas como definir membros de inst ncia i e membros dos quais cada ins t ncia da classe C possui uma vers o pr pria Como fazer para definir um atributo do qual 434 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C exista apenas uma vers o comum a todas as inst ncias da classe C A solu o simples basta declarar o atributo com sendo um atributo de classe e n o de inst ncia Isso consegue se precedendo a sua declara o do qualificador static class Vector public static int const dimens o Vector private double coordenadas dimens o Opps N o funciona y Um atributo de classe n o pode ser inicializado nas listas de inicializadores dos construtores Nem faria qualquer sentido pois um atributo de classe t m apenas uma inst ncia partilhada entre todas as inst ncias da classe de que membro n o fazendo sentido ser inicializada sen o uma vez antes do programa come ar Assim necess rio definir esse atributo fora da classe sendo durante essa defini o que se procede respectiva inicializa o int const
40. est o bem definidas para os racionais com excepc o da divis o por 0 ou melhor por 2 Assim em termos da representa o dos racionais como frac es o resultado das ope ra es aritm ticas elementares pode ser expresso como n No n X da na X dy da do da x do n1 na ni X da na X dy da do da x do n1 M Na _ n x N2 X no da do z dy x da x da Nj na T n X d 5 sen O da do P da X no 2 7 n sn e d d nn d d 7 3 2 Canonicidade do resultado Tal como definidas algumas destas opera es sobre frac es n o garantem que o resultado esteja no formato can nico mesmo que as frac es que servem de operandos o estejam Este problema f cil de resolver no entanto pois dada uma frac o que n o esteja for osamente no formato can nico pode se dividir ambos os termos pelo seu m ximo divisor comum para E A Z ut n mdc n d obter uma frac o equivalente em termos m nimos J mdctn ad Se O denominador for nega tivo pode se multiplicar ambos os termos por 1 para obter uma fracc o equivalente com o numerador positivo 312 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C 7 3 3 Aplica o soma de frac es Voltando classe C definida Representa n meros racionais class Racional public Isto magia por enquanto int numerador int denominador y muito importante estar ciente das diferen as entre a concretiza
41. i pois v sin nimo de i d imediatamente ap s a primeira invoca o da rotina e imediatamente antes da sua segunda invoca o j com os par metros retirados da pilha sendo de notar que o valor devolvido est guardado numa vari vel tempor ria sem nome no topo da pilha a vari vel est abaixo do pisa papeis que representa o topo da pilha e n o acima como habitual com os valores devolvidos por ir ser constru da uma refer ncia para alea que obriga a que seja preservada mais tempo e imediatamente antes da instru o 1 depois de invocada a rotina pela segunda vez f entre as instru es 1 e 2 j depois de incre mentado v e portanto j depois de incrementada a vari vel tempor ria de que v sin nimo e g imediatamente antes da instru o 5 depois de a rotina retornar V se claramente que a va ri vel incrementada da segunda vez n o foi a vari vel i como se pretendia mas uma vari vel tempor ria entretanto destru da 7 7 DEVOLU O POR REFER NCIA 353 Incrementa o inteiro recebido como argumento e devolve o Qpre i post incrementa i i 1 int amp incrementa int amp v 1 v Vv 1 2 return v ousimplesmente return v v 1 int i 0 3 incrementa i 4 incremental 5 cout lt lt i lt lt endl Esta vers o da rotina incrementa j leva ao resultado pretendido usando para isso uma devolu o por refer nc
42. inicializa r1 com 4 2 Constru o de r2 por invoca o impl cita do construtor da classe C Racional que pode ser invocado sem argumentos que inicializa r2 com o racional zero ou 3 Constru o do atributo i a partir do par metro i que neste caso fica com 1 usado o construtor por c pia dos int 4 Constru o do atributo j atrav s do construtor por omiss o dos int que necess rio invocar explicitamente e que inicializa j com o valor zero 5 Execu o do corpo do construtor da classe C C a Convers o do valor literal 3 de int para Racional b Atribui o do racional ar2 E de notar que a vari vel membro r2 constru da e inicializada com o valor zero e s depois lhe atribu do o racional o que uma perda de tempo Seria prefer vel incluir r 2 na lista de inicializadores 7 17 6 Matrizes de classe poss vel definir matrizes cl ssicas do C tendo como elementos valores de TAD por exem plo da classe C Racional Racional mi 10 Racional m2 10 1 2 Racional 3 Racional Racional 1l 3 442 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Os 10 elementos de m1 e os ltimos cinco elementos de m2 s o constru dos usando o constru tor por omiss o da classe Racional que os inicializa com o racional zero Os dois primeiros elementos da matriz m2 s o inicializados a partir de inteiros implicitamente convertidos pa ra racionais usando o construtor com um
43. j que j sin nimo de i As vari veis que s o refer ncias caso de j no exemplo anterior e dos par metros a e b do procedimento troca t m de ser inicializadas com a vari vel de que vir o a ser sin nimos Essa inicializa o feita explicitamente no caso de 5 e implicitamente no caso das vari veis a e b neste caso atrav s da passagem de x e y como argumento na chamada de troca Necessidade da devolu o por refer ncia Suponha se o c digo int i 0 1 5 cout lt lt i lt lt endl Note se que este c digo muito pouco recomend vel S que como a sobrecarga dos opera dores deve manter a mesma sem ntica que esses mesmos operadores possuem para os tipos b sicos necess rio conhecer bem os cantos casa mesmo os mais obscuros infelizmente Este c digo resulta na dupla incrementac o da vari vel i como seria de esperar Mas para isso acontecer o Operador para al m de incrementar a vari vel i tem de devolver a pr pria vari vel i e n o uma sua c pia pois de outra forma a segunda aplicac o do operador levaria incrementac o da c pia e n o do original Para que este assunto fique mais claro come ar se por escrever um procedimento incre menta com o mesmo objectivo do operador de incrementa o Como este procedimento deve afectar a vari vel passada como argumento neste caso i deve receber o argumento por refer ncia 7 7 DEVOLU O POR REFER NCIA 35
44. k mdc d d2 e mdc n1 n2 ent o dividindo ambos os termos da frac o resultado por k e pondo l em evid ncia m no _ lx ni xd n x di d do k x d x do onde dj di k e dy do k s o mutuamente primos i e mdc d d 1 e n m l e ng n2 l s o mutuamente primos i e mdc n4 n4 1 Este novo resultado apesar da divis o por k de ambos os termos da frac o pode ainda n o estar no formato can nico pois pode haver divisores n o unit rios comuns ao numerador e ao denominador Repare se no exemplo 1 4 1 10 LoS em que k mdc 10 15 5 Aplicando a equa o acima obt m se 1 1 1x3 1x2_ 5 10 157 5x2x3 30 Neste caso para reduzir a frac o aos termos m nimos necess rio dividir ambos os termos da frac o por 5 Em vez de tentar reduzir a frac o resultado tomando quer o numerador quer o denominador como um todo prefer vel verificar primeiro se poss vel haver divisores comuns entre os respectivos factores Considerar se o dois factores para o numerador l e n x d n3 x di e dois factores para o denominador k e dj x d num total de quatro combina es onde poss vel haver divisores comuns Ser que podem haver divisores n o unit rios comuns a l e a k Suponha se que existe um divisor 1 lt comum a le a k Nesse caso dado que d dj x ke n n x L ter se ia de 396 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C concluir que lt mdc n d o
45. lt endl mostra 1 2 0 5 cout lt lt double r lt lt endl mostra 0 5 A solu o poderia passar por alterar a classe C double de modo a ter um construtor que aceitasse um racional O problema que nem o tipo double uma classe nem se por absurdo o fosse estaria nas m os do programador alter la 7 17 OUTROS ASSUNTOS ACERCA DE CLASSES C 443 A solu o passa por alterar a classe C Racional indicando que se pode converter impli citamente um racional num double De facto a linguagem C permite faz lo poss vel numa classe C definir uma convers o impl cita de um tipo para essa classe mas tamb m o contr rio definir uma convers o impl cita da classe para um outro tipo Isso consegue se sobrecarregando um operador de convers o para o tipo pretendido neste caso double Esse operador chama se operator double Este tipo de operadores de convers o de tipo t m algumas particularidades 1 S podem ser sobrecarregados atrav s de rotinas membro da classe C a converter 2 N o incluem tipo de devolu o no seu cabe alho pois este indicado pelo pr prio nome do operador Ou seja no caso em apre o class Racional public Devolve o racional visto como um double Qpre V Gpost O valor devolvido uma aproxima o t o boa quanto poss vel do racional representado por this operator double const Racional operator double const return double numerador d
46. m dulo menos esfor o ser exigido do programador consumi dor No entanto n o se deve nunca perder o pragmatismo de vista e desenhar um m dulo tentando prever todas as suas poss veis utiliza es Em primeiro lugar porque essas previs es provavelmente falhar o conduzindo a c digo in til e em segundo porque todo esse c digo in til ir servir apenas como fonte de complexidade e erros desnecess rios Neste caso no en tanto o neg cio foi bom o desenvolvimento serviu n o apenas para fazer surgir naturalmente muitas particularidades associadas ao desenvolvimento de TAD em C servindo assim co mo ferramenta pedag gica como tamb m redundou numa classe que realmente til ou que pelo menos est no bom caminho para o vir a ser 7 17 Outros assuntos acerca de classes C Ao longo deste cap tulo e a pretexto do desenvolvimento de um TAD Racional introduziram se muitos conceitos importantes relativos s classes C Nenhum exemplo pr tico esgota todos os assuntos pelo que se reservou esta sec o final para introduzir alguns conceitos adi cionais sobre classes C 7171 Constantes membro Suponha que se pretende definir uma classe C para representar vectores num espa o de dimens o fixa e finita De modo a ser f cil alterar a dimens o do espa o onde se encontra o vector sem grande esfor o tentador definir um atributo constante para representar a dimen s o desse espa o Depois as coordenada
47. mesma forma como se faria se se pretendesse somar inteiros int main Ler frac es cout lt lt Introduza duas frac es numerador denominador Racional rl r2 cin gt gt El D TZ if not cin cerr lt lt Opps A leitura dos racionais falhou lt lt en dls return 1 Calcular racional soma Racional r rl r2 Escrever resultado cout lt lt A soma de lt lt rl lt lt com lt lt r2 7 14 OPERADORES DE INSER O E EXTRAC O 403 lt lt MN lt lt r lt lt T lt lt endl 7 14 1 Sobrecarga do operador lt lt Come ar se pelo operador de inser o por ser mais simples O operador lt lt bin rio tendo por isso dois operandos Por exemplo se se pretender escrever um valor inteiro no ecr pode se usar a instru o cout lt lt 10 onde o primeiro operando cout um canal de sa da ligado normalmente ao ecr e 10 um valor literal inteiro O efeito da opera o fazer surgir o valor 10 no ecr O segundo operando claramente do tipo int mas qual o tipo do primeiro operando Ali s o que cout A resposta a estas perguntas muito importante para a sobrecarga do operador lt lt desejada o primeiro operando cout uma vari vel global do tipo ostream ou seja canal de sa da Ambos vari vel cout e tipo ostream est o declarados no ficheiro de interface iostream Por outro lado o operador lt lt um operador b
48. numerador e denominador de uma frac o precisa de receber garantidamente um denominador n o nulo e tem de ter o cuidado de garantir que os seus atributos numerador e denominador est o no formato can nico das frac es Representa n meros racionais class Racional public Constr i racional com valor zero Construtor por omiss o Qpre V post this 0 0 lt denominador A mdc numerador denominador 1 Racional Constr i racional com valor inteiro pre V post this nA 0 lt denominador A mdc numerador denominador 1 Racional int const n 328 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Constr i racional correspondente a n d Qpre d 0 Opost this SA 0 lt denominador A mdc numerador denominador 1 Racional int const n int const d private Racional Racional numerador 0 denominador 1 assert 0 lt denominador and mdc numerador denomina dor 1 and numerador 0 Racional Racional int const n numerador n denominador 1 assert 0 lt denominador and mdc numerador denomina dor 1 and numerador n denominador Racional Racional int const n int const d numerador d lt 0 2 n n denominador d lt 0 d d assert d 0 reduz assert 0 lt denominador and mdc numerador denomina dor 1 and numerador d n denominador 7 4 CLASSES C COMO
49. o c digo anterior deveria ser corrigido para Racional r r Racional 1 3 7 9 2 Convers es impl citas Se uma classe A possuir um construtor que possa ser invocado passando um nico argumento do tipo B como argumento ent o est dispon vel uma convers o impl cita do tipo B para a classe A Por exemplo o primeiro construtor da classe Racional ver Sec o 7 4 1 pode ser chamado com apenas um argumento do tipo int o que significa que sempre que o compila dor esperar um Racional e encontrar um int converte o int implicitamente para um valor Racional Por exemplo estando definido um operator com operandos do tipo Racional o seguinte peda o o c digo Racional r1 1 3 Racional r2 rl 1 perfeitamente legal tendo o mesmo significado que Racional r1 1 3 Racional r2 rl Racional 1 370 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C colocando em r2 o racional Em casos em que esta convers o impl cita de tipos indesej vel pode se preceder o respectivo construtor da palavra chave explicit Assim se a classe Racional estivesse definida como class Racional public Constr i racional com valor inteiro Construtor por omiss o Qpre V post this n 0 lt denominador A mdc numerador denominador 1 explicit Racional int const n 0 o compilador assinalaria erro ao encontrar a express o r1 1 Neste caso no entanto a con vers o impl cita de i
50. o da condi o objectivo de uma opera o culpa do programador produtor do respectivo m todo Como explicitar a condi o invariante de classe apenas uma quest o de usar instru es de asser o e coment rios de documenta o apropriados Para simplificar conveniente definir uma opera o privada da classe chamada convencionalmente cumpreInvariante que devolve o valor l gico V se a condi o invariante de classe se cumprir e falso no caso contr rio Descri o da classe Classe UMais tarde se ver que dependendo da aplica o em desenvolvimento abortar o programa em caso de erro de programa o pode ou n o ser apropriado 7 4 CLASSES C COMO M DULOS Oinvariant CIC class Classe public Descri o da opera o opera o Qpre PC Qpost CO tipo opera o par metros private Descri o da opera o opera o privada Qpre PC Qpost CO tipo opera o privada par metros Indica se a condi o invariante de classe CIC se verifica Qpre this v post cumpreInvariante CIC N this v bool cumpreInvariante Hj Implementa o da opera o opera o m todo tipo Classe opera o par metros assert cumpreInvariante and v cumpreInvariante assert PC Implementa o assert cumpreInvariante and v cumpreInvariante assert CO return us bool Classe cumpreInvariante 335
51. o do conceito de racional e o conceito em si os valores represent veis num int s o limitados o que significa que n o poss vel representar qualquer racional numa vari vel do tipo Racional tal como n o era poss vel representar qualquer inteiro numa vari vel do tipo int Os problemas causados por esta diferen a ser o ignorados durante a maior parte deste cap tulo embora na Sec o 7 13 sejam sen o resolvidos pelo menos mitigados Um mero agregado de dois inteiros mesmo com um nome sugestivo n o s tem pouco in teresse como poderia representar muitas coisas diferentes Para que esse agregado possa ser considerado a concretiza o de um TAD necess rio definir tamb m as opera es que o no vo tipo suporta Uma das opera es a implementar a soma Pode se implementar a soma actualizando o procedimento do programa original para a seguinte fun o Devolve a soma de dois racionais Qpre rl denominador 0 A r2 denominador 0 post somaDe r1 r2A somaDe denominador 0 A mde somaDe numerador somaDe denominador 1 Racional somaDe Racional const rl Racional const r2 assert rl denominadorl 0 and r2 denominador2 0 Racional r r numerador rl numerador r2 denominador r2 numerador rl denominador r denominador rl denominador r2 denominador reduz r as sert r denominador 0 and mdc r numerador r denominador 1 return r 7 3 REPRESENTA
52. pia ela tende a ser mais eficiente que a passagem por valor pelo menos para tipos em que as c pias s o onerosas computacionalmente o que n o o caso dos tipos b sicos da linguagem Por outro lado este tipo de passagem de argumentos pro be a passagem como argumento de constantes como natural mas tamb m de vari veis tempor rias tais como resultados de express es que n o sejam lvalues ver Sec o 7 7 1 Este facto impede a passagem de argumentos de tipos diferentes de dos par metros mas para os quais exista uma convers o impl cita Quando a passagem de argumentos se faz por refer ncia constante Declara o TipoDeDevolu o rotina TipoDoPar metro const amp par metro 7 11 CONST NCIA VERIFICANDO ERROS DURANTE A COMPILA O 379 Defini o TipoDeDevolu o rotina TipoDoPar metro const amp par metro os par metros funcionam como sin nimos constantes dos argumentos ou refer ncias constantes para os par metros Sendo constantes as altera es aos par metros s o proibidas Por um lado a passagem de argumentos por refer ncia constante semelhante passagem por valor pois ambas n o s impossibilita altera es aos argumentos como permite que sejam passados valores constantes e tempor rios como argumentos e que estes sofram convers es impl citas uma refer ncia constante pode ser sin nimo tanto de uma vari vel como de uma constante pois uma vari vel pode sempre ser tratada
53. r2 Produto de dois racionais pre V post operator r1 x r2 Racional const operator Racional const rl Racional const amp r2 Divis o de dois racionais pre r2 0 post operator r1 r2 Racional const operator Racional const rl Racional const amp r2 Incrementa o racional recebido como argumento devolvendo o seu valor an tes de incrementado pre this r post operator r A this r 1 Racional const operator Racional amp r int Decrementa o racional recebido como argumento devolvendo o seu valor an tes de decrementado pre this r Opostoperator rA this r 1 Racional const operator Racional amp r int Indica se dois racionais s o iguais Qpre V post operator r1 r2 bool operator Racional const amp rl Racional const amp r2 Indica se dois racionais s o diferentes 422 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Qpre V post operator 11 4 r2 bool operator Racional const amp rl Racional const amp r2 Indica se o primeiro racional menor que o segundo Qpre V post operator lt r1 lt r2 bool operator lt Racional const amp rl Racional const amp r2 Indica se o primeiro racional maior que o segundo Qpre V post operator gt r1 gt r2 bool operator gt Racional const amp rl Racional const amp r2 Indica se o primeiro racional menor ou
54. racionais s o iguais Qpre V Gpost operator r1 r2 374 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C bool operator Racional const rl Racional const r2 return rl numerador r2 numerador and rl denominador r2 denominador O operador sobrecarrega se de uma forma ainda mais simples negando o resultado de uma invocac o ao operador definido acima Indica se dois racionais s o diferentes Qpre V post operator r1 4 r2 bool operator Racional const rl Racional const r2 return not rl r2 7 10 3 Operadores relacionais O operador lt pode ser facilmente implementado para a classe C Racional bastando re correr ao mesmo operador para os inteiros Suponha se que se pretende saber se n1 na r 2 di dz em que T e ra s o frac es no formato can nico Como 0 lt d e O lt ds a desigualdade acima equivalente a nido lt nad Logo a sobrecarga do operador lt pode ser feita como se segue Indica se o primeiro racional menor que o segundo Qpre V post operator lt r1 lt r2 bool operator lt Racional const rl Racional const r2 return rl numerador r2 denominador lt r2 numerador rl denominador Os restantes operadores relacionais podem ser definidos todos custa do operador lt E ins trutivo ver como sobretudo no caso desconcertantemente simples do operador gt 7 11 CON
55. se segue Representa n meros racionais class Racional public Isto magia por enquanto int numerador int denominador A sintaxe de defini o de um TAD custa de uma classe C portanto class nome do tipo declarac o de membros y sendo importante notar que este um dos poucos locais onde a linguagem exige um termina dor depois de uma chaveta final Es A nota o usada para representar a classe C Racional pode ser vista na Figura 7 2 A defini o de uma classe C consiste na declara o dos seus membros A defini o da classe estabelece um modelo segundo o qual ser o constru das as respectivas vari veis No caso apresentado as vari veis do tipo Racional quando forem constru das consistir o em dois membros um numerador e um denominador do tipo int Neste caso os membros s o simples vari veis mas poderiam ser tamb m constantes s vari veis e constantes membro de uma classe d se o nome de atributos Tal como as matrizes as classes permitem guardar agregados de informac o ou seja agrega dos de vari veis ou constantes chamados elementos no caso das matrizes e membros no caso Ao contr rio do que acontece na defini o de rotinas e nos blocos de instru es em geral o terminador aqui imprescind vel pois a linguagem C permite a defini o simult nea de um novo tipo de de vari veis desse tipo Por exemplo class Racional
56. ser demasiado extensa Exemplificando apenas para o primeiro construtor da classe class Racional public Constr i racional com valor inteiro Construtor por omiss o Qpre V post this n Racional int const n 0 y inline Racional Racional int const n 394 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C numerador n denominador 1 assert cumpreInvariante assert numerador_ n denominador 7 13 Optimiza o dos c lculos com racionais Um dos problemas com a representa o escolhida para a classe C Racional o facto de os atributos numerador e denominador serem do tipo int que tem limita es devidas sua representa o na mem ria do computador Essa foi parte da raz o pela qual se insistiu em que os racionais fossem sempre representados pelo numerador e denominador de uma frac o no formato can nico i e com denominador positivo e formando uma frac o reduzida No entanto esta escolha n o suficiente Basta olhar para a defini o da fun o que sobrecarrega o operador lt para a classe C Racional Indica se o primeiro racional menor que o segundo Qpre V post operator lt r1 lt r2 inline bool operator lt Racional const rl Racional const amp r2 return rl numerador r2 denominador lt r2 numerador rl denominador para se perceber imediatamente que mesmo que os racionais sejam represent veis durante c lcu
57. tal seja pos s vel para todas as classes C que n o declarem explicitamente um construtor por c pia O construtor por c pia fornecido implicitamente limita se a invocar os construtores por c pia para construir os atributos da inst ncia em constru o custa dos mesmos atributos na inst n cia original sendo a invoca o realizada por ordem de defini o dos atributos na defini o da classe 7 4 CLASSES C COMO M DULOS 331 E poss vel e muitas vezes desej vel declarar ou mesmo definir explicitamente um construtor por c pia para as classes Este assunto ser tratado com pormenor num cap tulo posterior 7 4 3 Condi o invariante de classe Na maior parte das classes C que concretizam um TAD os atributos s est o num estado aceit vel se verificarem um conjunto de restri es expressos normalmente na forma de uma condi o a que se d o nome de condi o invariante de classe ou CIC A classe dos racionais possui uma condi o invariante de classe que passa por exigir que os atributos numerador e denominador sejam o numerador e o denominador da frac o can nica representativa do racional correspondente i e CIC 0 lt denominador A mdc numerador denominador A vantagem da defini o de uma condi o invariante de classe para que todos os m todos correspondentes a opera es p blicas bem como todas as rotinas amigas da classe C que fazem parte da interface da classe com o consumidor Sec o
58. uma forma de os racionais poderem se inicializados de uma forma semelhante Por exemplo Racional r 1 3 Pretende se que inicialize r com o racional L ou mesmo 2 n 1 Racional r 2 Pretende se que inicialize r com o racional Racional r 3 Pretende se que inicialize r com o racional Por outro lado deveria ser poss vel evitar o comportamento dos tipos b sicos do C e elimi nar completamente as inst ncias por inicializar fazendo com que falta de uma inicializa o expl cita os novos racionais fossem inicializados com o valor zero 0 representado pela frac o 9 Ou seja Racional r Racional r 0 Racional r 0 1 deveriam ser instru es equivalentes Finalmente deveria haver alguma forma de evitar a inicializac o de racionais com valores imposs veis nomeadamente com denominador nulo I e a instru o Racional r 3 0 deveria de alguma forma resultar num erro Quando se constr i uma inst ncia de uma classe C chamado um procedimento especi al que se chama construtor da classe C Esse construtor fornecido implicitamente pela linguagem e um construtor por omiss o i e um construtor que se pode invocar sem lhe passar quaisquer argumento O construtor por omiss o fornecido implicitamente constr i cada um dos atributos da classe invocando o respectivo construtor por omiss o Neste caso como os atributos s o de tipos b sicos da linguagem n o s o inic
59. 1 Incrementa o inteiro recebido como argumento e devolve o Qpre i i Oposti i 1 void incrementa int amp v v v 1 int i 0 incrementa incrementa i cout lt lt i lt lt endl Infelizmente este c digo n o compila pois a invocac o mais exterior do procedimento recebe como argumento o resultado da primeira invoca o que void Logo necess rio devolver um inteiro nesta rotina Incrementa o inteiro recebido como argumento e devolve o pre i 1 post incrementa iAi i l int incrementa int amp v PE 1 v v 1 1 2 return v int i 0 J 3 incrementa i 4 incrementa 5 cout lt lt i lt lt endl Este c digo tem tr s problemas O primeiro problema que dada a defini o actual da lin guagem n o compila pois o valor tempor rio devolvido pela primeira invoca o da rotina n o pode ser passado por refer ncia n o constante para a segunda invoca o A linguagem C pro be a passagem por refer ncia n o constante de valores ou melhor de vari veis tem por rias 6 O segundo problema que ao contr rio do que se recomendou no cap tulo sobre modulariza o esta rotina n o um procedimento pois devolve alguma coisa nem uma fun o pois afecta um dos seus argumentos Note se que continua a ser indesej vel escrever este tipo de c digo Mas a emula o do funcionamento do operador que um operador com efeitos la
60. 2 return rl r2 inline Racional const operator Racional rl Racional const amp r2 return rl r2 inline Racional const operator Racional rl Racional const amp r2 assert r2 0 return rl r2 inline Racional const operator Racional amp r int Racional const c pia r r return c pia inline Racional const operator Racional amp r int Racional const c pia r r 7 16 C DIGO COMPLETO DO TAD RACIONAL return c pia inline bool operator Racional const amp rl return rl numerador r2 numerador rl denominador inline bool operator Racional const amp rl return not rl EZ inline bool operator lt Racional const amp rl 429 Racional const amp r2 and O r2 denominador Racional const amp r2 Racional const amp r2 int dn mdc rl numerador r2 numerador int dd mdc rl denominador r2 denominador return rl numerador dn r2 denominador dd lt r2 numerador dn rl denominador dd inline bool operator gt Racional const amp rl return r2 lt rl inline bool operator lt Racional const amp rl return not r2 lt rl inline bool operator gt Racional const amp rl return not rl lt r2 ostream operator lt lt ostreams sa da Ra r insereEm sa da return sa da istream operator gt gt istream amp entrada
61. ASSES C lodd x1 Carrega vari vel x1 no acumulador push t Coloca acumulador no topo da pilha lodd x2 t Carrega vari vel x2 no acumulador push t Coloca acumulador no topo da pilha Aqui a pilha tem os dois argumentos x1 e x2 call soma Invoca a fun o soma insp 2 Rep e a pilha Aqui o acumulador tem o valor devolvido stod r Guarda o acumulador na vari vel r lodd r push lodd x3 push Aqui a pilha tem os dois argumentos r e x3 call soma insp 2 Aqui o acumulador tem o valor devolvido stod r halt t Fun o soma lodl 1 Carrega no acumulador o segundo par metro addl 2 Adiciona primeiro par metro ao acumulador retn Retorna devolvendo resultado no acumulador Se levasse em conta o qualificador inline um compilador de C para assembly MAC 1 provavelmente geraria main jump main Vari veis x1 10 x2 20 x3 30 r 0 t Programa principal lodd x1 Carrega vari vel x1 no acumulador addd x2 Adiciona vari vel x2 ao acumulador stod r Guarda o acumulador na vari vel r lodd r addd x3 7 12 REDUZINDO O N MERO DE INVOCAC ES COM INLINE 393 stod r halt A diferenca entre os dois programas em assembly not vel O segundo claramente mais r pido pois evita todo o mecanismo de invocac o de func es Mas tamb m mais curto ou seja ocupa menos espa o na mem ria do computador Embora normal
62. BSTRACTOS DE DADOS E CLASSES C assert 0 lt denominador and mdc numerador denomina dor 1 and numerador d n denominador A Figura 7 4 mostra a nota o usada para representar a classe C Racional desenvolvida at aqui Racional atributo privado a THE rador int denominador int diese atributos opera o p blica sa constructor construtores Racional inn int 0 Racional inn int ind int query E opera es inspectores gt somaCom in r2 Racional Racional escreve update modificadores o OM le reduz opera o privada o Figura 7 4 A classe C Racional agora tamb m com opera es Note se a utiliza o de e para indicar a caracter sticas p blicas w privadas da classe C respectivamente e o termo in para indicar que o argumento da opera o Racional somaCom passado por valor ou seja apenas para dentro da operac o 7 4 2 Construtores por c pia Viu se que a linguagem fornece implicitamente um construtor por omiss o para as classes excepto quando estas declaram algum construtor explicitamente Algo de semelhante se passa relativamente aos chamados construtores por c pia Estes construtores s o usados para construir uma inst ncia de uma classe custa de outra inst ncia da mesma classe A linguagem fornece tamb m implicitamente um construtor por c pia desde que
63. Cap tulo 7 Tipos abstractos de dados e classes C In this connection it might be worthwhile to point out that the purpose of abstraction is not to be vague but to create a new semantic level in which one can be absolutely precise Edsger W Dijkstra The Humble Programmer Communications of the ACM 15 10 1972 Quando se fala de uma linguagem de programa o n o se fala apenas da linguagem em si com o seu l xico sintaxe gram tica e sem ntica Fala se tamb m de um conjunto de ferramen tas acess veis ao programador que n o fazendo parte da linguagem propriamente dita est o acess veis em qualquer ambiente de desenvolvimento de programas Ao conjunto dessas fer ramentas adicionais que se encontra em todos os ambientes de desenvolvimento chama se biblioteca padr o standard library Da biblioteca padr o do C fazem parte por exemplo os canais cin e cout que permitem leituras do teclado e escritas para o ecr o tipo string e o tipo gen rico vector Em rigor portanto o programador tem sua disposi o n o a lin guagem em si mas a linguagem equipada com a biblioteca padr o Para o programador no entanto tudo funciona como se a linguagem em si inclu sse essas ferramentas Isto para o programador em C o que est acess vel n o o C mas um C de que fazem parte todas as ferramentas da biblioteca padr o A tarefa de um programador resolver problemas usando pelo menos um computador F
64. S C COMO M DULOS Escrever resultado lt lt A soma de cou El cout r2 cou escreve lt lt com E escreve H lt lt ms r escreve cout lt lt lt lt endl 341 Note se que o compilador se encarrega de garantir que algumas inst ncias n o mudam de valor durante a execu o de um m todo o caso das constantes evidente pois que se essas constantes cumprem inicialmente a condi o invariante de classe tamb m a cumprir o no final no m todo pelo que se pode omitir a verifica o expl cita atrav s de uma instru o de asser o tal como se fez para o m todo somaCom 7 5 A Figura mostra a nota o usada para representar a condi o invariante da classe C Ra cional bem como a pr condi o e a condi o objectivo da opera o Racional somaCom Racional numerador int denominador int invariant 0 lt denominadorA mdc numerador denominador 1 constructor Racional inn int 0 Racional inn int ind int query somaCom in r2 Racional Racional escreve cumpreInvariante bool update le reduz precondition this r postcondition this rA somaltom r r2 Figura 7 5 A classe C Racional agora tamb m com opera es condi o invarian te de inst ncia e pr condic o e condi o objectivo indicadas para a ope
65. ST NCIA VERIFICANDO ERROS DURANTE A COMPILA O 375 Indica se o primeiro racional maior que o segundo Qpre V post operator gt r1 gt r2 bool operator gt Racional const rl Racional const r2 return 2 lt els Indica se o primeiro racional menor ou igual ao segundo pre V post operator lt r1 lt r2 bool operator lt Racional const rl Racional const r2 return not r2 lt r1 Indica se o primeiro racional maior ou igual ao segundo Qpre V post operator gt r1 gt r2 bool operator gt Racional const rl Racional const r2 return not rl lt r2 Curiosamente ou n o tamb m os operadores e se podem implementar custa apenas do operador lt Faz lo fica como exerc cio para o leitor 7 11 Const ncia verificando erros durante a compila o Uma boa linguagem de programa o permite ao programador escrever programas com um m nimo de erros Um bom programador que tira partido das ferramentas que a linguagem possui para reduzir ao m nimo os seus pr prios erros H tr s formas importantes de erros 1 Erros l gicos S o erros devidos a um racioc nio errado do programador a sua resolu o do problema incluindo algoritmos e estruturas de dados ainda que correctamente implementados n o leva ao resultado pretendido ou seja na realidade n o resolve o problema Este tipo de erro o mais dif cil de corrigir A facilidad
66. Vector dimens o 3 Infelizmente esta solu o n o compila correctamente que em C s se pode especificar a dimens o de uma matriz cl ssica usando um constante com valor conhecido pelo compilador Como um atributo de classe s inicializado na sua defini o que est fora da classe o atributo dimens o inicializado tarde demais o compilador engasga se na defini o da matriz membro dizendo que n o sabe o valor da constante Este problema n o em geral resol vel excepto quando o atributo de classe em defini o for de um tipo b sico inteiro do C Nesse caso poss vel fazer a defini o como inicializa o dentro da pr pria classe class Vector public static int const dimens o 3 Vector private 7 17 OUTROS ASSUNTOS ACERCA DE CLASSES C 435 double coordenadas dimens o Ah J funciona y onde a definic o externa classe deixa de ser necess ria Da mesma forma poss vel declarar opera es da classe C que n o precisam de ser invo cadas atrav s de nenhuma inst ncia s o as chamadas operac es de classe Suponha se por absurdo que se queria que a classe C Vector mantivesse uma contagem do n mero de inst ncias de si pr pria existente em cada instante Uma possibilidade seria class Vector public static int const dimens o 3 Vector static int n meroDeInst ncias private double coordenadas dimens o Ah J funcion
67. a static int n mero de inst ncias Vector Vector n mero_de_inst ncias inline int Vector n meroDelInst ncias return n mero_de_inst ncias int Vector n mero_de_inst ncias 0 Os membros de classe e n o de inst ncia s o precedidos do qualificador static aquando da sua declara o dentro da defini o da classe O atributo de classe n mero_de_inst ncias 436 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C declarado durante a defini o da classe e s definido i e constru da de facto com o valor inicial 0 depois da classe C tal como acontece com as rotinas membro O contador de inst ncias acima tem dois problemas O primeiro que a contabiliza o falha se algum vector for constru do por c pia a partir de outro vector Vector vl Ok incrementa contador Vector v2 v1 Erro N o incrementa contador Para j ignorar se este problema at porque s se falar do fornecimento expl cito de cons trutores por c pia que substituem o construtor por c pia fornecido implicitamente pela lin guagem num cap tulo posterior O segundo problema que a contabiliza o falha quando se destr i alguma inst ncia da classe 717 3 Destrutores Da mesma forma que os construtores de uma classe C s o usados para inicializar as su as inst ncias quando estas s o constru das podem se usar destrutores i e c digo que deve executado quando a ins
68. a o Racional extraiDe 7 16 C digo completo do TAD Racional O TAD Racional foi concretizado na forma de uma classe C com o mesmo nome e de rotinas n o membro associadas Conceptualmente o TAD definido pelas respectivas opera es pelo que a classe C n o suficiente para o concretizar faltam as rotinas associadas que n o s o membro da classe Ou seja as rotinas que operam com racionais fazem logicamente parte do TAD mesmo n o pertencendo classe C que o concretiza Note se que se concentraram as declara es das rotinas no in cio do c digo pois fazem lo gicamente parte da interface do TAD tendo se colocado a respectiva defini o no final do c digo junto com a restante implementa o do TAD Esta organiza o ser til aquando da organiza o do c digo em m dulos f sicos ver 9 de modo a permitir a f cil utiliza o do TAD desenvolvido em qualquer programa tinclude lt iostream gt finclude lt cctype gt tinclude lt cassert gt using namespace std Devolve o m ximo divisor comum dos inteiros passados como argumento Qpre V 7 16 C DIGO COMPLETO DO TAD RACIONAL 419 _ mdc m n m X 0Vn 0 post nac 1 o E int mdc int const m int const n Representa n meros racionais Qinvariant 0 lt denominador Amdc numerador denominador 1 class Racional public Constr i racional com valor inteiro Construtor por omiss o Qpre V post this
69. a classe a solu o foi delegar a tarefa da extrac o ou leitura para uma opera o da classe que n o tem quaisquer restri es de acesso 7 14 3 Lidando com erros No in cio deste cap tulo apresentou se a primeira vers o da rotina de leitura de racionais ent o vistos simplesmente como frac es sem mais explica es Chegou agora a altura de explicar o c digo dessa rotina entretanto convertida na opera o Racional extraiDe apresen tada abaixo sem instru es de asser o i e reduzida ao essencial void Racional extraiDe istream amp entrada Int np OS if entrada gt gt n gt gt d if d 0 entrada setstate ios_base failbit else numerador d lt 0 n n denominador_ d lt 0 d d reduz Em primeiro lugar note se que a extrac o do numerador e do denominador se faz n o direc tamente para os respectivos atributos mas para duas vari veis criadas para o efeito De outra forma se a extrac o do numerador tivesse sucesso mas a extrac o do denominador falhasse a extrac o do racional como um todo teria falhado e este teria mudado de valor o que para al m de ser m ideia violaria o estabelecido no contrato da opera o Usa se o idioma do C if entrada gt gt n gt gt d para fazer simultaneamente a extrac o dos dois valores inteiros canal de entrada e verificar se essa leitura teve sucesso Esta instru o poderia e talvez devesse ser
70. a condi o invariante de classe Claramente o denominador d positivo pelo que resta verificar se mdc n d d 1 Suponha se que existe um divisor 1 lt k comum ao numerador e ao denominador Nesse caso existem n e d tais que kn n d e kd d de onde se conclui facilmente que kn n kd ou seja n k n d S que isso significaria que 1 lt k lt mdc n d o que contradit rio com a hip tese de partida de que mdc n d 1 Logo n o existe divisor comum ao numerador e denominador superior unidade ou seja mdc n d d 1 como se queria demonstrar 358 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C assert cumpreInvariante numerador denominador assert cumpreInvariante return n o se necessitando de reduzir a frac o depois desta opera o Falta resolver um problema que o que devolver no final do m todo Depois da discus s o anterior com a rotina incrementa deve j ser claro que se deseja devolver o pr prio operando do operador que neste caso corresponde vari vel impl cita Como se viu atr s poss vel explicitar a vari vel impl cita usando a constru o this pelo que o c digo fica simplesmente Racional amp Racional operator assert cumpreInvariante numerador denominador assert cumpreInvariante return this A necessidade de devolver a pr pria vari vel impl cita ficar porventura mais clara se se ob se
71. a deixar claro que a invoca o da opera o n o afecta a inst ncia impl cita Mais tarde se ver uma forma mais elegante de garantir a const ncia da inst ncia impl cita du rante a execu o de um m todo i e uma forma de garantir que a inst ncia impl cita tratada como uma constante impl cita mesmo que na realidade seja uma vari vel Resolvemos o problema do acesso aos atributos privados para o procedimento escreve transformando o em procedimento membro da classe C E necess rio fazer o mesmo para todas as outras rotinas que acedem directamente aos atributos tinclude lt iostream gt tinclude lt cassert gt 70 significado do operador ficar claro em cap tulos posteriores 320 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C using namespace std Devolve o m ximo divisor comum dos inteiros passados como argumento Oprem mAn n _ mdc m n m XOVn 0 post mac A a t int mdc int m int n Representa n meros racionais class Racional public Escreve o racional no ecr no formato de uma frac o Qpre this r Qpost this rA coutV cout cont m n d ou simplesmente n se d 1 sendo Ga frac o can nica correspondente ao racional this void escreve Devolve a soma com o racional recebido como argumento pre denominador 0 A r2 denominador 0 A this r Opost this r A somaCom this r2 A denominador 0A somaCo
72. a segunda ins tru o ter uma interpreta o alternativa a de declarar uma fun o r que n o tem par metros e devolve um valor Racional Face a esta ambiguidade de interpreta o a linguagem optou por dar prefer ncia declara o de uma fun o Aquando da constru o de uma inst ncia de uma classe C um dos seus construtores in vocado Antes mesmo de o seu corpo ser executado no entanto todos os atributos da classe s o constru dos Se se pretender passar argumentos aos construtores dos atributos ent o obrigat ria a utiliza o de listas de utilizadores que se colocam na defini o do construtor entre o cabe alho e o corpo ap s o s mbolo dois pontos Esta lista consiste no nome dos atributos pela mesma ordem pela qual est o definidos na classe C seguido cada um dos ar gumentos a passar ao respectivo construtor colocados entre par nteses No caso da classe C Racional pretende se inicializar os atributos numerador e denominador respectivamente com os valores 0 e 1 pelo que a lista de inicializadores Racional Racional numerador 0 denominador 1 Uma vez que se pretendem mais duas formas de inicializa o dos racionais necess rio forne cer dois construtores adicionais O primeiro constr i um racional a partir de um nico inteiro o que quase t o simples como construir um racional com o valor zero O segundo um pouco mais complicado pois construindo um racional a partir do
73. acional const amp r2 assert cumpreInvariante and r2 cumpreInvariante assert r2 0 int dn mdc numerador_ r2 numerador_ int dd mdc denominador r2 denominador if r2 numerador lt 0 numerador numerador_ dn r2 denominador_ dd denominador denominador dd r2 numerador_ dn else numerador_ numerador_ dn r2 denominador_ dd denominador denomina dor dd r2 numerador dn assert cumpreInvariante return this 400 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C 713 4 Sim trico e identidade O caso das opera es de c lculo do sim trico e da identidade _ A ES a d gt y E do d n o p e qualquer problema pois os resultados est o sempre no formato can nico 7 13 5 Opera es de igualdade e relacionais Sendo dois racionais r e r2 e as respectivas representa es na forma de frac es can nicas ri T ero R evidente que r rz se e s se n n2 Ady d2 Da mesma forma r ra se e s sen Z na V dy do Relativamente aos mesmos dois racionais a express o r lt r2 equivalente a lt F ou ainda a nyd gt lt nad pois ambos os denominadores s o positivos Assim poss vel comparar dois racionais usando apenas compara es entre inteiros Os inteiros a comparar podem ser reduzidos calculando k mdc d1 do e l mdc n1 n2 e dividindo os termos apropriados da express
74. acionals Racional operator Racional const r2 assert cumpreInvariante and r2 cumpreInvariante numerador numerador r2 denominador r2 numerador denominador denominador r2 denominador reduz assert cumpreInvariante return this Racionals Racional operator Racional const r2 assert cumpreInvariante and r2 cumpreInvariante numerador numerador r2 denominador 7 8 MAIS OPERADORES PARA O TAD RACIONAL 367 r2 numerador denominador denominador r2 denominador reduz assert cumpreInvariante return this 7 8 2 Operadores aritm ticos Os operadores aritm ticos usuais podem ser facilmente implementados custa dos operado res especiais de atribui o Implementar se o aqui como rotinas normais n o membro por raz es que ser o clarificadas em breve Come ar se pelo operador A ideia criar uma vari vel local tempor ria cujo valor inicial seja uma c pia do primeiro operando e em seguida usar o operador para proceder soma Produto de dois racionais Qpre V post operator r1 x r2 Racional operator Racional const rl Racional const r2 Racional auxiliar rl auxiliar r2 return auxiliar Observando cuidadosamente este c digo conclui se facilmente que o par metro r1 desde que deixe de ser constante pode fazer o papel da vari vel auxiliar visto que a passagem se faz por valor Produto de dois raciona
75. ador A mdc n denominador 1 El int denominador const Escreve o racional no ecr no formato de uma frac o Qpre V post coutV cout cont m n d ou simplesmente n se d 1 sendo Za frac o can nica correspondente ao racional this void escreve const private Indica se a condi o invariante de classe se verifica Qpre V post cumpreInvariante 0 lt denominador Amdc numerador denominador 1 bool cumpreInvariante const y int Racional numerador const assert cumpreInvariante return numerador_ int Racional denominador const assert cumpreInvariante return denominador void Racional escreve const assert cumpreInvariante cout lt lt numerador_ 7 11 CONST NCIA VERIFICANDO ERROS DURANTE A COMPILA O 385 if denominador 1 cout lt lt lt lt denominador bool Racional cumpreInvariante const return 0 lt denominador and mdc numerador denomina dor_ 1 Note se que nas opera es que garantem a const ncia da inst ncia impl cita tendo se veri ficado a veracidade da condi o invariante de classe no seu in cio n o necess rio voltar a verific la no seu final Note se tamb m que pela sua natureza a opera o que indica se a condi o invariante de inst ncia se verifica tipicamente chamada cumpreInvariante uma opera o constante interessante verificar que uma classe C tem
76. ais mas n o que s o id nticos pois s o indiv duos diferentes Por outro lado pode se dizer que Fernando Pessoa e Alberto Caeiro n o s o apenas iguais mas tamb m id nticos pois s o nomes que se referem mesma pessoa 354 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C vi int amp gt v int amp v int amp v int amp retorno retorno Y int retorno retorno Vi int amp a4 a4 a5 a5 SINE ESTNE il int TESIC AE 1 int TELNE 0 0 1 F 1 KF 1 22 NS 2 ZA a b c d e f g Figura 7 7 Estado da pilha durante a execu o a Imediatamente antes das invoca es nas linhas 3 e 4 b imediatamente antes da instru o 1 depois de invocada a rotina pela primeira vez j com o par metro v na pilha c entre as instru es 1 e 2 j depois de incrementado v e portanto i pois v sin nimo de i d imediatamente ap s a primeira invoca o da rotina e imediatamente antes da sua segunda invoca o j com os par metros retirados da pilha sendo de notar que a refer ncia devolvida se encontra no topo da pilha e imediatamente antes da instru o 1 depois de invocada a rotina pela segunda vez tendo a refer ncia v sido inicializada custa da refer ncia no topo da pilha e portanto sendo v sin nimo de i f entre as instru es 1 e 2 j depois de incrementado v e portanto j de
77. al Opre this rAr2 0 post operator thisA this r r2 Racional amp operator Racional const amp r2 380 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C y Racionalg Racional operator Racional const r2 assert cumpreInvariante and r2 cumpreInvariante numerador numerador r2 denominador r2 numerador denominador denominador r2 denominador reduz assert cumpreInvariante return this Racional amp Racional operator Racional const amp r2 assert cumpreInvariante and r2 cumpreInvariante assert r2 0 int numerador2 r2 numerador_ if r2 numerador_ lt 0 numerador_ r2 denominador_ denominador_ numerador2 else numerador_ r2 denominador_ denominador numerador2 reduz assert cumpreInvariante return this Adi o de dois racionais 7 11 CONST NCIA VERIFICANDO ERROS DURANTE A COMPILA O 381 Qpre r1 r post operator r 12 Racional operator Racional rl Racional const amp r2 return rl r2 Preservou se a passagem por valor do primeiro argumento do operador por ser desej vel que nesse caso o par metro seja uma c pia do argumento de modo a sobre ele se poder utilizar o operador de notar uma altera o importante defini o da sobrecarga do operador passou a ser feita um c pia do numerador do segundo operando representado pelo par metr
78. amb m deixa de ser poss vel Que fazer 7 3 5 Rotinas membro opera es e m todos Uma vez que a membros privados t m acesso quaisquer outros membros da classe a solu o passa por tornar as rotinas existentes membros da classe C Racional Come ar se por tornar o procedimento escreve membro da classe i e por transform lo de simples rotina em opera o do TAD em concretiza o Representa n meros racionais class Racional public Escreve o racional no ecr no formato de uma frac o Qpre this r Opost this rA ncoutV cout cont m n d ou simplesmente n se d 1 sendo Za frac o can nica correspondente ao racional this void escreve Declara o da rotina membro opera o private 318 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C int numerador int denominador y Defini o da rotina membro m todo void Racional escreve cout lt lt numerador if denominador 1 cout lt lt lt lt denominador S o de notar quatro pontos importantes 1 Para o consumidor da classe C poder invocar a nova opera o necess rio que esta seja p blica Da o especificador de acesso public que coloca a nova opera o es creve na interface da classe C 2 Qualquer opera o ou rotina membro de uma classe C tem de ser declarada dentro da defini o dessa classe e definida fora ou alternativamente definida e portanto tamb m dec
79. ao novo tipo Racional da mesma forma que se tinha visto antes relativamente aos tipos enumerados ver Sec o 6 1 Mas ao contr rio do que se fez ent o agora as fun es de sobrecarga t m de ser membros da classe Racional de modo a poderem aceder aos seus membros privados alternativamente poder se iam usar fun es membro amigas da classe Sec o 7 15 Ou seja a solu o simplesmente alterar o nome da opera o Racional somaCom de somaCom para operator Representa n meros racionais Qinvariant O lt denominador A mdc numerador denominador 1 class Racional 7 5 SOBRECARGA DE OPERADORES 343 public Devolve a soma com o racional recebido como argumento Qpre this r post this r A operator this r2 Racional operator Racional const r2 private Racional Racional operator Racional const r2 Tal como acontecia com a express o rl somaCom r2 a express o r1 operator r1 in voca a opera o operator da classe C Racional usando r1 como inst ncia vari vel impl cita S que agora poss vel escrever a mesma express o de uma forma muito mais clara e intuitiva Ed FYZ De facto sempre que se sobrecarregam operadores usando opera es o primeiro operando que pode ser o nico no caso de operadores un rios i e s com um operando sempre a inst ncia impl cita durante a execu o do respectivo m todo sendo os resta
80. as opera es Todas as opera es inspectoras s o naturalmente opera es constantes Embora tamb m seja comum dizer se que as opera es constantes s o inspectoras neste texto reserva se o nome inspector para as opera es que devolvam propriedades da inst ncia para a qual s o invoca dos Pelo contr rio s opera es que alteram a inst ncia impl cita ou que a permitem alterar indirectamente chama se normalmente opera es modificadoras embora tamb m seja poss vel distinguir entre v rias categorias de opera es n o constantes Resta pois qualificar como constantes todas as opera es e respectivos m todos que garantem a const ncia da inst ncia impl cita class Racional public Devolve numerador da frac o can nica correspondente ao racional Qpre V numerador _ _ epost denominador this int numerador const Devolve denominador da frac o can nica correspondente ao racional Qpre V Exactamente da mesma forma que as pr condi es n o se referem normalmente ao tipo dos par metros e g o primeiro par metro tem de ser um int pois esse facto expresso na pr pria linguagem C e garantido pelo P P 8 compilador bem quase sempre como se ver quando se distinguir tipo est tico de tipo din mico 384 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C denominador post En V this A 0 lt denomin
81. asse n o pode perversa ou acidentalmente alterar os valores dos atributos de tal forma que um inst ncia da classe C deixe de estar num estado v lido Este assunto ser retomado com maior pormenor mais abaixo quando se falar da chamada CIC Condi o Invariante de Classe As classes C possuem tamb m um manual de utiliza o correspondente ao contrato entre o seu produtor e os seus consumidores Esse contrato normalmente expresso atrav s de um coment rio de documenta o para a classe em si e dos coment rios de documenta o de todas os seus membros p blicos 7 41 Construtores Suponha se o c digo Racional a a numerador 1 a denominador 3 ou Racional a 1 3 A partir do momento em que os atributos da classe passaram a ser privados ambas as formas de inicializa o deixaram de ser poss veis Como resolver este problema Para os tipos b sicos da linguagem a inicializa o faz se usando uma de duas poss veis sinta xes int a 10 ou int a 10 Na realidade no primeiro tro o de c digo n o se faz uma inicializa o As opera es de atribui o alteram os valores dos atributos j inicializados ou melhor a atributos deixados por inicializar pelas regras absurdas impor tadas da linguagem C e por isso contendo lixo 7 4 CLASSES C COMO M DULOS 325 Se realmente se pretende que a nova classe C Racional represente um tipo de primeira categoria importante fornecer
82. asse podem pertencer a uma de tr s categorias de acesso p blico protegido e privado Para j apenas se descrever o a primeira e a ltima Membros p blicos introduzidos pelo especificador de acesso public s o acess veis sem qualquer restri o Membros privados introduzidos pelo especificador de acesso private s o acess veis apenas por membros da mesma classe ou alternativamente por fun es ami gas da classe que ser o vistas mais tarde Fazendo uma analogia de uma classe com um clube dir se ia que h certas partes de um clube que est o abertas ao p blico e outras que est o disposi o apenas dos seus membros O consumidor de um rel gio ou de um micro ondas assume que n o precisa de conhecer o funcionamento interno desses aparelhos podendo recorrer apenas a uma interface Assim o produtor desses aparelhos normalmente esconde o seu mecanismo numa caixa deixando no exterior apenas a interface necess ria para o consumidor Tamb m o produtor da classe C Racional deveria ter escondido os pormenores de implementa o da classe C do consumidor final Podem se resumir estas ideias num princ pio b sico da programa o Princ pio do encapsulamento O produtor deve esconder do consumidor final tudo o que puder ser escondido I e os pormenores de implementa o devem ser escondidos devendo se fornecer interfaces limpas e simples para a manipula o das entidades fabricadas aparelhos de cozinha rel
83. c str if not entrada cerr lt lt Opps N o consegui ligar a ficheiro N lt lt nome do ficheiro lt lt X lt lt endl Racional r entrada gt gt r Se num mesmo programa se escreve e l de um mesmo ficheiro poss vel usar canais que permitem simultaneamente inser es e extrac es Por m a forma mais simples alternar 7 15 AMIZADES E PROMISCUIDADES 415 escritas e leituras no mesmo ficheiro usando canais diferentes desde que se garanta que todos os dados inseridos no respectivo canal de sa da foram j escritos no respectivo ficheiro antes de os tentar extrair a partir de um canal de entrada ligado ao mesmo ficheiro Repare se nas linhas finais do teste de unidade do TAD Racional Racional r1 2 6 Racional r2 3 ofstream sa da teste satda lt lt XL lt lt P lt lt 2 sa da close S o fecho expl cito garante que a extrac o do canal entrada tem sucesso ifstream entrada teste Racional r4 r5 entrada gt gt r4 gt gt r5 7 15 Amizades e promiscuidades 7 15 1 Rotinas amigas H casos em que pode ser conveniente definir rotinas normais i e n o membro que tenham acesso aos membros privados de uma classe C Por exemplo suponha se que se pretendia definir a rotina operator gt gt para a classe C Racional como se fez mais atr s mas sem delegar o trabalho na opera o Racional extraiDe Nesse caso podia se tentar definir a rotina como
84. cilmente desligadas 1 O construtor para construir r que invoca a opera o Racional reduz cujo m todo invoca a fun o mdc 2 3 4 O construtor para converter implicitamente o valor literal 2 num racional 5 O construtor por c pia ver Sec o 7 4 2 para copiar o argumento r para o par metro r1 durante a invoca o d a fun o operator que invoca a opera o Racional operator cujo m todo invoca a opera o Racional reduz cujo m todo invoca 0 N ON a fun o mdc 10 O construtor por c pia para devolver r1 por valor na fun o operator 11 O construtor por c pia para construir a vari vel s custa da constante tempor ria de volvida pela fun o operator Mesmo tendo em conta que o compilador pode eventualmente optimizar algumas destas in voca es 11 invoca es para duas inocentes linhas de c digo parece demais N o ser lento Como evit lo A linguagem C fornece uma forma simples de reduzir o peso da arruma o da casa aquando da invoca o de uma rotina rotinas muito simples tipicamente n o fazendo uso de ciclos e consistindo em apenas duas ou tr s linhas excluindo instru es de asser o po dem qualificadas como em linha ou inline A palavra chave inline pode ser usada para este efeito qualificando se com ela as defini es das rotinas que se deseja que sejam em linha Mas o que significa a defini o de uma
85. cional 3 4 Racional 7 9 assert rl Racional 11 6 Racional 47 18 assert rl Racional 2 18 Racional 5 2 assert rl r2 Racional 11 2 assert rl Racional 5 7 Racional 25 14 assert rl 40 100 assert 30 ri 12 ofstream sa da teste sa da lt lt rl lt lt lt lt r2 sa da close ifstream entrada teste Racional r4 r5 entrada gt gt r4 gt gt ro assert rl r4 assert r2 r5 7 7 DEVOLU O POR REFER NCIA 349 tendif TESTE S o de notar os seguintes pontos e Alguma da sintaxe utilizada neste teste s ser introduzida mais tarde O leitor deve regressar a este teste quando o TAD Racional for totalmente desenvolvido e Cada teste consiste essencialmente numa instru o de asser o H melhores formas de escrever os testes de unidade sem recorrer a asser es nomeadamente recorrendo a bibliotecas de teste Mas tais bibliotecas est o fora do mbito deste texto e O teste consiste numa fun o main De modo a n o entrar em conflito com a fun o main do programa propriamente dito envolveu se a fun o main de teste entre duas directivas de pr compila o tifdef TESTE e fendif TESTE Isso faz com que toda a fun o s seja levada em conta pelo compilador quando estiver definida a macro TESTE coisa que num compilador em Linux se consegue tipicamente com a op o de compila
86. crita pode falhar Por exemplo o disco r gido pode estar cheiro pode n o haver permiss es para escrever no direct rio em causa ou pode existir j um ficheiro com o mesmo nome protegido para escrita Se o estabelecimento do canal falhar durante a sua constru o este fica em estado de erro sendo muito f cil verificar essa situa o tratando o canal como se de um booleano se tratasse cout lt lt Diga o nome do ficheiro string nome do ficheiro cin gt gt nome do ficheiro ofstream sa da nome do ficheiro c str if not sa da cerr lt lt Opps N o consegui criar ficheiro lt lt nome do ficheiro lt lt X lt lt endl ainda poss vel estabelecer e encerrar um canal usando as opera es ofstream open que recebe o nome do ficheiro como argumento e ofstream close que n o tem argu mentos S se garante que todos os dados inseridos num canal ligado a um ficheiro j nele foram escritos se 7 14 OPERADORES DE INSER O E EXTRAC O 413 1 o canal tiver sido explicitamente encerrado atrav s da opera o ostream close 2 o canal tiver sido destru do da forma usual e g no final do bloco onde a vari vel que o representa est definida 3 tiver sido invocada a opera o ostream flush 4 tiver sido inserido no canal o manipulador flush ie sa da lt lt flush ou 5 tiver sido inserido no canal o manipulador end ie sa da lt lt endl que col
87. de perfeitamente ser negativo Prevendo esse caso o c digo fica if r2 numerador lt O numerador r2 denominador denominador r2 numerador else numerador r2 denominador denominador r2 numerador tal como se pode encontrar no no m todo acima Relativamente ao operador poss vel resolver o problema de duas formas A mais simples neste momento implementar o operador custa do operador pois este j est definido Nesse caso a solu o Racional amp Racional operator Racional const r2 assert cumpreInvariante and r2 cumpreInvariante this this r2 assert cumpreInvariante return this Esta soluc o no entanto tem o inconveniente de obrigar realizac o de v rias c pias entre racionais al m de exigir a construc o de um racional tempor rio para guardar o resultado 366 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C da adi o antes de este ser atribu do vari vel impl cita Como se ver a melhor solu o desenvolver o operador de raiz e implementar o operador sua custa Os operadores e sobrecarregam se de forma muito semelhante class Racional public Adiciona de um racional Opre this r post operator thisA this r r2 Racional amp operator Racional r2 Subtrai de um racional pre this r Opostoperator thisA this r r2 Racional amp operator Racional r2 y R
88. de que o TAD Racional possa ser usado como qualquer tipo b sico da linguagem desej vel encontrar uma forma de proibir a invoca o de opera es modificadoras atrav s de inst ncias tempor rias 386 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C luz da discuss o na sec o anterior f cil perceber que o problema se resolve se as fun es que devolvem inst ncias tempor rias de classes C i e as fun es que devolvem inst ncias de classes C por valor forem alteradas de modo a devolverem constantes tempor rias e n o vari veis No caso do TAD em desenvolvimento s o apenas as rotinas que sobrecarregam os operadores aritm ticos usuais e os operadores de incrementa o e decrementa o sufixo que precisam de ser alteradas Adi o de dois racionais pre r1 r1 post operator r 12 Racional const operator Racional rl Racional const amp r2 return rl r2 Subtracc o de dois racionais pre r1 r1 post operator r r2 Racional const operator Racional rl Racional const amp r2 return rl r2 Produto de dois racionais pre r1 r post operator rj x 12 Racional const operator Racional rl Racional const amp r2 return rl r2 Divis o de dois racionais pre r1 r A r2 0 post operator r r2 Racional const operator Racional rl Racional const amp r2 assert r2 0 return rl r2
89. declara o de amizade feita na parte p blica ou na parte privada da classe No entanto sendo as amizades uma quest o de implementac o desej vel colocar a declarac o na parte privada da classe tipicamente no seu final 7 15 AMIZADES E PROMISCUIDADES 417 class Racional public private friend istream operator gt gt istream amp entrada Racional amp r y Qualquer rotina n o membro que fa a uso de uma classe C conceptualmente parte das opera es que concretizam o comportamento desejado para o correspondente TAD No entan to se uma rotina n o membro n o for amiga da classe C embora seja parte da implemen ta o do TAD n o parte da implementa o da correspondente classe C Isso deve se ao facto de n o ter acesso s suas partes privadas e por isso n o ter nenhuma forma directa de afectar o estado das suas inst ncias Por m a partir do momento em que uma rotina se torna amiga de uma classe C passa a fazer parte da implementa o dessa classe por isso que a rotina operator gt gt definida acima se preocupa com o cumprimento da condi o invariante de classe se pode afectar directamente o estado das inst ncias da classe bom que assim seja que o produtor de uma rotina n o membro amiga de uma classe deve ser visto como pro dutor da classe C respectiva enquanto o produtor de uma rotina n o membro e n o amiga que fa a uso de uma classe n o pode ser visto como produtor des
90. decomposta em duas 408 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C entrada gt gt n gt gt d if entrada A primeira destas instru es serve para fazer as duas extrac es Tal como se viu para o ope rador lt lt a primeira instru o interpretada como entrada gt gt n gt gt d devido associatividade esquerda do operador gt gt Que acontece quando a primeira extrac o falha por exemplo quando no canal n o se encontra uma sequ ncia de d gitos interpret vel como um n mero inteiro mas sim por exemplo caracteres alfab ticos Nesse caso a primeira extrac o n o tem qualquer efeito e o canal entrada fica em estado de erro Nesse caso a segunda falhar tamb m pois todas as opera es de inser o e extrac o realizadas sobre um canal em estado de erro est o condenadas ao fracasso Ou seja se a primeira opera o falhar a segunda n o tem qualquer efeito o que equivalente a n o ser realizada Como o valor de um canal interpretado como um valor booleano verdadeiro se o canal n o estiver em estado de erro e falso se estiver as instru es acima s o equivalentes a if not entrada fail entrada gt gt n if entrada fail entrada gt gt d if entrada fail onde istream fail uma opera o da classe i stream que indica se o canal est em estado de erro Uma vez realizadas as duas extrac es com sucesso necess rio verificar ainda assim se os va
91. e Declara o da rotina membro opera o 338 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Devolve a soma com o racional recebido como argumento Qpre this r post this r A somaCom this r2 Racional somaCom Racional const 12 L do teclado um novo valor para o racional na forma de dois inteiros sucessi vos Qpre this r QpostSe cin e cin tem dois inteiros n e d dispon veis para leitu ra com d 0 ent o this 24 Acin sen o this rArcin void 1 private int numerador int denominador Reduz a frac o que representa o racional Qpre denominador this r post denominador 4 0 A mdc numerador denominador 1A this r void reduz Indica se a condi o invariante de classe se verifica Qpre this r Qpost this r A cumpreInvariante 0 lt denominador A mdc numerador denominador 1 bool cumpreInvariante y Racional Racional int const n numerador n denominador 1 assert cumpreInvariante assert numerador n denominador Racional Racional int const n int const d numerador d lt 0 2 n n denominador d lt 0 d d assert d 0 7 4 CLASSES C COMO M DULOS 339 reduz assert cumpreInvariante assert numerador d n denominador void Racional escreve assert cumpreInvariante cout lt lt numerador if denominador 1 cou
92. e a preocupar se com o comportamento exterior do tipo Pelo contr rio para o produtor da classe C a representa o dos racionais fundamental pois ele que tem de garantir que todas as opera es cumprem o respectivo contrato A invoca o da opera o Racional reduz no m todo Racional 1 feita sem necessidade de usar a sintaxe usual para a invoca o de opera es i e sem indicar expli citamente a inst ncia atrav s da qual e para a qual essa invoca o feita Isso deve se ao facto de se pretender fazer a invoca o para a inst ncia impl cita Seria poss vel explicitar essa inst ncia this reduz tal como de resto poderia ter sido feito para os atributos this numerador n mas isso conduziria apenas a c digo mais denso Note se que os par nteses em volta de this s o fundamentais pois o operador de selec o de membro tem maior preced ncia que o ope rador un rio conte do de a estudar mais tarde tamb m importante perceber se que n o existe qualquer vantagem em tornar a fun o mac membro na nova classe C Em primeiro lugar pode haver necessidade de calcular o m ximo divisor comum de outros inteiros que n o o numerador e o denominador Ali s tal necessida de surgir ainda durante este cap tulo Em segundo lugar porque o c lculo do m ximo divisor comum poder ser necess rio em contextos que nada tenham a ver com n meros racionais Finalmente a nota
93. e ou dificuldade da sua detec o varia bastante conforme os casos mas comum que ocorram erros l gicos de dif cil detec o 2 Erros de implementa o Ao implementar a resolu o do problema idealizada foram co metidos erros n o sint cticos ver abaixo i e o programa n o uma implementa o do algoritmo idealizado Erros deste tipo s o f cil de corrigir desde que sejam detectados A detec o dos erros tanto pode ser f cil como muito dif cil por exemplo quando os erros 376 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C ocorrem em casos fronteira que raramente ocorrem na pr tica ou quando o programa produz resultados que sendo errados parecem plaus veis 3 Erros sint cticos S o gralhas O pr prio compilador se encarrega de os detectar S o f ceis de corrigir Antes de um programa ser disponibilizado ao utilizador final testado Antes de ser testado compilado Antes de ser compilado desenvolvido Com excep o dos erros durante o de senvolvimento claro que quanto mais cedo no processo ocorrerem os erros mais f ceis ser o de detectar e corrigir e menor o seu impacte Assim uma boa linguagem aquela que permite que os inevit veis erros sejam sobretudo de compila o detectados facilmente pelo compi lador e n o de implementa o ou l gicos detectados com dificuldade pelo programador ou pelos utilizadores do programa Para evitar os erros l gicos uma linguage
94. ecer tamb m todas as restantes pr condi es tornando o programa capaz de lidar com frac es com termos negativos e O ciclo usado na fun o madc foi optimizado passando a usar se um ciclo pouco or todoxo com duas poss veis sa das Fica como exerc cio para o leitor demonstrar o seu correcto funcionamento e verificar a sua efici ncia e Foram acrescentadas rotinas para a leitura e c lculo da soma de duas frac es e Nas rotinas lidando com frac es alterou se o nome das vari veis para explicitar melhor aquilo que representam e g numerador em vez de n e Para evitar c digo demasiado extenso para uma vers o impressa deste texto cada rotina definida antes das rotinas que dela fazem uso n o se fazendo uma distin o clara entre declara o e defini o Mais tarde ser ver que esta n o for osamente uma boa solu o e Uma vez que a pr condi o e a condi o objectivo s o facilmente identific veis pela sua localiza o na documenta o das rotinas ap s Opre e Qpost respectivamente abandonou se o h bito de nomear essas condi es PC e CO e Protegeu se de erros a leitura das frac es ver Sec o 7 14 tinclude lt iostream gt tinclude lt cassert gt using namespace std Devolve o m ximo divisor comum dos inteiros passados como argumento Oprem mAn n mde m n m 0Vn 0 1 m 0An 0 int mdc int m int n post mdc i if m 0 and n 0 ret
95. emas graves de implementa o O primeiro tem a ver com a facilidade com que permite realizar algumas opera es Por exemplo muito f cil verificar a igualdade de dois racionais comparando simplesmente os seus numeradores e denominadores coisa que s poss vel fazer directamente se se garantir que as frac es que os representam est o no formato can nico O segundo problema tem a ver com as limita es dos inteiros Suponha se o seguinte c digo int main 1 Racional x 50000 50000 y 1 50000 Racional z x soma y z escreve cout lt lt endl No ecr deveria aparecer 1 50000 N o se usando uma representa o em frac es can nicas ao se calcular o denominador do re sultado i e ao se multiplicar os dois denominadores obt m se 50000 x 50000 2500000000 Em m quinas em que os int t m 32 bits esse valor n o represent vel pelo que se obt m um valor errado em Linux 1386 obt m se 1794967296 apesar de a frac o resultado ser perfeita mente represent vel Este problema pode ser mitigado se se trabalhar sempre com frac es no formato can nico Mesmo assim o problema n o totalmente resolvido Suponha se o seguinte c digo int main Racional x 1 50000 y 1 50000 Racional z x soma y z escreve cout lt lt endl No ecr deveria aparecer 1 25000 mas ocorre exactamente o mesmo problema que anteriormente pois desej vel n o s usar uma repres
96. enta o can nica para os racionais como tamb m tentar garantir que os resultados de c lculos interm dios s o t o pequenos quanto poss vel Este assunto ser retomado mais tarde Sec o 7 13 334 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C 7 4 5 Explicita o da condi o invariante de classe A condi o invariante de classe til n o apenas como uma ferramenta formal que permite verificar o correcto funcionamento de por exemplo um m todo til como ferramenta de detec o de erros Da mesma forma que conveniente explicitar pr condi es e condi es objectivo das rotinas atrav s de instru es de asser o tamb m o no caso da condi o in variante de classe A inten o detectar as viola es dessa condi o durante a execu o do programa e abort lo se alguma viola o for detectada A condi o invariante de classe claramente uma no o de implementa o refere se sempre aos atributos que se presume serem privados de uma classe Uma das vantagens de se esta belecer esta distin o clara entre interface e implementa o est em permitir altera es subs tanciais na implementa o sem que a interface mude De facto perfeitamente poss vel que o programador produtor mude substancialmente a implementa o de uma classe C sem que isso traga qualquer problema para o programador consumidor que se limita a usar a interface da classe C A mudan a da im
97. gios rotinas C classes C etc Isso consegue se no caso das classes C usando o especificador de acesso private para esconder os membros da classe Representa n meros racionais class Racional 7 3 REPRESENTA O DE RACIONAIS POR FRAC ES 317 private int numerador int denominador y Ao se classificar os membros numerador e denominador como privados n o se impede o programador consumidor de usando mecanismos mais ou menos obscuros e perversos ace der ao seu valor O facto de um membro ser privado n o coloca barreiras muito fortes quanto ao seu acesso Pode se dizer que funciona como um aviso esse sim forte de que o progra mador consumidor n o deve aceder a eles para seu pr prio bem o produtor poderia por exemplo decidir alterar os nomes dos membros para n e d com isso invalidando c digo que fizesse uso directo dos membros da classe O compilador encarrega se de gerar erros de com pilac o por cada acesso ilegal a membros privados de uma classe Assim claro que os membros privados de uma classe C fazem parte da sua implementa c o enquanto os membros p blicos fazem parte da sua interface Tornados os atributos da classe privados torna se imposs vel no procedimento 1 atribuir valores directamente aos seus membros Da mesma forma todas as outras rotinas deixam de poder aceder aos atributos da classe A inicializac o t pica dos agregados por exemplo Racional rl 6 9 t
98. ia Repare se na condi o objectivo desta rotina e compare se com a usada para a vers o anterior da mesma rotina em que se devolvia por valor neste caso neces s rio dizer que o que se devolve n o apenas igual a i mas tamb m id ntico a i ou seja o pr prio i como se pode ver na Figura 7 71 Para isso usou se o s mbolo em vez do usual Para se compreender bem a diferen a entre a devolu o por valor e devolu o por refer ncia comparem se as duas rotinas abaixo int c pia int v return v int amp mesmo int amp v return v A primeira rotina devolve uma c pia do par metro v que por sua vez j uma c pia do argumento passado rotina Ou seja devolve uma c pia do argumento coisa que aconteceria mesmo que o argumento fosse passado por refer ncia A segunda rotina pelo contr rio recebe o seu argumento por refer ncia e devolve o seu par metro tamb m por refer ncia Ou seja o que devolvido um sin nimo do pr prio par metro v que por sua vez um sin nimo do argumento passado rotina Ou seja a rotina devolve um sin nimo do argumento Uma quest o filos fica que esse sin nimo n o tem nome Ou melhor a pr pria express o de invoca o da rotina que funciona como sin nimo do argumento Isso deve ser claro no seguinte c digo V necess rio clarificar a diferen a entre igualdade e identidade Pode se dizer que dois g meos s o igu
99. ializados durante a sua cons tru o ao contr rio do que seria desej vel contendo por isso lixo Para evitar o problema deve ser o programador produtor a declarar explicitamente um ou mais construtores e j agora defini los com o comportamento pretendido pois nesse caso o construtor por omiss o deixa de ser fornecido implicitamente pela linguagem Uma vez que se pretende que os racionais sejam inicializados por omiss o com zero tem de se fornecer um construtor por omiss o explicitamente que tenha esse efeito Nem sempre a linguagem fornece um construtor por omiss o implicitamente Isso acontece quando a classe tem atributos que s o constantes refer ncias ou que n o t m construtores por omiss o entre outros casos 326 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Representa n meros racionais class Racional public Constr i racional com valor zero Construtor por omiss o Qpre V post this 0 0 lt denominador A mdc numerador denominador 1 Racional private Racional Racional numerador 0 denominador 1 assert 0 lt denominador and mdc numerador denominador 1 Os construtores s o opera es de uma classe C mas s o muito especiais quer por por ra z es sem nticas quer por raz es sint cticas Do ponto de vista sem ntico o que os distingue dos outros operadores o facto de n o serem invocados atrav s de vari veis da classe pr
100. ica o sinal do denominador e reduz a fracc o correspon dente ao numerador e denominador passados como argumento Neste caso essas verifica es s o in teis pois o denominador n o varia mantendo se positivo e mudar o sinal do numera dor mant m numerador e denominador mutuamente primos Assim prefer vel a primeira vers o onde se constr i um racional usando o construtor por omiss o que muito eficien te e em seguida se alteram directamente e sem mais verifica es os valores do numerador e denominador Em qualquer dos casos devolvido um racional por valor e por isso constante 7 11 4 Devolu o por refer ncia constante Em alguns casos tamb m poss vel utilizar devolu o por refer ncia constante Esta t m a vantagem de ser mais eficiente do que a devolu o por valor podendo ser utilizada quando o valor a devolver n o for uma vari vel local fun o nem uma inst ncia tempor ria constru da dentro da fun o pois tal redundaria na devolu o de um sin nimo constante de uma inst n cia entretanto destru da o caso do operador un rio que por uma quest o se simetria se sobrecarrega por interm dio de uma opera o da classe C Racional class Racional public 7 12 REDUZINDO O N MERO DE INVOCAC ES COM INLINE 389 Devolve vers o constante do racional Qpre V post operator this Racional const amp operator const y Racional const amp Racional operator c
101. igual ao segundo pre V post operator lt r1 lt r2 bool operator lt Racional const amp rl Racional const amp r2 Indica se o primeiro racional maior ou igual ao segundo pre V post operator gt r1 gt r2 bool operator gt Racional const amp rl Racional const amp r2 Insere o racional no canal de sa da no formato de uma frac o Qpre V Qpost sa daV sa da cont m n d ou simplesmente n se d 1 sendo Ga fracc o can nica correspondente ao racional r ostream operator lt lt ostreams amp sa da Racional const amp r Extrai do canal um novo valor para o racional na forma de uma frac o Qpre r r post Se entrada e entrada cont m n d ou apenas n assumindo se d 1 em que n e d s o inteiros com d 4 0 ent o P a A entrada sen o r rN entrada istream operator gt gt istream amp entrada Racionals r int mdc int m int A if m O and n O return 1 if m lt 0 7 16 C DIGO COMPLETO DO TAD RACIONAL while true if m 0 return n inline Racional Racional int const n numerador n denominador 1 assert cumpreInvariante assert numerador_ n denominador_ inline Racional Racional int const n int const d numerador_ d lt 0 n n denominador d lt 0 d d assert d 0 reduz assert cumpreInvariante assert numerador_ d n denominador
102. in rio como qualquer outro e por isso tem associatividade esquerda Isso quer dizer que a instru o cout lt lt LO lt lt T T interpretada como cout lt lt 10 lt lt A primeira opera o com o operador lt lt faz se por isso com o primeiro operando do tipo ostreame o segundo do tipo char A segunda opera o com o operador lt lt faz se claramen te com o segundo operando do tipo char De que tipo ser o primeiro operando nesse caso E que valor possui As respostas s o evidentes se se lembrar que a instru o acima equivalente a cout lt lt 10 cout lt lt T E claro que o primeiro operando da segunda opera o com o operador lt lt tem de ser n o apenas do tipo ostream para que o segundo operando seja inserido num canal mas deve ser exactamente o canal cout para que a inser o se fa a no local correcto A sobrecarga do operador lt lt n o se pode fazer custa de uma opera o da classe Racional pois o primeiro operando do operador deve ser do tipo ost ream Sendo este tipo uma classe quando muito o operador lt lt poderia ser sobrecarregado por uma opera o dessa classe Mas como a classe est pr definida na biblioteca padr o do C n o poss vel faz lo Assim a sobrecarga ser feita usando uma rotina normal e por isso com dois par metros O primeiro par metro corresponder ao canal onde se deve realizar a opera o de inser o e o segundo ao raci
103. include lt cctype gt no in cio do programa para usar esta fun o 412 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Escrita em ficheiros Para se poder escrever num ficheiro necess rio estabelecer um canal de escrita ligado a esse ficheiro e inserir nele os dados a escrever no ficheiro O estabelecimento de um canal de escrita para um ficheiro feito de uma forma muito simples A instru o ofstream sa da nome do ficheiro constr i um novo canal chamado sa da que est ligado ao ficheiro da nome nome do fi cheiro Note se que sa da uma vari vel como outra qualquer s que representa um canal de escrita para um dado ficheiro A instru o acima poss vel porque a classe ofstream pos sui um construtor que recebe uma cadeia de caracteres cl ssica do C Isso significa que poss vel usar cadeias de caracteres para especificar o nome do ficheiro ao qual o canal deve estar ligado desde que se fa a uso da opera o string c str que devolve a cadeia de caracteres cl ssica corresponde a uma dada cadeia de caracteres cout lt lt Diga o nome do ficheiro string nome do ficheiro cin gt gt nome do ficheiro ofstream sa da nome do ficheiro c str O estabelecimento de um canal de sa da para um dado ficheiro uma opera o destrutora se o ficheiro j existir esvaziado antes Dessa forma a escrita come a sempre do nada Claro est que o estabelecimento de um canal de es
104. ional const amp r2 assert cumpreInvariante and r2 cumpreInvariante assert r2 O int dn mdc numerador_ r2 numerador_ int dd mdc denominador_ r2 denominador if r2 numerador lt 0 7 16 C DIGO COMPLETO DO TAD RACIONAL 427 numerador numerador_ dn r2 denominador_ dd denominador denominador dd r2 numerador dn else numerador_ numerador_ dn r2 denominador_ dd denominador denomina dor dd r2 numerador dn assert cumpreInvariante return this inline Racional amp Racional operator assert cumpreInvariante numerador denominador assert cumpreInvariante return this inline Racional amp Racional operator assert cumpreInvariante numerador_ denominador_ assert cumpreInvariante return this inline void Racional reduz assert denominador_ 0 int k mdc numerador_ denominador numerador_ k denominador_ k assert denominador 0 and mdc numerador_ denomina 428 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C dor 1 inline bool Racional cumpreInvariante const return 0 lt denominador and mdc numerador denomina dor_ 1 inline Racional const operator Racional rl Racional const amp r2 return rl r2 inline Racional const operator Racional rl Racional const amp r
105. is Qpre r1 r post operator rj x r2 Racional operator Racional rl Racional const r2 rl r2 return rl Finalmente dado que o operador devolve o primeiro operando podem se condensar as duas instru es do m todo numa nica instru o idiom tica 368 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Produto de dois racionais Qpre r1 r post operator rj x r2 Racional operator Racional rl Racional const r2 return rl r2 A implementa o dos restantes operadores aritm ticos faz se exactamente da mesma forma Divis o de dois racionais pre r1 r A r2 0 post operator r r2 Racional operator Racional rl Racional const r2 assert r2 0 return rl r2 Adi o de dois racionais pre r1 r post operator r 12 Racional operator Racional rl Racional const r2 return rl r2 Subtracc o de dois racionais Qpre r1 n Qpost operator r 12 Racional operator Racional rl Racional const r2 return rl r2 Para al m da vantagem j discutida de implementar um operador custa de outro agora deve j ser clara a vantagem de ter implementado o operador custa do operador e n o o contr rio a operac o tornou se muito mais eficiente pois n o obriga a copiar ou construir qualquer racional enquanto a opera o continua a precisar a sua dose de c pias e cons
106. ivisores n o unit rios comuns a n x d n x di ea k Assim sendo m mde n4 x dy ny x dy k a frac o ny ngo 1x n x d5 n5 xd m NI Y 420 Y A di d k m x dy x do est no formato can nico Qual foi a vantagem de factorizar l e k e proceder aos restantes c lculos face alternativa mais simples de calcular a frac o como n no na x do no x da h M da do da x do h com h mdc n x da na X di di X do A vantagem meramente computacional Apesar de os c lculos propostos exigirem mais opera es os valores interm dios dos c lculos s o em geral mais pequenos o que minimiza a possibilidade de existirem valores interm dios que n o sejam represent veis em valores do tipo int evitando se assim transbordamentos A frac o can nica correspondente adi o pode ser portanto calculada pela equa o acima A frac o can nica correspondente subtrac o pode ser calculada por uma equa o semelhante n na _ 1x m x do n x dy m da do k m x di x dy 7 13 OPTIMIZA O DOS C LCULOS COM RACIONAIS 397 Pode se agora actualizar a defini o dos m todos Racional operator e Racional operator para Racionals Racional operator Racional const amp r2 assert cumpreInvariante and r2 cumpreInvariante int dn int dd mdc denominador_ r2 denominador mdc numerador_ r2 numerador_ Devidoa r r int d2 r2
107. ivo das opera es n o s o testadas usando instru es de asser o O problema que a condi o objectivo das opera es est escrita em termos da no o matem tica de n mero racional e n o f cil fazer a ponte entre uma no o matem tica e o c digo C Por exemplo como explicitar em c digo a condi o objectivo do operador para racionais Uma primeira tentativa poderia ser a tradu o directa Devolve a soma com o racional recebido como argumento Qpre this r post this r A operator this r2 Racional Racional operator Racional const r2 assert cumpreInvariante and r2 cumpreInvariante Racional r r numerador numerador r2 denominador r2 numerador denominador r denominador denominador r2 denominador r reduz assert cumpreInvariante and r cumpreInvariante assert r this r2 return r H dois problemas neste c digo O primeiro que o operador ainda n o est definido Este problema resolver se facilmente mais frente neste cap tulo O segundo muito mais importante a asserc o tal como est escrita recorre recursivamente ao pr prio operador Claramente o caminho certo n o passa por aqui Os testes de unidade proporcionam uma alternativa interessante s instru es de asserc o para as condi es objectivo das opera es A ideia que se deve escrever um conjunto exaustivo de testes para as v rias o
108. ize return itens ndice int main VectorDeInt v 10 v 10 3 ndice errado aborta com asser o falhada 7 7 DEVOLU O POR REFER NCIA 357 7 7 2 Operadores e prefixo O operador prefixo necessita de alterar o seu nico operando Assim conveniente sobrecarreg lo na forma de uma opera o da classe C Racional Uma vez que tem um nico operando este ser usado como inst ncia neste caso vari vel impl cita durante a execu o do respectivo m todo pelo que a opera o n o tem qualquer par metro importante perceber que a incre menta o de um racional pode ser feita de uma forma muito mais simples do que recorrendo soma de racionais em geral a adi o de um a um racional representado por uma frac o can nica n d d 9 que tamb m uma frac o no formato can nico pelo que o c digo simplesmente Representa n meros racionais Qinvariant O lt denominador A mdc numerador denominador 1 class Racional public Incrementa e devolve o racional Qpre this r post operador thisA this r 1l Racional amp operator y Racionalg Racional operator Seja 3 o racional guardado numa inst ncia da classe C Racional e que portanto verifica a condi o inva riante dessa classe ou seja O lt dA mdc n d 1 bvio que n n d 1 dT d Mas ser que a frac o n d d verifica
109. l 2 18 Racional 5 2 assert rl r2 Racional 11 2 assert rl Racional 5 7 Racional 25 14 assert rl 40 100 assert 30 rl 12 ofstream sa da teste saida lt lt EL ALOE sa da close ifstream entrada teste Racional r4 r5 entrada gt gt r4 gt gt r5 assert rl r4 assert r2 r5 lse TESTE int main dL Ler frac es cout lt lt Introduza duas frac es numerador denominador Racional rl r2 cin gt gt rlc gt gt 24 if not cin cerr lt lt Opps A leitura dos racionais falhou lt lt en return 1 Calcular racional soma Ww LA 431 432 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Racional r rl r2 Escrever resultado cout lt lt A soma de lt lt rl lt lt com lt lt r2 lt lt T WV y lt lt lt lt Ef lt lt endi ndif TESTE O c digo acima representa o resultado final de um longo p riplo come ado no in cio des te cap tulo Ser que valeu a pena o esfor o posto no desenvolvimento do TAD Racional Depende Se o objectivo era simplesmente somar duas frac es certamente que n o Se o ob jectivo por outro lado era permitir a escrita simples de programas usando n meros racionais ent o valeu a pena Em geral quanto mais esfor o for dispendido pelo programador produtor no desenvolvimento de uma
110. larada dentro da defini o da classe Recorda se que implementa o de uma ope ra o se chama m todo e que por isso todos os m todos fazem parte da implementa o de uma classe C ey 3 A opera o escreve foi declarada sem qualquer par metro 4 H um pormenor na definic o do m todo escreve que novo o nome do m todo precedido de Racional Esta nota o serve para indicar que escreve um m todo correspondente a uma opera o da classe Racional e n o uma rotina vulgar Onde ir a opera o Racional escreve buscar o racional a imprimir De onde v em as vari veis numerador e denominador usadas no corpo do m todo Racional escreve Em primeiro lugar recorde se que o acesso aos membros de uma classe se faz usando o opera dor de selec o de membro Ou seja inst ncia nome do membro em que inst ncia uma qualquer inst ncia da classe em causa Esta nota o t o v lida para atributos como para opera es pelo que a instru o para escrever a vari vel r no ecr no programa em desenvolvimento deve passar a ser r escreve Em cap tulos posteriores se ver que as classes propriamente ditas podem ter mais do que um m todo associ ado a cada opera o 7 3 REPRESENTA O DE RACIONAIS POR FRAC ES 319 O que acontece que inst ncia atrav s da qual a opera o Racional escreve invo cada est expl cita na pr pria invoca o
111. lo atrav s da escrita de programas numa linguagem de programa o dada Depois de especifica do o problema com exactid o o programador inteligente come a por procurar na linguagem b sica na biblioteca padr o e noutras quaisquer bibliotecas dispon veis ferramentas que re solvam o problema na totalidade ou pelo menos parcialmente esta procura evita as perdas de tempo associadas ao reinventar da roda infelizmente ainda t o em vogal Se n o existirem ferramentas dispon veis ent o h que constru las Ao faz lo o programador est a expandir Por outro lado importante notar que se pede muitas vezes ao estudante que reinvente a roda Faz lo parte fundamental do treino na resolu o de problemas concretos Conv m portanto que o estudante se disponha a essa tarefa que fora do contexto da aprendizagem in til Mas conv m tamb m que n o se deixe viciar na resolu o por si pr prio de todos os pequenos problemas que j foram resolvidos milhares de vezes importante saber fazer um equil brio entre a curiosidade intelectual de resolver esses problemas e o pragmatismo de procurar um solu o j pronta Durante a vida acad mica a balan a deve pender fortemente no sentido da curiosidade intelectual Finda a vida acad mica o equil brio deve pender mais para o pragmatismo 299 300 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C mais uma vez a linguagem dispon vel que passa a dispor de ferramenta
112. lores lidos s o aceit veis Neste caso isso corresponde a verificar se o denominador nulo Se for a leitura deve falhar I e o racional deve manter o valor original e o canal deve ficar em estado de erro de modo a que a falha de extrac o possa ser detectada mais tarde S dessa forma ser poss vel por exemplo escrever o seguinte c digo Racional r r extraiDe cin if not cin cerr lt lt Opps A leitura falhou lt lt endl 7 14 OPERADORES DE INSER O E EXTRAC O 409 ou mesmo Racional r cin gt gt r if not cin cerr lt lt Opps A leitura falhou lt lt endl utilizando o operador gt gt j sobrecarregado para os racionais Pretende se de novo que o comportamento de um programa usando racionais seja t o semelhante quanto poss vel do ponto de vista sem ntico com o mesmo programa usando inteiros Assim no caso de se extrair um denominador nulo deve se colocar o canal entrada em estado de erro Para o fazer usa se a instru o entrada setstate ios base failbit A parte restante do c digo auto explicativa 7 14 4 Coer ncia entre os operadores lt lt e gt gt Tal como sobrecarregados os operadores lt lt e gt gt para racionais ou melhor as opera es Ra cional insereEm e Racional extraiDe n o s o coerentes a extrac o n o su porta o formato usado pela inser o nomeadamente n o espera o s mbolo entre os termos da frac o nem admite
113. los interm dios que os envolvam podem ocorrer transbordamentos No entanto embora seja imposs vel eliminar totalmente a possibilidade de transbordamentos excepto eventual mente abandonando o tipo int e usando um TAD representando n meros inteiros de di mens o arbitr ria poss vel minorar o seu impacte Por exemplo no caso do operador lt poss vel encontrar divisores comuns aos numeradores e aos denominadores dos racionais a comparar e us los para reduzir ao m ximo a magnitude dos inteiros a comparar Indica se o primeiro racional menor que o segundo Qpre V post operator lt r1 lt r2 inline bool operator lt Racional const rl Racional const amp r2 int dn mdc rl numerador r2 numerador int dd mdc rl denominador r2 denominador 7 13 OPTIMIZA O DOS C LCULOS COM RACIONAIS 395 return rl numerador dn r2 denominador r2 numerador dn r1 denominador As mesmas ideias podem ser aplicadas a outras opera es pelo que se discutem nas sec es seguintes Durante estas sec es admite se que as frac es originais Z T e 2 est o no formato can nico Recorda se tamb m que se admite uma extens o da fun o mdc de tal forma que mdc 0 0 1 7 13 1 Adi o e subtracc o O resultado da soma de fracc es dado por n na ni X da n x da ETA d x do embora tenha for osamente o denominador positivo pode n o estar no formato can nico Se
114. m denominador 0 A mde somaCom numerador somaCom denominador 1 Racional somaCom Racional const 12 L do teclado um novo valor para o racional na forma de dois inteiros sucessi vos Qpre this r post Se cin e cin tem dois inteiros n e d dispon veis para leitu ra com d 0 ent o 0 lt denominador A mdc numerador denominador 1A this a Acin sen o this rArzcin void 1 private int numerador int denominador Reduz a frac o que representa o racional Qpre denominador O A this r post denominador 4 0 A mdc numerador denominador 1A this r void reduz y 7 3 REPRESENTA O DE RACIONAIS POR FRAC ES 321 void Racional escreve cout lt lt numerador if denominador 1 cout lt lt lt lt denominador Racional Racional somaCom Racional const r2 assert denominador 0 and r2 denominador 0 Racional r r numerador numerador r2 denominador r2 numerador denominador r denominador denominador r2 denominador r reduz assert denominador O and r denominador O and mdc r numerador r denominador 1 return void Racional 1 int in dj if cin gt gt n gt gt d if d 0 cin setstate ios base failbit else numerador d lt 0 n n denominador d lt 0 d d reduz assert 0 lt denominador and mdc numerador denomina numerador d
115. m deve possuir uma boa biblioteca que liberte o programador da tarefa ingrata e sujeita a erros de desenvolver algoritmos e estruturas de da dos bem conhecidos Mas como evitar os erros de implementac o H muitos casos em que a linguagem pode ajudar o caso da possibilidade de usar constantes em vez de vari veis que permite ao compilador detectar facilmente tentativas de alterar o seu valor enquanto que a utiliza o de uma vari vel para o mesmo efeito impediria do compilador de detectar o erro deixando esse trabalho nas m os do programador Outro caso o do encapsulamento A cate goriza o de membros de uma classe C como privados permite ao compilador detectar ten tativas err neas de acesso a esses membros coisa que seria imposs vel se os membros fossem p blicos recaindo sobre os ombros do programador consumidor da classe a responsabilida de de n o aceder a determinados membros de acordo com as especifica es do programador produtor Ainda outro caso a defini o das vari veis t o perto quando poss vel da sua pri meira utiliza o que permite evitar utiliza es err neas dessa vari vel antes do local onde realmente necess ria e onde se a vari vel for de um tipo b sico toma um valor arbitr rio lixo Assim conveniente usar os mecanismos da linguagem de programa o que permitem ex primir no pr prio c digo determinadas op es de implementa o e condi es de utiliza o e que permitem
116. ma vari vel local visto que o par metro v n o uma refer ncia mas sim uma vari vel local cujo valor uma c pia do argumento respectivo Como essa vari vel local destru da exactamente aquando do retorno da rotina a refer ncia devolvida fica a referir se a coisa nenhuma Uma digress o pelo operador Uma vez que o operador de indexa o usado normalmente para as matrizes e vectores pode ser sobrecarregado por tipos definidos pelo programador a devolu o de refer ncias permite por exemplo definir a classe VectorDeInt abaixo que se comporta aproximada mente como a classe vector lt int gt descrita na Sec o 5 2 embora com verifica o de erros de indexa o 356 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C include lt iostream gt include lt vector gt include lt cstdlib gt using namespace std class VectorDelnt public VectorDeInt vector lt int gt size type const dimen s o inicial 0 int const valor inicial dos itens 0 int amp operator vector lt int gt size type const ndice private vector lt int gt itens y VectorDeInt VectorDeInt vector lt int gt size type const dimen s o_inicial int const valor_inicial_dos_itens v dimens o inicial valor inicial dos itens int amp VectorDeInt operator vector lt int gt size type const ndice assert 0 lt ndice and ndice lt itens s
117. mas est impl cita durante a execu o do respectivo m todo Mais essa inst ncia que est impl cita durante a execu o pode ser modificada pe lo m todo pelo menos se for uma vari vel Tudo funciona como se a inst ncia usada para invocar a opera o fosse passada automaticamente por refer ncia Durante a execu o do m todo Racional escreve numerador e denominador referem se aos atributos da inst ncia atrav s da qual a respectiva opera o foi invocada Assim quando se adaptar o final do programa em desenvolvimento para int main Escrever resultado rl escreve r2 escreve r escreve durante a execu o do m todo Racional escreve as vari veis numerador e denomi nador referir se o sucessivamente aos correspondentes atributos de r1 r2 e r inst ncia que est impl cita durante a execu o de um m todo chama se naturalmente inst ncia impl cita ou vari vel impl cita se for uma vari vel ou constante impl cita se for uma constante pelo que no exemplo anterior a inst ncia impl cita durante a execu o do m todo come a por ser r1 depois r2 e finalmente r poss vel explicitar a inst ncia impl cita durante a execu o de um m todo da classe ou seja a inst ncia atrav s da qual a respectiva opera o foi invocada Para isso usa se a constru o this Esta constru o usou se na documenta o da opera o escreve nomeadamente no seu contrato par
118. mente haja sempre um ganho em termos do n mero de instru es a efectuar se o c digo a colocar em linha for de masiado extenso o programa pode se tornar mais longo o que pode inclusivamente levar ao esgotamento da mem ria f sica levando utiliza o da mem ria virtual do sistema operativo que tem a lament vel caracter stica de ser ordens de grandeza mais lenta Assim necess rio usar o qualificador inline com conta peso e medida Para definir uma opera o como em linha pode se fazer uma de duas coisas 1 Ao definir a classe C definir logo o m todo em vez de a declarar apenas a respectiva opera o 2 Ao definir o m todo correspondente opera o declarada na defini o da classe prece der o seu cabe alho do qualificador inline Em geral a segunda alternativa prefer vel primeira pois torna mais evidente a separa o entre a interface e a implementa o da classe separando claramente opera es de m todos A defini o de uma rotina membro ou n o membro como em linha n o altera a sem ntica da sua invoca o tendo apenas consequ ncias em termos da tradu o do programa para c digo m quina No caso do c digo em desenvolvimento neste cap tulo relativo ao TAD Racional todas as rotinas s o suficientemente simples para que se justifique a utiliza o do qualificador inli ne com excep o apenas da fun o mdc por envolver um ciclo e da opera o Racio nal 1 por
119. mplifica para Incrementa o racional recebido como argumento devolvendo o seu valor an tes de incrementado Opre this r Opostoperator rA this r 1 Racional operator Racional amp r int Racional const c pia r r return c pia interessante notar como se recorre ao operador de incrementa o prefixo que j foi definido na implementa o do operador sufixo Ao contr rio do que pode parecer tal n o ocorre sim plesmente porque se est a sobrecarregar o operador sufixo como uma rotina n o membro da classe Racional De facto mesmo que o operador fosse definido como membro da classe A sobrecarga tamb m se poderia fazer custa de uma opera o da classe Racional Racional operator int Racional const c pia this this return c pia continuaria a ser vantajoso faz lo que o c digo de incrementa o propriamente dito fica concentrado numa nica rotina pelo que se for necess rio mudar a representa o dos racio nais apenas ser necess rio alterar a implementa o do operador prefixo Repare se como em qualquer dos casos necess rio fazer uma c pia do racional antes de incrementado e devolver essa c pia por valor o que implica realizar ainda outra c pia Final mente compreende se a insist ncia desde o in cio deste texto em usar a incrementa o prefixo em detrimento da vers o sufixo mesmo onde teoricamente ambas produzem o me
120. mporta como qualquer tipo b sico da linguagem O seu objectivo permitir a definic o de inst ncias que armazenam valores O que dis tingue umas inst ncias das outras fundamentalmente o seu valor Nos TAD o nfase p e se na igualdade pelo que as c pias s o comuns Classe propriamente dita Conceito mais complexo a estudar em cap tulos posteriores Re presentam as caracter sticas comuns de objectos independentes O seu objectivo poder 2Na realidade os tipos de primeira categoria s o concretiza es numa linguagem de programa o de TAD que s o uma abstrac o matem tica Como os TAD na sua acep o matem tica est o fora por enquanto do mbito deste texto os dois termos usam se aqui como sin nimos 3 Apesar do cuidado posto na redac o deste texto prov vel que aqui e acol ocorram viola es a esta conven o Espera se que n o sejam factor de distrac o para o leitor 306 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C construir objectos independentes de cuja interac o e colabora o resulte o comporta mento adequado do programa O nfase p e se na identidade e n o na igualdade pelo que as c pias s o infrequentes merecendo o nome de clonagens Classe C Ferramenta da linguagem que permite implementar quer TAD quer classes pro priamente ditas 7 21 Defini o de TAD E poss vel definir um novo tipo um TAD para representar n meros racionais na forma de uma frac o como
121. n Racional int const n 0 Constr i racional correspondente a n d pre d 0 5 n post this q Racional int const n int const d Devolve numerador da frac o can nica correspondente ao racional pre V numerador _ _ POE qanominadoro this int numerador const Devolve denominador da frac o can nica correspondente ao racional Qpre V post En V denominador this A 0 lt denominador A mdc n denominador 1 df int denominador const Devolve vers o constante do racional Qpre V post operator this Racional const operator const Devolve sim trico do racional Qpre V post operator this Racional const operator const Insere o racional no canal no formato de uma frac o pre V post sa daV sa da cont m n d ou simplesmente n se d 1 sendo Za frac o can nica correspondente ao racional this void insereEm ostream amp sa da const Extrai do canal um novo valor para o racional na forma de uma frac o Qpre this r 420 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C postSe entrada e entrada cont m n d ou apenas n assumindo se d 1 em que n e d s o inteiros com d 4 0 ent o ZENIS S L A entrada sen o this rA entrada void extraiDe istream amp entrada Adiciona de um racional Qpre this r post operator thisA this r r2 Raci
122. not canal Extrai do canal um novo valor para o racional na forma de uma frac o 7 14 OPERADORES DE INSER O E EXTRAC O 411 Qpre r r post Se entrada e entrada cont m n d ou apenas n assumindo se d 1 em que n e d s o inteiros com d 4 0 ent o PE z A entrada sen o r rN entrada istream amp operator gt gt istream amp s entrada Racional amp r r extraiDe entrada return entrada S o de notar os seguintes pontos e A opera o istream peek devolve o valor do pr ximo caractere no canal sem o extrair e A opera o istream get extrai o pr ximo caractere do canal e devolve o 23 e A fun o isdigit decimais indica se o caractere passado como argumento um dos d gitos Fica como exerc cio para o leitor o estudo pormenorizado do m todo Racional extraiDe 714 5 Leitura e escrita de ficheiros Uma vez sobrecarregados os operadores lt lt e gt gt para a classe C Racional poss vel us los para fazer extrac es e inser es n o apenas do teclado e para o ecr mas de e para onde quer que um canal esteja estabelecido poss vel estabelecer canais de entrada e sa da para ficheiros por exemplo Para isso usam se as classes ifstreame ofstream compat veis com istreame ostream respectivamente e que ficam dispon veis se se incluir a seguinte linha no in cio do programa tinclude lt fstream gt 23 Acrescentar t
123. nt para Racional realmente til pelo que o qualificador explicit desnecess rio 7 9 3 Sobrecarga de operadores opera es ou rotinas Suponha se por um instante que o operador para a classe C Racional sobrecarregado atrav s de uma opera o Isto regresse se vers o do operador apresentada na Sec o 7 5 Nesse caso o seguinte c digo Racional r 1 3 Racional s r 3 v lido pois o valor inteiro 3 convertido implicitamente para Racional e seguidamente invocado o operador definido Ou seja o c digo acima equivalente a Racional r 1 3 Racional s r Racional 3 Por m o c digo Racional r 1 3 Racional s 3 r 7 10 OPERADORES IGUALDADE DIFERENCA E RELACIONAIS 371 inv lido pois a linguagem C pro be convers es na inst ncia atrav s da qual se invoca um m todo Se o operador tivesse sido sobrecarregado custa de uma normal rotina n o membro todos os seus argumentos poderiam sofrer convers es impl citas o que resolveria o problema Mas foi exactamente isso que se fez nas sec es anteriores Logo o c digo acima perfeitamente legal e equivalente a Racional r 1 3 Racional s Racional 3 r Este facto ser utilizado para implementar alguns dos operadores em falta para a classe C Racional 7 10 Operadores igualdade diferen a e relacionais Os operadores de igualdade diferenca e relacionais ser o desenvolvidos usando
124. nte int dn mdc numerador_ r2 numerador_ int dd mdc denominador_ r2 denominador Devidoa r r int n2 r2 numerador_ int d2 r2 denominador_ numerador_ dn denominador_ dd numerador_ numerador_ d2 dd n2 dn denominador_ dd mdc numerador_ dd numerador_ dn numerador_ dd denominador_ d2 dd assert cumpreInvariante return this Racionals Racional operator Racional const amp r2 assert cumpreInvariante and r2 cumpreInvariante int dn int dd mdc numerador_ r2 numerador_ mdc denominador_ r2 denominador_ 426 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Devidoa r r int n2 r2 numerador_ int d2 r2 denominador_ numerador dn denominador dd numerador numerador_ d2 dd n2 dn denominador dd mdc numerador_ dd numerador dn numerador_ dd denominador d2 dd assert cumpreInvariante return this inline Racionalg Racional operator Racional const amp r2 dor assert cumpreInvariante and r2 cumpreInvariante int n1d2 mdc numerador_ r2 denominador int n2dl mdc r2 numerador_ denominador numerador_ numerador nld2 r2 numerador_ n2d1 denominador_ denomina _ n2dl r2 denominador_ nld2 assert cumpreInvariante return this inline Racional amp Racional operator Rac
125. ntes operandos passados como argumento opera o Se for um operador bin rio e g etc ent o a sobrecarga do operador pode ser feita e Para uma classe C Classe definindo uma opera o tipo de devolu o Clas se operatorl tipo do segundo operando Numa invoca o deste operador o primeiro operando obrigatoriamente do tipo Classe usado como inst ncia impl ci ta e o segundo operando passado como argumento 344 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C e Atrav s de uma rotina n o membro tipo de devolu ooperatorf tipo do primeiro operai tipo do segundo operando Numa invoca o deste operador ambos os operan dos s o passados como argumentos A express o a b pode portanto ser interpretada como a operatore b ou operatort a b consoante o operador esteja definido como membro da classe a que a pertence ou esteja defi nido como rotina normal n o membro Se for um operador un rio e g prefixo etc ent o a sobrecarga do operador Q pode ser feita e Para uma classe C Classe definindo uma opera o tipo de devolu o Clas se operator Numa invoca o deste operador o seu nico operando obrigato riamente do tipo Classe usado como inst ncia impl cita e Atrav s de uma rotina n o membro tipo de devolu ooperatorf tipo do operando A express o Ga ou a se for sufixo pode portanto ser interpretada como a operatore
126. o n1 1 da k lt n2 1 da k Da mesma forma podem se reduzir todas as compara es entre racionais com lt gt gt ou lt s correspondentes compara es entre inteiros Pode se agora actualizar a defini o da rotina operator lt Indica se o primeiro racional menor que o segundo Qpre V Gpost operator lt r1 lt r2 inline bool operator lt Racional const rl Racional const amp r2 int dn mdc rl numerador r2 numerador int dd mdc r1 denominador r2 denominador return rl numerador dn r2 denominador dd lt r2 numerador dn rl denominador dd 7 13 6 Operadores especiais O TAD Racional tal como concretizado at agora suporta opera es simult neas entre raci onais e inteiros sendo para isso fundamental a convers o impl cita entre valores do tipo int eotipo Racional fornecida pelo primeiro construtor da respectiva classe C No entanto instrutivo seguir a ordem dos acontecimentos quando se calcula por exemplo a soma de um racional com um inteiro 7 13 OPTIMIZA O DOS C LCULOS COM RACIONAIS 401 Racional r 1 2 cout lt lt r 1 lt lt endl A soma implica as seguintes invoca es 1 Construtor da classe C Racional para converter o inteiro 1 no correspondente racio nal 2 Rotina operator 3 Opera o Racional operator Ser poss vel evitar a convers o do inteiro em racional e sobretud
127. o Para que tal comportamento fique claro conv m comparar cuidadosamente os seguintes tro os de c digo int i 0 int j i 360 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C int i 0 IFF int 5 Enquanto o primeiro tro o de c digo inicializa a vari vel j como valor de i j incrementado i e com 1 o segundo tro o de c digo inicializa a vari vel j com o valor de i antes de incre mentado ou seja com 0 Em ambos os casos a vari vel i incrementada ficando com o valor 1 Clarificada esta diferenca h agora que implementar os operadores de incrementac o e decre mentac o sufixo para a classe C Racional A primeira quest o fundamental sint ctica sendo os operadores prefixo e sufixo ambos un rios como distingui los na defini o dos ope radores Se forem definidos como opera es da classe C Racional ent o ambos ter o o mesmo nome e ambos n o ter o nenhum par metro distinguindo se apenas no tipo de devo lu o visto que as vers es prefixo devolvem por refer ncia e as vers es sufixo devolvem por valor O mesmo se passa se os operadores forem definidos como rotinas normais n o membro O problema que o tipo de devolu o n o faz parte da assinatura das rotinas membro ou n o pelo que o compilador se queixar de uma dupla defini o do mesmo operador Face a esta dificuldade os autores da linguagem C tomaram uma das decis es mais arbi tr rias que poderiam ter tomado
128. o evitar calcular a soma de um racional com um inteiro recorrendo complicada maquinaria necess ria para somar dois racionais Certamente Basta fornecer vers es especializadas para operandos inteiros das sobrecargas dos operadores em causa class Racional public Adiciona de um inteiro Opre this r Opostoperator thisA this r n Racional amp operator int const n y Racionalg Racional operator int const i assert cumpreInvariante numerador_ i denominador_ assert cumpreInvariante return this 402 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Adi o de um racional e um inteiro Qpre r r Qpost operator r i inline Racional const operator Racional r int const i return r i Adi o de um inteiro e um racional pre r r postoperator i r inline Racional const operator int const i Racional r return r i Fica como exerc cio para o leitor desenvolver as sobrecargas de operadores especializadas em todos os outros casos em que se possam fazer opera es conjuntas entre inteiros e racionais 7 14 Operadores de inserc o e extrac o poss vel e desej vel sobrecarregar o operador lt lt de inser o num canal e o operador gt gt de extrac o de um canal Ali s estas sobrecargas s o digamos a cereja sobre o bolo S o o toque final que permite escrever o programa da soma de racionais exactamente da
129. o can nica correspondente ao racional Qpre this r post this r A En V denominador this AO lt denominador A mdc n denominador 1 int denominador private int numerador int denominador A condi o objectivo da opera o denominador algo complexa pois evita colocar na interface da classe refer ncias sua implementa o como seria o caso se se referisse ao atributo denominador Assim usa se a defini o de denominador de frac o can nica O valor devolvido denominador tem de ser tal que exista um numerador n tal que 3 a a PRA NA a rela 1 a frac o denominados igual inst ncia impl cita e a n 4 2 2 a frac o denominador est no formato can nico Ou seja o valor devolvido o denominador da fracc o can nica correspondente inst ncia impl cita A condi o objectivo da opera o numerador mais simples pois recorre defini o da opera o deno minador para dizer que se o valor devolvido for o numerador de uma frac o cujo denominador o valor devolvido pela opera o denominador ent o essa frac o igual inst ncia impl cita Como o denominador usado o denominador da frac o can nica igual inst ncia impl cita conclui se que o valor devolvido de facto o numerador dessa mesma frac o can nica 7 10 OPERADORES IGUALDADE DIFERENCA E RELACIONAIS 373 y int Racional numerador assert cumpreInvariante
130. o ponto de vista do programador programador ou seja durante a defini o da rotina faz toda a diferen a que o par metro seja constante se o for o compilador detectar tentativas de o alterar no corpo da rotina protegendo o programador dos seus pr prios erros no caso de a altera o do valor do par metro ser de facto indesej vel Finalmente note se que a palavra chave const no caso da passagem de argumentos por valor eliminada automaticamente da assinatura da rotina pelo que perfeitamente poss vel que surja apenas na sua defini o implementa o sendo eliminada da declara o interface Declara o TipoDeDevolu o rotina TipoDoPar metro par metro Defini o TipoDeDevolu o rotina TipoDoPar metro const par metro Altera o de par metro proibida No caso da passagem por refer ncia a palavra chave const faz toda a diferen a em qualquer caso quer do ponto de vista da interface quer do ponto de vista da implementa o Na pas sagem de argumentos por refer ncia Declara o TipoDeDevolu o rotina TipoDoPar metros amp par metro Defini o TipoDeDevolu o rotina TipoDoPar metro amp par metro os par metros funcionam como sin nimos dos argumentos ou refer ncias vari veis para os argumentos Assim qualquer altera o de um par metro repercute se sobre o argumento respectivo Como neste tipo de passagem de argumentos n o realizada qualquer c
131. o r2 fundamental faz lo para que o c digo tenha o comportamento desej vel no caso de se invocar o operador da seguinte forma Y Ei Fica como exerc cio para o leitor verificar que o resultado estaria longe do desejado se esta altera o n o tivesse sido feita dica a vari vel impl cita e a vari vel da qual r2 sin nimo s o a mesma vari vel 7 11 2 Constantes impl citas opera es constantes E poss vel definir constantes de um TAD concretizado custa de uma classe C Por exemplo para a classe C Racional poss vel escrever o c digo Racional const um ter o 1l 3 que define uma constante um ter o O problema est em que tal como a classe C Raci onal est definida esta constante praticamente n o se pode usar Por exemplo o c digo cout lt lt O denominador lt lt um ter o denominador lt lt endl resulta num erro de compila o A raz o para o erro simples o compilador assume que as opera es da classe C Racional alteram a inst ncia impl cita ou seja assume que as opera es t m sempre uma vari vel e n o uma constante impl cita Assim como o compilador assume que h a possibilidade de a constante um ter o ser alterada o que um contra senso simplesmente pro be a invoca o da opera o inspectora Racional denominador Note se que o mesmo problema j existia no c digo desenvolvido repare se na rotina que sobrecarrega o operador por e
132. o usada para calcular a soma Racional r rl somaCom r2 horrenda sem d vida alguma Numa sec o posterior se ver como sobrecarregar o opera dor de modo a permitir escrever Racional r rl 12 7 4 Classes C como m dulos Das discuss es anteriores nomeadamente sobre o princ pio do encapsulamento e as categorias de acesso dos membros de uma classe torna se claro que as classes C s o uma unidade de modularizac o De facto assim Ali s as classes s o a unidade de modularizac o por excel ncia na linguagem C e na programa o baseada em e orientada para objectos 324 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Como qualquer m dulo que se preze as classes C distinguem claramente interface e im plementac o A interface de uma classe C corresponde aos seus membros p blicos Usu almente a interface de uma classe C consiste num conjunto de operac es e tipos p blicos A implementa o de uma classe C consiste pelo contr rio nos membros privados e na defini o das respectivas opera es i e nos m todos da classe Normalmente a implementa c o de uma classe C cont m os atributos da classe particularmente as vari veis membro e opera es utilit rios necess rias apenas para o programador produtor da classe de toda a conveni ncia que os atributos de uma classe C e em especial as suas vari veis membro sejam privados S dessa forma se garante que um consumidor da cl
133. oca um fim de linha no canal e invoca automaticamente a opera o ostream flush Ou seja tudo funciona como se o canal tivesse um certa capacidade para dados tal como uma mangueira tem a capacidade de armazenar um pouco de gua Tal como numa mangueira s se pode garantir que toda a gua que nela entrou saiu pela outra ponta tomando algumas dilig ncias tamb m num canal de sa da s se pode garantir que os dados chegaram ao seu destino e n o est o ainda em circula o no canal se se diligenciar como indicado acima A partir do momento em que um canal de sa da est estabelecido pode se us lo da mesma forma que ao canal cout Por exemplo cout lt lt Diga o nome do ficheiro string nome do ficheiro cin gt gt nome do ficheiro ofstream sa da nome do ficheiro c str if not sa da cerr lt lt Opps N o consegui criar ficheiro N lt lt nome do ficheiro lt lt X lt lt endl Racional r 1 3 sa da lt lt r lt lt endl Leitura de ficheiros Para se poder ler de um ficheiro necess rio estabelecer um canal de leitura ligado a esse ficheiro e extrair dele os dados a ler do ficheiro O estabelecimento de um canal de leitura para um ficheiro feito de uma forma muito simples A instru o ifstream entrada nome do ficheiro constr i um novo canal chamado entrada que est ligado ao ficheiro da nome nome do ficheiro Mais uma vez entrada uma vari vel como ou
134. odos os atributos com excep o dos pertencentes a tipos b sicos do C que infelizmente n o s o inicializados implicitamente Neste caso portanto o construtor por omiss o da classe C constr i os atributos r1 r r2 com o valor racional zero deixando os tributos i e j por inicializar O construtor por omiss o fornecido implicitamente pode ser invocado explicitamente C c CO ou C c C embora neste caso seja tamb m invocado o construtor por c pia tamb m fornecido implici tamente que constr i a vari vel c custa da inst ncia tempor ria constru da pelo construtor por omiss o Para que esse facto fique claro repare se no c digo cout lt lt Racional lt lt endl que mostra no ecr o valor da inst ncia tempor ria da classe C Racional constru da pelo respectivo construtor por omiss o i e o valor zero Neste caso o construtor por c pia da classe C Racional n o invocado Se o programador declarar algum construtor explicitamente ent o o construtor por omiss o deixa de ser fornecido implicitamente Por exemplo se a classe C C fosse class C public Clint iy EA private Racional rl Racional r2 int 1 int 3 440 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C o c digo C c ops falta o construtor por omiss o resultaria num erro de compila o No exemplo seguinte o construtor por omiss o faz exactamente o mesmo papel que o cons trutor por omis
135. omporte como qualquer outro tipo existente em C necess rio um TAD Tipo Abstracto de Dados ou tipo de primeira categoria Um TAD ou tipo de primeira cate goria um tipo definido pelo programador que se comporta como os tipos b sicos servindo para definir inst ncias i e vari veis ou constantes que guardam valores sobre os quais se pode operar A linguagem C proporciona uma ferramenta as classes C que permite concretizar tipos de primeira categoria importante notar aqui que o termo classe tem v rios significados Em cap tulos posteriores falar se de classes propriamente ditas que servem para definir as caracter sticas comuns de objectos dessa classe e que se concretizam tamb m usando as classes C Este cap tulo por outro lado debru a se sobre os TAD que tamb m se concretizam custa de classes C Se se acrescentar que a fronteira entre TAD cujo objectivo definir inst ncias e as classes pro priamente ditas cujo objectivo definir as caracter sticas comuns de objectos independentes percebe se que inevit vel alguma confus o de nomenclatura Assim sempre que se falar simplesmente de classe ser na acepc o de classe propriamente dita enquanto que sempre que se falar do mecanismo da linguagem C que permite concretizar quer TAD quer classes propriamente ditas usar se sempre a express o classe C Assim TAD Tipo definido pelo utilizador que se co
136. on veis para leitura com d 314 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C 0 ent o 0 lt r denominador A mdc r numerador r denominador 1A r a Acin sen o r rArzcin void l Racionals r inten di T Cin gt gt n gt gt d if d 0 cin setstate ios base failbit else r numerador d lt 0 n n r denominador d lt 0 d d reduz r assert 0 lt r denominador and mdc r numerador r deno minador 1 and r numerador d n r denominador and cin return assert not cin Devolve a soma de dois racionais pre r1 denominador 0 A r2 denominador 0 post somaDe r1 r2 somaDe denominador 0 A mde somaDe numerador somaDe denominador 1 Racional somaDe Racional const rl Racional const r2 assert rl denominador O and r2 denominador 0 Racional r r numerador rl numerador r2 denominador r2 numerador rl denominador r denominador rl denominador r2 denominador reduz r as 7 3 REPRESENTA O DE RACIONAIS POR FRAC ES 315 sert r denominador 0 and mdc r numerador r denominador 1 return r Escreve um racional no ecr no formato de uma frac o Qpre V Qpost coutV cout cont m n d ou simplesmente n se d 1 sendo Za frac o can nica correspondente ao racional r void escreve Racional const r int cout lt lt r numerador if r denominador
137. onal a inserir Como o canal certamente modificado pela opera o de inser o ter de ser passado por refer ncia Um ficheiro c face usado dulariza o f ra permitir a dulo f sico usar ferramen nidas noutro f sico Estes s o mat ria d tulo 9 404 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C tipo de devolu o operator lt lt ostream amp sa da Racio nal constg r O tipo de devolu o para que o canal seja passado sucessivamente em instru es de inser o encadeadas tais como ter naturalmente de ser ostreams ou seja o canal ter de ser devolvido por refer ncia Ali s a justifica o para o fazer id ntica que se usou para os operadores de incrementa o e decrementa o prefixo e para os operadores especiais de atribui o Ou seja a defini o da rotina operator lt lt dever tomar a forma Insere o racional no canal de sa da no formato de uma frac o Qpre V Qpost sa daV sa da cont m n d ou simplesmente n se d 1 sendo Ga frac o can nica correspondente ao racional r ostream operator lt lt ostreams sa da Racional const amp r return sa da Dada a exist ncia de opera es de inspec o que permitem obter o numerador e o denomina dor da frac o can nica correspondente a um racional seria perfeitamente poss vel eliminar a opera o Racional escreve da classe C Racional e usar o seu corpo com adap ta es como co
138. onal amp operator Racional const amp r2 Subtrai de um racional Opre this r QOpostoperator thisA this r r2 Racional amp operator Racional const amp r2 Multiplica por um racional Qpre this r post operator thisA this rxr2 Racional amp operator Racional const amp r2 Divide por um racional Qpre this rA12X0 post operator thisA this r x2 Racional amp operator Racional const r2 x Incrementa e devolve o racional Qpre this r post operador thisA this r 1l Racional amp operator Decrementa e devolve o racional Opre this r post operador this A this rr 1 Racional amp operator private int numerador int denominador Reduz a frac o que representa o racional Qpre denominador 0A this r post denominador amp 0Amde numerador denominador 1A this r void reduz 7 16 C DIGO COMPLETO DO TAD RACIONAL 421 Indica se a condi o invariante de classe se verifica pre V post cumpreInvariante 0 lt denominador A mdc numerador_ denominador_ 1 bool cumpreInvariante const y Adi o de dois racionais Qpre V Qpost operator r1 r2 Racional const operator Racional const rl Racional const r2 Subtrac o de dois racionais Qpre V Qpost operator r1 r2 Racional const operator Racional const rl Racional const amp
139. onst assert cumpreInvariante return this Como contra exemplo suponha se que a rotina que sobrecarrega o operador sufixo devol via por refer ncia constante Incrementa o racional recebido como argumento devolvendo o seu valor an tes de incrementado pre this r Opostoperatort rA this r 1 Racional const amp operator Racional amp r int Racional const c pia r r return c pia Erro Devolu o de refer ncia para vari vel local Seria claramente um erro faz lo pois seria devolvida uma refer ncia para uma inst ncia local que destru da logo que a fun o retorna 7 12 Reduzindo o n mero de invoca es com inline O mecanismo de invoca o de rotinas membro ou n o implica tarefas de arrumac o da casa algo morosas como se viu na Sec o 3 4 necess rio colocar na pilha o endere o de retorno e os respectivo argumentos executar as instru es do corpo da rotina depois retirar 390 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C os argumentos da pilha e retornar eventualmente devolvendo o resultado no seu topo Lo go a invoca o de rotinas pode ser em alguns casos um factor limitador da efici ncia dos programas Suponha se as instru es Racional r 1 3 Racional s r 2 Quantas invoca es de rotinas s o feitas neste c digo A resposta surpreendente mesmo ignorando as instru es de asser o que ali s podem ser fa
140. os s o vari veis ou constantes o que lhe interessa que ser o c pias dos argumentos que por isso n o ser o afectados pelas altera es que os par metros possam ou n o sofrer a interface da rotina n o afectada e as declara es TipoDeDevolu o rotina TipoDoPar metro par metro TipoDeDevolu o rotina TipoDoPar metro const par metro s o id nticas pelo que se s i usar apenas a primeira forma excepto quando for importante deixar clara a const ncia do par metro devido ao facto de ele ocorrer na condi o objectivo da rotina i e quando se quiser dizer que o par metro usado na condi o objectivo tem o valor original entrada da rotina Curiosamente poss vel criar classes cujo construtor por c pia ver Sec o 7 4 2 altere o original normal mente muito m ideia faz lo pois perverte a sem ntica usual da c pia mas em alguns casos poder ser uma pr tica justificada o caso do tipo gen rico auto ptr da biblioteca padr o do C Mas mesmo no caso de uma classe C ter um construtor por c pia que altere o original tal altera o ocorre durante a passagem de um argumento dessa classe C por valor seja ou n o o par metro respectivo constante o que s vem refor ar a irrele v ncia para a interface de uma rotina de se usar a palavras chave const para qualificar par metros que n o sejam refer ncias 378 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C J d
141. ou alteradas Essas rotinas mal comportados devem ser privadas de modo a evitar utiliza es err neas por parte do consumidor final da classe C que coloquem alguma inst ncia num estado inv lido A defini o de uma condi o invariante de classe e a sua imposi o entrada e sa da dos m todos p blicos e de rotinas amigas de uma classe C n o passa de um esfor o in til se as suas vari veis membro forem p blicas i e se o seu estado for alter vel do exterior Se o forem o consumidor da classe C pode alterar o estado de uma vari vel da classe por engano ou maliciosamente invalidando a condi o invariante de classe com consequ ncias potencialmente dram ticas no comportamento da classe C e no programa no seu todo Essas consequ ncias s o normalmente graves porque as rotinas que lidam com as vari veis membro da classe assumem que estas verificam a condi o invariante de classe n o fazendo quaisquer garantias acerca do seu funcionamento quando ela n o se verifica 332 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C De todas as opera es de uma classe C as mais importantes s o porventura as opera es construtoras S o estas que garantem que as inst ncias s o criadas verificando imediatamen te a condi o invariante de classe A sua import ncia pode ser vista na classe Racional em que os construtores garantem desde que as respectivas pr condi es sejam respeitadas que a condi o inva
142. ouble denominador A divis o do numerador pelo denominador feita depois de ambos serem convertidos para double De outra forma seria realizada a divis o inteira cujo resultado n o bem aquilo que se pretendia O problema deste tipo de operadores de convers o de tipo que devem ser usados com mo derac o que levam frequentemente a ambiguidades Por exemplo definido o operador de convers o para double de valores da classe C Racional como deve ser interpretado o seguinte c digo 444 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Racional r 1 3 O compilador pode interpretar a guarda da instru o de selec o ou condicional como double r double 1 ou como r Racional 1 mas n o sabe qual escolher As regras do C para resolver este tipo de ambiguidades s o algo complicadas ver 12 Sec o 7 4 e n o resolvem todos os casos No exemplo dado o programa de facto amb guo e portanto resulta num erro de compila o Como muito mais natural e frequente a convers o impl cita de um int num Racional do que a convers o impl cita de um Racional num double a melhor solu o simplesmente n o sobrecarregar o operador de convers o para double 7 17 8 Uma aplica o mais til das convers es H casos em que os operadores de convers o podem ser muito teis Suponha se que se pre tende definir um tipo Palavra que se comporta como um int em quase tudo mas fornece algumas
143. pera es da unidade e mant los durante toda a vida do c digo Por uni dade entende se aqui uma unidade de modulariza o tipicamente uma classe C e rotinas 14A n o ser para efeitos de estudo e desenvolvimento pessoal claro 7 6 TESTES DE UNIDADE 347 associadas que concretizam um TAD ou uma classe propriamente dita Os testes de unidade s muito parcialmente substituem as instru es de asser o para as condi es objectivo das opera es da classe 1 As instru es de asser es est o sempre activas e verificam a validade da condi o ob jectivo sempre que o opera o invocada Por outro lado os testes de unidade apenas s o executados de tempos e tempos e de uma forma independente do programa ou dos programas no qual a unidade testada est integrada 2 As instru es de asser o verificam a validade da condi o objectivo para todos os casos para os quais o programa ou os programas invocam a respectiva opera o da classe C No caso dos testes de unidade no entanto impens vel testar exaustivamente as opera es em causa 3 As instru es de asser o est o activas durante o desenvolvimento e durante a explo ra o do programa desenvolvido 5 enquanto os testes de unidade s o executados de tempos a tempos durante o desenvolvimento ou manuten o do programa Justificados que foram os testes de unidade pode se agora criar o teste de unidade para o TAD Racional ifdef TESTE
144. plementa o de uma classe implica normalmente uma alte ra o da condi o invariante de classe mas n o do comportamento externo da classe por isso muito importante que pr condi o e condi o objectivo de cada opera o m todo sejam claramente factorizadas em condi es que dizem respeito apenas implementa o e que de vem corresponder condi o invariante de classe e condi es que digam respeito apenas ao comportamento externo da opera o Dito por outras palavras apesar de do ponto de vista da implementa o a condi o invariante de classe fazer parte da pr condi o e da condi o objectivo de todas as opera es m todos como se disse na sec o anterior prefer vel p la em evid ncia documentando a claramente parte das opera es e m todos e excluindo a da documenta o contrato de cada opera o Ou seja a condi o invariante de classe far parte do contrato de cada m todo ponto de vista da implementa o mas n o far parte do contrato da correspondente opera o ponto de vista externo da interface Quando a condi o invariante de classe violada de quem a culpa Nesta altura j n o dever o subsistir d vidas a culpa do programador produtor da classe 1 Viola o da condi o invariante de classe culpa do programador produtor da classe 2 Viola o da pr condi o de uma opera o culpa do programador consumidor da clas se 3 Viola
145. pois de incrementada a vari vel i pela segunda vez e g imediatamente antes da instru o 5 depois de a rotina retornar V se claramente que a vari vel incrementada da segunda vez foi exactamente a vari vel i como se pretendia 7 7 DEVOLU O POR REFER NCIA 355 int main int valor 0 c pia valor 10 erro 10 mesmo valor A instru o envolvendo a rotina c pia est errada pois a rotina devolve um valor tempor rio que n o pode surgir do lado esquerdo de uma atribui o Na terminologia da linguagem C diz se que c pia valor n o um valor esquerdo lvalue ou left value Pelo contr rio a express o envolvendo a rotina mesmo est perfeitamente correcta sendo absolutamente equivalente a escrever valor 10 Na realidade ao se devolver por refer ncia numa rotina est se a dar a possibilidade ao con sumidor dessa procedimento de colocar a sua invoca o do lado esquerdo da atribui o Por exemplo definido a rotina incrementa como acima poss vel escrever int a 11 incrementa a 0 poss vel mas absurdo incrementa e depois atribui ze roa a incrementa a 2 poss vel mas m ideia incrementa e depois divi de a por dois Note se que a devolu o de refer ncias implica alguns cuidados adicionais Por exemplo a rotina int amp mesmoFalhado int v return v cont m um erro grave devolve uma refer ncia ou sin nimo para u
146. possibilidades adicionais tais como acesso individualizado aos seus bits ver Sec o 2 7 4 O novo tipo poderia ser concretizado custa de uma classe C class Palavra public Palavra int const valor 0 operator int const bool bit int const n const private int valor inline Palavra Palavra int const valor valor valor 7 17 OUTROS ASSUNTOS ACERCA DE CLASSES C 445 inline Palavra operator int const return valor inline bool Palavra bit int const n const return valor amp 1 lt lt n 0 Esta definic o tornaria poss vel escrever Palavra p 99996 D P 4 std cout lt lt Valor lt lt p lt lt std endl std cout lt lt Em bin rio for int i 32 i 0 1 std cout lt lt p bit i 1 std cout lt lt std endl que resultaria em Valor 100000 Em bin rio 00000000000000011000011010100000 Esta classe C para ser verdadeiramente til deveria proporcionar outras opera es que ficam como exerc cio para o leitor 446 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C
147. pr tica n o f cil a decis o de antecipar ou n o utiliza es futuras Durante o desen volvimento de uma classe deve se tentar suportar utiliza es futuras dif ceis de antecipar ou deve se restringir o desenvolvimento quilo que necess rio em cada momento Se o objec tivo preparar uma biblioteca de ferramentas utiliz veis por qualquer programador ent o claramente devem se tentar prever as utiliza es futuras Mas se a classe est a ser desenvol vida para ser utilizada num projecto em particular a resposta cai algures no meio destas duas 346 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C 14 op es m ideia de facto gastar esfor o de desenvolvimento a desenvolver ferramentas de utiliza o futura mais do que d bia Mas tamb m m ideia congelar o desenvolvimento de tal forma que aumentar as funcionalidades de uma classe C logo que tal se revele neces s rio seja dif cil O ideal pois est em n o desenvolver prevendo utiliza es futuras mas em deixar a porta aberta para futuros desenvolvimentos A recomenda o anterior n o se afasta muito do preconizado pela metodologia de desenvol vimento eXtreme Programming 1 Uma excelente recomenda o dessa metodologia tamb m o desenvolvimento dos chamados testes de unidade Se se olhar com aten o para a defini o da classe C Racional definida at agora conclui se facilmente que a maior parte das con di es object
148. presenta es alternativas para as frac es ver 1 7 7 3 REPRESENTA O DE RACIONAIS POR FRAC ES 311 racionais diferentes t m forcosamente representac es diferentes Mas Z e s o frac es que correspondem a um nico racional e que por acaso tamb m um inteiro Para se ob ter uma representac o em frac es que seja nica para cada racional necess rio introduzir algumas restri es adicionais Em primeiro lugar necess rio usar apenas o numerador ou o denominador para conter o sinal do n mero racional Como j se imp s uma restri o ao denominador viz d 0 natural impor uma restri o adicional d deve ser n o negativo Assim 0 lt d Mas necess ria uma restri o adicional Para que a representa o seja nica tamb m necess rio que n e d n o tenham qualquer divisor comum diferente de 1 i e que mdc n d 1 Uma frac o nestas condi es diz se em termos m nimos e dos seus termos diz se que s o mutuamente primos Dos tr s exemplos acima 2 e apenas a ltima frac o verifica todas as condi es enunciadas ou seja tem denominador positivo e numerador e denominador s o mutuamente primos Uma frac o que verifique estas condi es i e 0 lt d A mdc n d 1 diz se no formato can nico 7 3 1 Opera es aritm ticas elementares As opera es aritm ticas elementares adi o subtrac o multiplica o divis o sim trico e identidade
149. que seja o pr prio compilador a verificar do seu cumprimento tirando esse peso dos ombros do programador que pode por isso dedicar mais aten o a outros assuntos mais importantes o caso da classifica o de determinadas inst ncias como constantes estudada nesta sec o no mbito da classe Racional 7 11 1 Passagem de argumentos At agora viram se duas formas de passagem de argumentos por valor e por refer ncia Com a utiliza o da palavra chave const as possibilidades passam a quatro ou melhor a tr s e meia A forma mais simples de passagem de argumentos por valor Neste caso os par metros s o vari veis locais rotina inicializadas custa dos argumentos respectivos Ou seja os par metros s o c pias dos argumentos 7 11 CONST NCIA VERIFICANDO ERROS DURANTE A COMPILA O 377 Declara o TipoDeDevolu o rotina TipoDoPar metro par metro Defini o TipoDeDevolu o rotina TipoDoPar metro par metro E tamb m poss vel que os par metros sejam constantes Declara o TipoDeDevolu o rotina TipoDoPar metro const par metro Defini o TipoDeDevoluc o rotina TipoDoPar metro const par metro No entanto a diferen a entre um par metro vari vel ou constante no caso da passagem de argumentos por valor n o tem qualquer esp cie de impacte sobre o c digo que invoca a rotina Ou seja para o programador consumidor da rotina irrelevante se os par metr
150. r os atributos quer as opera es podem ser de inst ncia ou de classe consoante cada inst ncia da classe C possua conceptualmente a sua pr pria c pia do membro em causa ou exista apenas uma c pia desse membro partilhada entre todas as inst ncias da classe 310 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Todas as rotinas t m uma interface e uma implementa o e as rotinas membro n o s o excep o Normalmente o termo opera o usado para designar a rotina membro do ponto de vista da sua interface enquanto o termo m todo usado para designar a implementa o da rotina membro Para j a cada opera o corresponde um e um s m todo mas mais tarde se ver que poss vel associar v rios m todos mesma opera o Ao conjunto dos atributos e das opera es de uma classe C chama se caracter sticas embora como se ver o que caracteriza um TAD seja apenas a sua interface que normalmente n o inclui quaisquer atributos 7 24 Opera es suportadas pelas classes C Ao contr rio do que se passa com as matrizes as vari veis de uma classe C podem se atri buir livremente entre si O efeito de uma atribui o o de copiar todos os atributos de ins t ncia entre as vari veis em causa Da mesma forma poss vel construir uma inst ncia de uma classe a partir de outra inst ncia da mesma classe ficando a primeira igual segunda Por exemplo Racional rl 6 9 Racional r2 rl r2
151. ra o Racio nal somaCom 342 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C 7 5 Sobrecarga de operadores Tal como definida a classe C Racional obriga o consumidor a usar uma nota o desagra d vel e pouco intuitiva para fazer opera es com racionais Como se viu seria desej vel que a fun o main no programa em desenvolvimento se pudesse escrever simplesmente como int main 1 Ler frac es cout lt lt Introduza Racional rl r2 cin gt gt rl gt gt r2 if not cin cerr lt lt Opps dl return 1 duas frac es numerador denominador A leitura dos racionais falhou lt lt en Calcular racional soma Racional r rl r2 Escrever resultado cout lt lt A soma de lt lt rl Q lt lt com T lt lt f2 lt lt T V lt lt lt lt IN lt lt endl Se se pudesse escrever o programa como acima claramente a classe Racional uma vez equi pada com os restantes operadores dos tipos aritm ticos b sicos passaria a funcionar para o consumidor como qualquer outro tipo b sico do C seria verdadeiramente um tipo de pri meira categoria O C possibilita a sobrecarga dos operadores etc de modo a poderem ser utilizados com TAD concretizados pelo programador na forma de classes C A solu o para o problema passa ent o pela sobrecarga dos operadores do C de modo a terem novos significados quando aplicados
152. riante da classe se verifica para as inst ncias constru das Finalmente de notar que algumas classes C n o t m condi o invariante de classe Tais classes C n o s o normalmente concretiza es de nenhum TAD sendo meros agregados de informa o o caso por exemplo de um agregado que guarde nome e morada de utentes de um servi o qualquer Essas classes C t m normalmente todas as suas vari veis membro p blicas e por isso usam normalmente a palavra chave struct em vez de class Note se que estas palavras chave s o quase equivalentes pelo que a escolha de class ou struct meramente convencional escolhendo se class para classes C que sejam concretiza es de TAD ou classes propriamente ditas e struct para classes C que sejam meros agregados de informa o A nica diferen a entre as palavras chave struct e class que com a primeira todos os membros s o p blicos por omiss o enquanto com a segunda todos os membros s o privados por omiss o 7 4 4 Porqu o formato can nico das frac es Qual a vantagem de manter todas as frac es que representam os racionais no seu formato can nico I e qual a vantagem de impor 0 lt denominador A mdc numerador denominador como condi o invariante de classe C A verdade que esta condi o poderia ser consideravelmente relaxada para o programador consumidor a representa o interna dos racionais irrelevante muito embora ele espere que a opera
153. rotina ser em linha Que o compilador se lhe parecer apropriado e o compilador pode se recusar a faz lo em vez de traduzir o c digo da rotina em linguagem m quina coloc lo num nico local do programa execut vel e cham lo quando necess rio coloca o c digo da rotina em linguagem m quina directamente nos locais onde ela deveria ser invocada Por exemplo natural que o c digo m quina produzido por 7 12 REDUZINDO O N MERO DE INVOCAC ES COM INLINE 391 inline int soma int const amp a return a b int main int x1 10 int x2 20 int x3 30 int r 0 seja id ntico ao produzido por int main int xl 10 int x2 20 int x3 30 int r 0 r x x2 r x3 int const amp b soma r x3 Para melhor compreender o que foi dito boa ideia fazer uma digress o pela linguagem as sembly ali s a nica nestas folhas Para isso recorrer se m quina MAC 1 desenvolvida por Andrew Tanenbaum para fins pedag gicos e apresentada em 13 Sec o 4 3 ver tamb m MAC 1 asm http www daimi aau dk bentor html useful asm htm1 A tradu o para o assembly do MAC 1 do programa original Se n o levasse em conta o qualificador inline um compilador de C para assembly MAC 1 poderia gerar jump main Vari veis x1 10 x2 20 x3 30 r O main Programa principal 392 soma CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CL
154. rpo da rotina operator lt lt No entanto adoptar se uma solu o diferente Manter se a opera o Racional escreve embora com um nome mais apropriado e implementar se a rotina operator lt lt sua custa Para isso fundamental tornar a opera o mais gen rica de modo a inserir o racional num canal arbitr rio class Racional public Insere o racional no canal no formato de uma frac o Qpre V Qpost sa daV sa da cont m n d ou simplesmente n se d 1 sendo Za frac o can nica correspondente ao racional this void insereEm ostream amp sa da const y 7 14 OPERADORES DE INSER O E EXTRAC O 405 inline void Racional insereEm ostream amp sa da const assert cumpreInvariante sa da lt lt numerador_ if denominador 1 sa da lt lt lt lt denominador_ Insere o racional no canal de sa da no formato de uma frac o pre V Opost sa daV sa da cont m n d ou simplesmente n se d 1 sendo Ga frac o can nica correspondente ao racional r ostream operator lt lt ostreams sa da Racional const amp r r insereEm sa da return sa da 7 14 2 Sobrecarga do operador gt gt O caso do operador gt gt muito semelhante embora neste caso o primeiro operando do ope rador seja do tipo i st ream ou seja canal de entrada e se deva passar o racional por refer ncia para permitir a sua altera o
155. rvar um exemplo semelhante ao que se usou mais atr s mas usando racionais em vez de inteiros Racional r 1 2 r omesmoque 1 r escreve cout lt lt endl Este c digo absolutamente equivalente ao seguinte que usa a nota o usual de invoca o de opera es de uma classe C Racional r 1 2 r operator operator r escreve cout lt lt endl 7 7 DEVOLU O POR REFER NCIA 359 Aqui torna se perfeitamente clara a necessidade de devolver a pr pria vari vel impl cita para que esta possa ser usada par invocar pela segunda vez o mesmo operador Quanto ao operador prefixo a sua defini o igualmente simples Representa n meros racionais Qinvariant 0 lt denominador A mdc numerador denominador 1 class Racional public Decrementa e devolve o racional Qpre this r post operador this A this r w1 Racional amp operator y inline Racionalg Racional operator assert cumpreInvariante numerador denominador assert cumpreInvariante return this 7 7 3 Operadores e sufixo Qual a diferen a entre os operadores de incrementa o e decrementa o prefixo e sufixo Como j foi referido no Cap tulo 2 a diferen a est no que devolvem As vers es prefixo devolvem o pr prio operando j incrementado e as vers es sufixo devolvem uma c pia do valor do operando antes de incrementad
156. s ser o Isso deve se ao facto de ter sempre pr condi o V e de poder operar sobre va ri veis impl citas que n o verificam a condi o invariante de classe como bvio pois serve justamente para indicar se essa condi o se verifica e Os m todos privados n o t m instru es de asser o para a condi o invariante de clas se pois podem ser invocados por outros m todos em instantes de tempo durante os quais as inst ncias da classe inst ncia impl cita par metros etc n o verifiquem essa condi o Aplicando estas ideias classe Racional em desenvolvimento obt m se tinclude lt iostream gt tinclude lt cassert gt using namespace std Devolve o m ximo divisor comum dos inteiros passados como argumento Oprem mAn n mdc m n mA40VnX0 1 m 0 NN A post mdc int mdc int m int n Representa n meros racionais Qinvariant O lt denominador A mdc numerador denominador 1 class Racional public Constr i racional com valor inteiro Construtor por omiss o Qpre V post this n Racional int const n 0 Constr i racional correspondente a n d Qpre d 0 Opost this G Racional int const n int const d Escreve o racional no ecr no formato de uma frac o Qpre this r Qpost this rA coutV cout cont m n d ou simplesmente n se d 1 sendo Za frac o can nica correspondente ao racional this void escrev
157. s o fornecido implicitamente para a classe C C no exemplo original class C public CO private Racional rl Racional r2 ME Is ine Jy Sempre n o sejam colocados na lista de inicializa o de um construtor os atributos que n o sejam de tipos b sicos do C s o inicializados implicitamente atrav s do respectivo constru tor por omiss o se ele existir bem entendido Assim o construtor no exemplo acima pode se simplificar para EE Antes de ser executado o corpo do construtor envolvido numa construc o todos os atributos da classe C s o constru dos pela ordem da sua defini o na classe sendo passados aos cons trutores os argumentos indicados na lista de inicializadores entre par nteses ap s o nome do atributo se existirem ou os construtores por omiss o na falta do nome do atributo na lista com excep o dos atributos de tipos b sicos do C que t m de ser inicializados explicitamente caso contr rio ficam por inicializar Por exemplo no c digo class C public Gine tny dnt cd into 7 17 OUTROS ASSUNTOS ACERCA DE CLASSES C 441 private Racional rl Racional r2 int ts INC J C C int const n int const d int const 1 r1 n d i i 30 ao ser constru da a vari vel c invocado o seu construtor o que resultar nas seguintes ope ra es 1 Constru o de r1 por invoca o do construtor da classe C Racional com argumen tos n e d que neste caso
158. s adicionais digamos que incrementa de novo a linguagem para C ferramentas do programador biblioteca padr o linguagem C Figura 7 1 A bibloteca padr o do C e as ferramentas do programador como extens es funcionalidade b sica da linguagem C H essencialmente duas formas distintas de construir ferramentas adicionais para uma lin guagem A primeira passa por equipar a linguagem com opera es adicionais na forma de rotinas mas usando os tipos existentes int char bool double matrizes etc a chama da programa o procedimental A segunda passa por adicionar tipos linguagem e engloba a programa o centrada nos dados ou programa o baseada em objectos Para que os novos tipos criados tenham algum interesse fundamental que tenham opera es pr prias que t m de ser concretizadas pelo programador Assim a segunda forma de expandir a linguagem passa necessariamente pela primeira Neste cap tulo ver se a forma por excel ncia de acrescentar tipos e respectivas opera es linguagem No cap tulo anterior abordaram se as simples e limitadas enumera es neste ver se o os tipos abstractos de dados pe a fundamental da programa o centrada nos dados A partir deste ponto portanto o nfase ser posto na constru o de novos tipos Neste cap tulo construir se o novos tipos relativamente simples e independentes uns dos outros Quando se iniciar o estudo
159. s do vector poderiam ser guardadas numa matriz cl ssica do C membro da classe com a dimens o dada Ou seja class Vector public S de tal forma assim que se est a estudar a inclus o de uma classe gen rica semelhante na biblioteca padr o do C verhttp www boost org 7 17 OUTROS ASSUNTOS ACERCA DE CLASSES C 433 int const dimens o 3 erro private double coordenadas dimens o Infelizmente n o poss vel definir e inicializar uma constante dentro de uma classe A raz o para a proibi o simples Sendo dimens o uma constante membro de inst ncia cada inst ncia da classe C possuir a sua pr pria c pia dessa constante Mas isso significa que para ser verdadeiramente til essa constante dever poder tomar valores diferentes para cada inst ncia da classe C i e para cada vari vel dessa classe C que seja constru da Da que n o se possam inicializar atributos constantes de inst ncia na sua pr pria defini o Seria poss vel por exemplo inicializar a constante nos construtores da classe class Vector public int const dimens o Vector private double coordenadas dimens o Vector Vector dimens o 3 As listas de inicializadores s o extremamente teis sendo utilizadas para inicializar n o s atributos constantes como tamb m atributos que sejam refer ncias e atributos que sejam de uma classe sem construtor por omiss o i
160. sa classe C mas sim como seu consumidor 7 15 2 Classes amigas Da mesma forma que no caso das rotinas tamb m se podem declarar classes inteiras como amigas de uma classe C Nesse caso todos os m todos da classe declarada como amiga t m acesso s partes privadas da classe C que declarou a amizade Este tipo de amizade pode ser muito til em algumas circunst ncias como se ver no Cap tulo 10 embora em geral sejam de evitar A sintaxe da declara o de amizade de classes semelhante usada para as rotinas Por exemplo class B y class A public 418 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C private Declara o da classe C B como amiga da classe A friend class B 715 3 Promiscuidades Em que casos devem ser usadas rotinas ou classes amigas de uma classe C A regra ge ral o m nimo poss vel Se se puder evitar usar rotinas e classes amigas tanto melhor pois evita se introduzir uma excep o regra de que s os membros de uma classe C t m acesso suas partes privadas e regra de que a implementa o de uma classe corresponde s suas partes privadas e aos respectivos m todos Todas as excep es s o potencialmente geradoras de erros Como mnem nica do perigo das amizades em C fica a frase amizades normal mente trazem promiscuidades Assim e respeitando a regra geral enunciada manter se a implementa o da rotina operator gt gt custa da oper
161. smo resul tado tal como em incrementa es ou decrementa es isoladas por exemplo no progresso de um ciclo que a incrementa o ou decrementa o sufixo quase sempre menos eficiente do que a respectiva vers o prefixo O operador de decrementa o sufixo define se exactamente de mesma forma 362 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Decrementa o racional recebido como argumento devolvendo o seu valor an tes de decrementado Qpre this r Qpost operator rA this r w1 Racional operator Racional r int Racional const c pia r r return c pia Como bvio tendo se devolvido por valor em vez de por refer ncia n o poss vel escrever Racional r r erro que de resto j era uma constru o inv lida para os tipos b sicos do C 7 8 Mais operadores para o TAD Racional Falta ainda sobrecarregar muitos operadores para o TAD Racional Um facto curioso como se verificar em breve que os operadores aritm ticos sem efeitos laterais se implementam facilmente custa dos operadores aritm ticos com efeitos laterais e que a vers o alternativa em que se implementam os operadores com efeitos laterais custa dos que n o os t m conduz normalmente a menores efici ncias pois estes ltimos operadores implicam frequentemente a realiza o de c pias Assim tendo se j sobrecarregado os operadores de incrementa o e decrementa o o pr ximo passo ser
162. t lt lt lt lt denominador assert cumpreInvariante Racional Racional somaCom Racional const r2 assert cumpreInvariante and r2 cumpreInvariante Racional r r numerador numerador r2 denominador r2 numerador denominador r denominador denominador r2 denominador r reduz assert cumpreInvariante and r cumpreInvariante return r void Racional 1 assert cumpreInvariante LITE m cds if cin gt gt n gt gt d if d 0 cin setstate ios_base failbit else numerador d lt 0 n n denominador d lt 0 d d 340 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C reduz assert cumpreInvariante assert numerador d n denominador and cin return assert cumpreInvariante assert not cin void Racional reduz assert denominador 0 int k mdc numerador denominador numerador k denominador k assert denominador 0 and mdc numerador denomina bool Racional cumpreInvariante int dl return O lt denominador and mdc numerador denominador 1 main Ler frac es cout lt lt Introduza duas frac es numerador denominador Racional rl r2 add A t CLAUS if not cin cerr lt lt Opps A leitura dos racionais falhou lt lt en return 1 Calcular racional soma Racional r rl somaCom r2 7 4 CLASSE
163. t ncia destru da para arrumar a casa no final do tempo de vida das inst ncias de uma classe C Os destrutores s o extremamente teis particularmente quando se utilizam vari veis din micas ou em geral quando os construtores da classe C reservam algum recurso externo para uso exclusivo da inst ncia constru da Utiliza es mais interessan tes do conceito ver se o mais tarde bastando para j apresentar um exemplo ing nuo da sua utiliza o no mbito da classe C Vector Os destrutores declaram se e definem se como os construtores excepto que se coloca o s mbolo antes do seu nome que tamb m o nome da classe class Vector public static int const dimens o 3 Vector Vector static int n meroDeInst ncias private double coordenadas dimens o Ah J funciona static int n mero de inst ncias 7 17 OUTROS ASSUNTOS ACERCA DE CLASSES C Vector Vector n mero_de_inst ncias Vector Vector n mero de inst ncias inline int Vector n meroDeInst ncias return n mero de inst ncias int Vector n mero de inst ncias O 437 Note se que a linguagem fornece implicitamente um destrutor para as classes definidas sempre que este n o seja definido explicitamente pelo programador fabricante 7 17 4 De novo os membros de classe Suponha se o seguinte c digo usando a classe desenvolvida Vector a int main
164. t not cin Soma duas frac es Qpre denominador1 4 0 A denominador2 0 post Dumerador_ _ _numeradorl numerador2 P denominador denominadorl denominador2 denominador 0A mde numerador denominador 1 void somaFrac o int amp numerador int amp denominador int const numeradorl int const denominadorl int const numerador2 int const denominador2 assert denominadorl 0 and denominador2 0 numerador numeradorl denominador2 numerador2 denomina dorl denominador denominadorl denominador2 reduzFracc o numerador denominador assert denominador 0 and mdc numerador denomina dor 1 Escreve uma frac o no ecr no formato usual Qpre V post coutV cout cont m n d ou simplesmente n se d 1 sendo n e d os valores de numerador e denominador void escreveFracc o int const numerador int const denominador cout lt lt numerador if denominador 1 cout lt lt lt lt denominador int main 304 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Ler frac es cout lt lt Introduza duas frac es numerador denominador dl 12 a27 l Frac o nl dl d2 int nl l Frac o n2 if not cin Opps return 1 cerr lt lt A leitura das frac es falhou lt lt endl Calcular fracc o soma reduzida d somaFracc o n int n d nl dl n2 d2 Escrever resultado cout lt
165. tas do primeiro operando do operador Como resolver o problema H duas solu es para este dilema A primeira passa por tornar a rotina que sobrecarrega o operador amigo da classe C Racional ver Sec o 7 15 Esta solu o desaconselh vel pois h uma alternativa simples que n o passa por amizades e por isso n o est sujeita a introduzir quaisquer promiscuidades deve se explorar o facto de a rotina precisar de saber os valores do numerador e denominador da frac o can nica correspondente ao racional mas n o precisar de alterar o seu valor 372 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C 7 10 1 Inspectores e interroga es Se se pensar cuidadosamente nas poss veis utiliza es do TAD Racional conclui se facil mente que o programador consumidor pode necessitar de conhecer a frac o can nica corres pondente ao racional Se assim for conv m equipar a classe C com duas fun es membro que se limitam a devolver o valor do numerador e denominador dessa frac o can nica Como a representa o de um Racional justamente feita custa de uma frac o can nica conclui se que as duas fun es membro s o muito f ceis de implementar class Racional public Devolve numerador da frac o can nica correspondente ao racional Qpre this r this p Dumerador_ _ xthis post this r denominador this int numerador Devolve denominador da frac
166. terais obriga utiliza o de uma fun o com efeitos laterais O terceiro problema mais grave que mesmo que fosse poss vel a passagem de uma vari vel tempor ria por re fer ncia o c digo acima ainda n o faria o desejado pois nesse caso a segunda invoca o da rotina incrementa acabaria por alterar apenas essa vari vel tempor ria e n o a vari vel i como se pode ver na Figura Para resolver este problema a rotina dever devolver n o uma c pia de i mas a pr pria vari vel i que como quem diz um sin nimo da vari vel i Ou seja a rotina dever devolver i por refer ncia Esta restri o razoavelmente arbitr ria e est em discuss o a sua poss vel elimina o numa pr xima vers o da linguagem C 352 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C vi int amp v int amp retorno retorno a5 a5 int vi int amp v int amp 7 int int int retorno retorno A nt CIAO F 1 i int 1 int A Ant 1 int 1 int trint 1 int 0 0 lt 1 Sa 1 1 1 1 5 4 a b c d e f g Figura 7 6 Estado da pilha durante a execu o a Imediatamente antes das invoca es nas linhas 3 e 4 b imediatamente antes da instru o 1 depois de invocada a rotina pela primeira vez j com o par metro v na pilha c entre as instru es 1 e 2 j depois de incrementado v e portanto
167. tos e inst ncias embora em rigor o termo objecto deva ser reservado para as classes propriamente ditas a estudar em cap tulos posteriores Para todos os efeitos os atributos da classe Racional funcionam como vari veis guardadas quer dentro da vari vel r1 quer dentro da vari vel r2 A notac o usada para representar inst ncias de uma classe a que se pode ver na Figura 7 3 onde fica claro que os atributos s o parte das inst ncias da classe Deve se comparar a Figura 7 2 com a Figura 7 3 pois na primeira representa se a classe Racional e na segunda as vari veis r1 e r2 dessa classe 308 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C rl Racional numerador 6 denominador 9 r2 Racional atributo numerador 7 denominador 3 valor a Nota o usual rl Racional r2 Racional numerador int 6 numerador int 7 denominador int 9 denominador int 3 b Com sub inst ncias rl Racional 2 3 r2 Racional 7 3 c Como TAD com valor l gico representado Figura 7 3 Nota es usadas para representar inst ncias da classe C Racional 7 2 TIPOS ABSTRACTOS DE DADOS E CLASSES C 309 7 2 2 Acesso aos membros O acesso aos membros de uma inst ncia de uma classe C faz se usando o operador de se lec o
168. tra qualquer s que representa um canal de leitura para um dado ficheiro tamb m poss vel usar cadeias de caracteres para especificar o nome do ficheiro ao qual o canal deve estar ligado 414 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C cout lt lt Diga o nome do ficheiro string nome do ficheiro cin gt gt nome do ficheiro ifstream entrada nome do ficheiro c str O estabelecimento de um canal de entrada pode falhar Por exemplo se o ficheiro n o exis tir ou se estiver protegido para leitura Se o estabelecimento do canal falhar durante a sua constru o este fica em estado de erro sendo de novo muito f cil verificar essa situa o cout lt lt Diga o nome do ficheiro string nome do ficheiro cin gt gt nome do ficheiro ifstream entrada nome do ficheiro c str if not entrada cerr lt lt Opps N o consegui ligar a ficheiro N lt lt nome do ficheiro lt lt X lt lt endl Tal como para os canais de sa da tamb m poss vel estabelecer e encerrar um canal usando as opera es ofstream open que recebe o nome do ficheiro como argumento e ofs tream close que n o tem argumentos A partir do momento em que um canal de entrada est estabelecido pode se us lo da mesma forma que ao canal cin Por exemplo cout lt lt Diga o nome do ficheiro string nome_do_ficheiro cin gt gt nome_do_ficheiro ofstream entrada nome do ficheiro
169. tru es Mas porqu definir estes operadores como rotinas normais n o membro H uma raz o de peso que tem a ver com as convers es impl citas 7 9 CONSTRUTORES CONVERS ES IMPL CITAS E VALORES LITERAIS 369 7 9 Construtores convers es impl citas e valores literais 7 9 1 Valores literais J se viu que a defini o de classes C concretizando TAD permite a acrescentar linguagem C novos tipos que funcionam praticamente como os seus tipos b sicos Mas haver equi valente aos valores literais Recorde se que num programa em C 10 e 100 0 s o valores literais dos tipos int e double respectivamente Ser poss vel especificar uma forma para por exemplo escrever valores literais do novo tipo Raciona1 Infelizmente isso imposs vel em C Por exemplo o c digo Racional r r 1 3 redunda num programa aparentemente funcional mas com um comportamento inesperado Acontece que a express o 1 3 interpretada como a divis o inteira que neste caso tem re sultado zero Esse valor inteiro depois convertido implicitamente para o tipo Racional e atribu da vari vel r Logo r depois da atribuic o conter o racional zero Existe uma alternativa elegante aos inexistentes valores literais para os racionais propor cionada pelos construtores da classe e funciona quase como se de valores literais se tratasse os construtores podem ser chamados explicitamente para criar um novo valor dessa classe Assim
170. u seja lt 1 o que uma contradi o Logo le a k n o t m divisores comuns n o unit rios Ser que pode haver divisores n o unit rios comuns a l e a did Suponha se que existe um divisor 1 lt comum a lea dd Nesse caso existe for osamente um divisor 1 lt j comum a l e a d ou a d Se j for divisor comum a l e a d ent o j tamb m divisor comum a n e a di ou seja j lt mdc n dy donde se conclui que j lt 1 o que uma contradi o O mesmo argumento se aplica se j for divisor comum a le a d Logo l e did n o t m divisores comuns n o unit rios Ser que podem haver divisores n o unit rios comuns a n x d n xd ea d xd Suponha se que existe um divisor 1 lt h comum n x d n4 x d e de d x dy Nesse caso existe for osamente um divisor 1 lt i comum a n x d n x di ea dj ou a d Seja ent o 1 lt i um divisor comum an x dh n x di ea di Nesse caso tem de existir um divisor 1 lt j comum a dj ea n ou a dy Isso implicaria que j lt mdc n d ou que j lt mdc d d 4 1 Em qualquer dos casos conclui se que j lt 1 o que uma contradi o O mesmo argumento se aplica se 1 lt i for divisor comum a nj x dy n4 x d ea d Logo nj x dh n x dj e d x dh n o t m divisores comuns n o unit rios Assim a existirem divisores n o unit rios comuns ao denominador e numerador da frac o l x ny x d5 n5 x dy k x di x ds eles devem se exist ncia de d
171. urn 1 if m lt O 302 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C A while true if m 0 return n n n m if n 0 return m m m n Reduz a frac o recebida como argumento Qpre denominador 0 A denominador dA numerador n post denominador 0 mdc numerador denominador 1A numerador__ n denominador d void reduzFrac o int amp numerador int amp denominador assert denominador 0 int m ximo_divisor_comum mdc numerador denominador numerador m ximo_divisor_comum denominador m ximo_divisor_comum assert denominador 0 and mdc numerador denomina L do teclado uma frac o na forma de dois inteiros sucessivos pre numerador n denominador d postSe cin e cin tem dois inteiros n e d dispon veis para leitura com d 0 ent o 0 lt denominador mdc numerador denominador 1 numerador__n denominador Cin sen o numerador n A denominador n N cin void l Frac o int amp numerador int amp denominador int n d LE Cin gt gt n gt gt d if d 0 cin setstate ios_base failbit else numerador d lt 0 n n 7 1 DE NOVO A SOMA DE FRAC ES 303 denominador d lt 0 d d reduzFracc o numerador denominador assert 0 lt denominador and mdc numerador denomina dor 1 and numerador d n denominador and cin return asser
172. xemplo 382 CAP TULO 7 TIPOS ABSTRACTOS DE DADOS E CLASSES C Indica se dois racionais s o iguais Qpre V Gpost operator r1 r2 bool operator Racional const rl Racional const amp r2 return rl numerador r2 numerador and rl denominador r2 denominador Os par metros r1 e r2 desta rotina funcionam como sin nimos constantes dos respectivos argumentos que podem ser constantes ou n o Logo o compilador assinala um erro no corpo desta rotina ao se tentar invocar os inspectores Racional numerador e Raci onal denominador atrav s das duas constantes o compilador n o adivinha que uma opera o n o altera a inst ncia impl cita Ali s nem o poderia fazer pois muitas vezes no c digo que invoca a opera o o compilador n o tem acesso ao respectivo m todo como se ver no 9 pelo que n o pode verificar se de facto assim Logo necess rio indicar explicitamente ao compilador quais as opera es que n o alteram a inst ncia impl cita ou seja quais as opera es que tratam a inst ncia impl cita como uma constante impl cita Isso consegue se acrescentando a palavra chave const ao cabe alho das opera es em causa e respectivos m todos pois esta palavra chave passar a fazer parte da respectiva assinatura o que permite sobrecarregar uma opera o com o mesmo nome e lista de par metros onde a nica coisa que varia a const ncia da inst ncia impl cita
Download Pdf Manuals
Related Search
Related Contents
Motorola ASTRO W3 User`s guide Aufbau- Bedienungsanleitung Delos Serie INSCRIPTION-ANNULATION : MODE D`EMPLOI About this User`s Manual Manual de instalación y mantenimiento Triton Riel GX ingecon hybrid monofásico Cables Direct 1.7m SCSI-3 HP68 Soundmate 2 Copyright © All rights reserved.
Failed to retrieve file