Documente Academic
Documente Profesional
Documente Cultură
Copyright(C) 2003-2007 da Novatec Editora Ltda. proibida a reprodu Todos os direitos reservados e protegidos pela Lei 5.988 de 14/12/1973. E ca o desta obra, mesmo parcial, por qualquer processo, sem pr evia autoriza ca o, por escrito, do autor e da Editora.
Editor: RUBENS PRATES Capa: CAMILA MESQUITA Revis ao: PATRIZIA ZAGNI DUARTE BUENO Editora ca o eletr onica: ANDRE Revis ao t ecnica desta edi ca o: TIAGO RIBEIRO SCHAEWER [M.Sc, Doutorando] TIAGO CALIMMAN [Mestrando] IRINEU SILVA [Mestrando] ALLAN GALANTE [M.Sc.] GIOVANNI COLONESE [M.Sc.] ISBN: XX-XXXX-XXX-X
NOVATEC EDITORA LTDA. Rua Cons. Moreira de Barros, 1084 Conj. 01 02018-012 S ao Paulo, SP Brasil Tel.: +55 11 6959-6529 Fax: +55 11 6950-8869 E-mail: novatec@novateceditora.com.br Endere co: www.novateceditora.com.br
Este livro foi desenvolvido no LDSC/LENEP/UENF Laborat orio de Desenvolvimento de Software Cient co - LDSC http://www.lenep.uenf.br/~ldsc do Laborat orio de Engenharia e Explora ca o de Petr oleo - LENEP http://www.lenep.uenf.br da Universidade Estadual do Norte Fluminense - Darcy Ribeiro - UENF http://www.uenf.br
Sum ario
I Filosoa e Modelagem Orientada a Objeto
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
51 51 51 52 52 52 54 54 55 55 56 57 58 59 59 61 61 62 63 63 64 66 66 66 69 69 70 72 73 73 74 75 76 79 80
1 Introdu c ao ` a Programa c ao 1.1 Programas e softwares . . . . . . . . . . . . . . . . . . . . 1.1.1 O que e um programa, um software? . . . . . . . . 1.2 Deni ca o de software propriet ario e software livre . . . . . 1.2.1 Deni ca o e caracter sticas do software propriet ario 1.2.2 Deni ca o e caracter sticas do software livre . . . . 1.2.3 Exemplos de softwares livres e propriet arios . . . . 1.3 Tipos de interface de um programa/software . . . . . . . . 1.3.1 Um programa sem interface (kernel num erico) . . . 1.3.2 Um programa com interface via linha de comando 1.3.3 Um programa com interface em modo texto . . . . 1.3.4 Um software com interface em modo gr aco . . . . 1.4 Que tipo de software devo desenvolver? . . . . . . . . . . 1.5 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . 1.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Introdu c ao ` a Programa c ao Orientada a Objeto POO 2.1 Entendendo os objetos . . . . . . . . . . . . . . . . . . . . . 2.2 Exemplo de objeto . . . . . . . . . . . . . . . . . . . . . . . 2.3 O conceito de objeto (ou inst ancia) . . . . . . . . . . . . . . 2.4 Breve hist orico da programa ca o orientada a objeto . . . . . 2.4.1 Vis ao desorganizada e vis ao estruturada versus vis ao 2.4.2 Vantagens da POO . . . . . . . . . . . . . . . . . . . 2.5 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . 2.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Conceitos B asicos de Orienta c ao a Objeto OO 3.1 Abstra ca o . . . . . . . . . . . . . . . . . . . . . . . 3.2 Encapsulamento e oculta ca o . . . . . . . . . . . . . 3.3 Classes . . . . . . . . . . . . . . . . . . . . . . . . . 3.4 Atributos (propriedades e vari aveis) . . . . . . . . 3.5 M etodos (fun co es, opera co es e servi cos) . . . . . . 3.6 Heran ca . . . . . . . . . . . . . . . . . . . . . . . . 3.7 Polimorsmo . . . . . . . . . . . . . . . . . . . . . 3.8 Outros conceitos u teis . . . . . . . . . . . . . . . . 3.9 Resumo do cap tulo . . . . . . . . . . . . . . . . . 3.10 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . orientada a objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 4 Modelagem Orientada a Objeto 4.1 Introdu ca o ` a modelagem . . . . . . . . . . . . . . . . . . . . . . 4.1.1 O que e um modelo? . . . . . . . . . . . . . . . . . . . . 4.1.2 Tipos e exemplos de modelos . . . . . . . . . . . . . . . 4.1.3 Por que usamos modelos? . . . . . . . . . . . . . . . . . 4.2 Introdu ca o ` a modelagem orientada a objeto . . . . . . . . . . . 4.2.1 O que e a modelagem orientada a objeto? . . . . . . . 4.2.2 Quando surgiu a modelagem orientada a objeto? . . . 4.2.3 Quais as vantagens da modelagem orientada a objeto? . 4.3 O que e a UML? . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 As diferentes vis oes da UML e os respectivos diagramas 4.3.2 Os elementos da UML . . . . . . . . . . . . . . . . . . . 4.3.3 Os estere otipos da UML2 . . . . . . . . . . . . . . . . . 4.4 Programas para modelagem orientada a objeto . . . . . . . . . 4.4.1 O programa Dia . . . . . . . . . . . . . . . . . . . . . . 4.4.2 O programa umbrello . . . . . . . . . . . . . . . . . . . 4.4.3 O programa Visual-Paradigm . . . . . . . . . . . . . . . 4.5 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . 4.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Engenharia de Software 5.1 O que e e quais s ao os objetivos da engenharia de software? . 5.2 Breve hist orico da engenharia de software . . . . . . . . . . . 5.3 Caracter sticas dos modelos de engenharia de software . . . . 5.3.1 Modelo seq uencial linear . . . . . . . . . . . . . . . . . 5.3.2 Modelo iterativo . . . . . . . . . . . . . . . . . . . . . 5.3.3 Modelo baseado em prototipagem . . . . . . . . . . . 5.3.4 Modelo RAD Rapid Application Development . . . 5.3.5 Modelo incremental . . . . . . . . . . . . . . . . . . . 5.3.6 Modelo espiral . . . . . . . . . . . . . . . . . . . . . . 5.3.7 Modelo TMO Tecnologia de Modelagem de Objetos 5.3.8 Modelo UP Unied Process . . . . . . . . . . . . . . 5.3.9 Modelo XP eXtreme Programming . . . . . . . . . . 5.4 O modelo selecionado . . . . . . . . . . . . . . . . . . . . . . 5.5 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . 5.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Etapas para o Desenvolvimento de um Software 6.1 Concep ca o especica ca o . . . . . . . . . . . . . . . . . . . 6.1.1 Casos de uso do software cen arios . . . . . . . . . 6.1.2 Diagrama de casos de uso . . . . . . . . . . . . . . . 6.1.3 Senten cas para casos de uso . . . . . . . . . . . . . . 6.2 Elabora ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.1 An alise de dom nio . . . . . . . . . . . . . . . . . . . 6.2.2 Identica ca o de pacotes assuntos . . . . . . . . . . 6.2.3 Diagrama de pacotes assuntos, m odulos . . . . . . 6.2.4 Senten cas para pacotes . . . . . . . . . . . . . . . . . 6.2.5 Montagem de prot otipo da interface do software . . 6.2.6 Deni ca o de cronogramas, prazos, custos, contratos 6.3 AOO An alise Orientada a Objeto . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO 81 81 81 82 82 84 84 84 85 85 85 88 89 93 93 94 96 96 97 99 99 100 101 101 102 102 102 102 102 103 103 104 105 106 106 109 110 111 111 113 114 115 116 116 117 117 118 119
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO 6.4 AOO Modelo estrutural . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.1 Identica ca o de classes . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.2 Identica ca o de atributos . . . . . . . . . . . . . . . . . . . . . . . 6.4.3 Identica ca o de m etodos . . . . . . . . . . . . . . . . . . . . . . . . 6.4.4 Diagrama de classes . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.5 Identica ca o de associa co es . . . . . . . . . . . . . . . . . . . . . . 6.4.6 Diagrama de classes com associa co es . . . . . . . . . . . . . . . . . 6.4.7 Classe de associa ca o . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.8 Identica ca o de agrega co es e composi co es . . . . . . . . . . . . . . 6.4.9 Diagrama de classes com agrega co es e composi co es . . . . . . . . . 6.4.10 Identica ca o de heran cas . . . . . . . . . . . . . . . . . . . . . . . 6.4.11 Diagrama de classes com heran cas . . . . . . . . . . . . . . . . . . 6.4.12 Identica ca o de classes abstratas e classes de interface . . . . . . . 6.4.13 Restri co es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.14 Realiza co es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.15 Depend encias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.16 Identica ca o de objetos . . . . . . . . . . . . . . . . . . . . . . . . 6.4.17 Diagrama de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.18 Diagrama de estrutura composta . . . . . . . . . . . . . . . . . . . 6.4.19 Resumo dos diagramas do modelo estrutural . . . . . . . . . . . . 6.4.20 Itera ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . AOO Modelo din amico . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.1 Identica ca o de eventos e mensagens . . . . . . . . . . . . . . . . . 6.5.2 Diagrama de seq u encia eventos e mensagens . . . . . . . . . . . . 6.5.3 Diagrama de comunica ca o colabora ca o . . . . . . . . . . . . . . 6.5.4 Identica ca o dos estados assumidos pelo objeto . . . . . . . . . . . 6.5.5 Diagrama de m aquina de estado . . . . . . . . . . . . . . . . . . . 6.5.6 Identica ca o de atividades . . . . . . . . . . . . . . . . . . . . . . . 6.5.7 Diagrama de atividades . . . . . . . . . . . . . . . . . . . . . . . . 6.5.8 Diagrama de tempo . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.9 Diagrama de intera ca o geral . . . . . . . . . . . . . . . . . . . . . . 6.5.10 Resumo dos diagramas do modelo din amico . . . . . . . . . . . . . 6.5.11 Itera ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Projeto do sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.6.1 Deni ca o da interface de programa ca o API . . . . . . . . . . . . 6.6.2 Sele ca o da implementa ca o de controle . . . . . . . . . . . . . . . . 6.6.3 Sele ca o das plataformas a serem suportadas . . . . . . . . . . . . . 6.6.4 Sele ca o das bibliotecas externas . . . . . . . . . . . . . . . . . . . . 6.6.5 Sele ca o da biblioteca gr aca a ser utilizada GDI . . . . . . . . . 6.6.6 Sele ca o do ambiente de desenvolvimento integrado IDE . . . . . Projeto orientado a objeto POO . . . . . . . . . . . . . . . . . . . . . . 6.7.1 Diagrama de componentes . . . . . . . . . . . . . . . . . . . . . . . 6.7.2 Diagrama de implanta ca o execu ca o . . . . . . . . . . . . . . . . . Implementa ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.8.1 Antes de iniciar a implementa ca o . . . . . . . . . . . . . . . . . . . 6.8.2 Roteiro para montar o c odigo inicial do programa com o Umbrello 6.8.3 Dicas para implementa ca o da interface gr aca . . . . . . . . . . . Teste de software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.9.1 Por que testar? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 119 119 120 121 122 123 124 125 125 126 126 128 128 130 130 130 130 131 131 131 132 133 133 134 137 138 139 143 143 146 146 146 146 148 149 150 150 151 152 152 157 159 160 161 161 161 162 162 163
6.5
6.6
6.7
6.8
6.9
6 6.9.2 Equipe de teste . . . . . . . . . . . . . . . . . . . . . 6.9.3 Metodologia de teste . . . . . . . . . . . . . . . . . . 6.9.4 Senten cas para teste de software . . . . . . . . . . . Documenta ca o do programa . . . . . . . . . . . . . . . . . . 6.10.1 Itens a serem documentados . . . . . . . . . . . . . . 6.10.2 Cart oes CRC . . . . . . . . . . . . . . . . . . . . . . 6.10.3 Dicion ario de classes . . . . . . . . . . . . . . . . . . Manuten ca o e reuso de software . . . . . . . . . . . . . . . . 6.11.1 Senten cas e dicas para conseguir o reuso de software 6.11.2 Senten cas para aumentar o empacotamento . . . . . 6.11.3 Senten cas para conseguir o reuso de classes . . . . . 6.11.4 Senten cas para conseguir o reuso de m etodos . . . . 6.11.5 Senten cas para montagem de bibliotecas . . . . . . 6.11.6 Senten cas para montagem de framework . . . . . . 6.11.7 Senten cas para facilitar a extens ao de um programa 6.11.8 Senten cas para programa ca o em grande escala . . . Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 163 166 168 168 172 172 173 173 173 173 174 175 175 176 176 177 177
6.10
6.11
6.12 6.13
II
181
. . . . . . . . . . . . . . . . . . . . . . . . . 183 183 184 185 185 186 186 187 189 189 189 190 191 192 193 193 195 195 198 199 199 199 200 200 201 201 202
7 Introdu c ao ao C++ 7.1 Um pouco de hist oria . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Exemplos de aplica co es em C++ . . . . . . . . . . . . . . . . . . . . 7.3 O que e o Ansi C++? . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4 Quais as novidades e vantagens de C++ em rela ca o a C? . . . . . . 7.5 Quais os tipos de programas em C++ . . . . . . . . . . . . . . . . . 7.6 Diferen cas de nomenclatura POO e C++ . . . . . . . . . . . . . . 7.7 Editar, pr e-processar, compilar, linkar, debugar e otimizar . . . . . . 7.8 Layout de um programa orientado a objeto em C++2 . . . . . . . . 7.8.1 Arquivo de projeto . . . . . . . . . . . . . . . . . . . . . . . . 7.8.2 Arquivo de cabe calho da classe CNomeClasse.h . . . . . . . 7.8.3 Arquivo de implementa ca o da classe CNomeClasse.cpp . . . 7.8.4 Arquivo de implementa ca o da fun ca o main() programa.cpp 7.9 Senten cas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.10 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.11 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Conceitos b asicos de C++ 8.1 Sobre a sintaxe de C++ . . . . . . . . . . . . . . . . . 8.2 Palavras-chave do C++ . . . . . . . . . . . . . . . . . 8.3 Nome dos objetos identicadores . . . . . . . . . . . 8.3.1 Conven ca o para nomes de objetos . . . . . . . 8.4 Declara co es . . . . . . . . . . . . . . . . . . . . . . . . 8.4.1 Exemplos de declara co es e deni co es2 . . . . . 8.5 Deni co es . . . . . . . . . . . . . . . . . . . . . . . . . 8.6 Introdu ca o ` a fun ca o main() . . . . . . . . . . . . . . . 8.7 Introdu ca o ` a entrada e sa da de dados com cin e cout 8.7.1 Usando cout . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO 8.7.2 Usando cin . . . . . . . . . . . . . . . . Introdu ca o ` as diretrizes de pr e-processador . . 8.8.1 Usando #ifdef..#endif . . . . . . . . Introdu ca o ` as estruturas de controle . . . . . . 8.9.1 Usando for . . . . . . . . . . . . . . . . 8.9.2 Usando while e fun co es da biblioteca de Introdu ca o aos operadores de C++ . . . . . . . 8.10.1 Usando operadores de C++ . . . . . . . Introdu ca o as fun co es . . . . . . . . . . . . . . Declara co es e escopo . . . . . . . . . . . . . . . Senten cas para conceitos b asicos de C++ . . . Resumo do cap tulo . . . . . . . . . . . . . . . Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C/C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7 203 205 205 206 206 207 208 208 210 213 214 215 216 217 217 217 221 222 224 225 225 225 228 229 229 230 231 233 235 235 236 236 238 239 239 240 240 243 243 244 244 245 247 248 248 248 248 249
8.8 8.9
9 Tipos 9.1 Introdu ca o ao conceito de tipos . . . . . . . . . . . . 9.2 Uso de tipos predenidos de C++ . . . . . . . . . . 9.2.1 Uso de suxos para os tipos predenidos2 . . 9.2.2 Uso avan cado dos tipos predenidos2 . . . . . 9.2.3 Senten cas para uso de tipos predenidos . . . 9.3 Uso de tipos do usu ario . . . . . . . . . . . . . . . . 9.3.1 Introdu ca o aos vetores no estilo de C . . . . . 9.3.2 Introdu ca o ` as estruturas . . . . . . . . . . . 9.3.3 Introdu ca o ` as uni oes . . . . . . . . . . . . . . 9.3.4 Introdu ca o ` as enumera co es . . . . . . . . . . 9.3.5 Introdu ca o ` as classes . . . . . . . . . . . . . . 9.4 Usando tipos denidos em bibliotecas STL . . . . 9.4.1 Introdu ca o ` a classe <string> . . . . . . . . . 9.4.2 Introdu ca o ` a STL e ` a classe <vector> . . . . 9.5 Manipulando tipos . . . . . . . . . . . . . . . . . . . 9.5.1 Criando apelidos typedef . . . . . . . . . 9.5.2 Obtendo o tipo de tamanho size_t() . . . 9.5.3 Obtendo o tamanho dos objetos sizeof() . 9.5.4 Identicando o tipo do objeto typeid()2 . 9.6 Vantagem da tipica ca o forte do C++ . . . . . . . . 9.7 Senten cas para tipos . . . . . . . . . . . . . . . . . . 9.8 Resumo do cap tulo . . . . . . . . . . . . . . . . . . 9.9 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . .
10 Namespace 10.1 O que e um namespace? . . . . . . . . . . . . . . . . . . . . 10.2 Utilizando o espa co de nomes da biblioteca-padr ao std:: 10.3 Mudando escopo com using . . . . . . . . . . . . . . . . . . 10.4 Prot otipo para declarar e denir um namespace . . . . . . . 10.5 Namespaces an onimos . . . . . . . . . . . . . . . . . . . . . 10.6 Namespaces uso avan cado2 . . . . . . . . . . . . . . . . . 10.6.1 Compondo namespace com using2 . . . . . . . . . . 10.6.2 Namespace aninhado2 . . . . . . . . . . . . . . . . . 10.6.3 Usando vari aveis est aticas em um namespace2 . . . 10.7 Senten cas para namespace . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++
SUMARIO 10.8 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 10.9 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
11 Classes 11.1 Prot otipo para declarar e denir classes . . . . . . . . 11.2 Encapsulamento em C++ utilizando o especicador de 11.3 Classes e escopo . . . . . . . . . . . . . . . . . . . . . 11.4 Classes e diretrizes de pr e-processador . . . . . . . . . 11.5 Classes Uso avan cado2 . . . . . . . . . . . . . . . . . 11.5.1 Classes abstratas2 . . . . . . . . . . . . . . . . 11.5.2 Classes de interface2 . . . . . . . . . . . . . . . 11.5.3 Classes encapsulamento e robustes de c odigo2 . 3 11.5.4 Classes aninhadas . . . . . . . . . . . . . . . . 11.5.5 Classes do tipo POD3 . . . . . . . . . . . . . . 11.5.6 Classes do tipo trivial3 . . . . . . . . . . . . . . 11.6 Senten cas para classes . . . . . . . . . . . . . . . . . . 11.7 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . 11.8 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . 12 Atributos 12.1 Prot otipo para declarar e denir atributos 12.2 Atributos de objeto . . . . . . . . . . . . . 12.3 Atributos de classe static . . . . . . . 12.4 Atributos constantes const . . . . . . . 12.5 Atributos uso avan cado2 . . . . . . . . . 12.5.1 Atributos mutantes mutable2 . . 12.5.2 Atributos vol ateis volatile3 . . 12.6 Senten cas para atributos . . . . . . . . . . 12.7 Resumo do cap tulo . . . . . . . . . . . . 12.8 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
251 251 252 253 253 254 254 255 255 256 257 257 258 259 259 261 261 262 263 265 266 266 267 267 268 268 269 269 270 271 272 273 273 274 274 275 277 278 281 284 286 290 290 292 292
13 M etodos 13.1 Introdu ca o aos m etodos de C++ . . . . . . . . . 13.2 Prot otipo para declarar e denir m etodos . . . . 13.3 Declara ca o de um m etodo . . . . . . . . . . . . . 13.4 Deni ca o de um m etodo . . . . . . . . . . . . . . 13.5 Retorno de um m etodo . . . . . . . . . . . . . . . 13.6 Par ametros dos m etodos . . . . . . . . . . . . . . 13.6.1 Passagem dos par ametros por c opia . . . 13.6.2 Passagem dos par ametros por refer encia 13.6.3 Passagem dos par ametros por ponteiro . . 13.6.4 Par ametros predenidos inicializadores . 13.7 M etodos normais . . . . . . . . . . . . . . . . . . 13.8 M etodos constantes const . . . . . . . . . . . . 13.9 M etodos est aticos static . . . . . . . . . . . . 13.10M etodos em linha inline . . . . . . . . . . . . 13.11M etodos uso avan cado . . . . . . . . . . . . . . 13.12Senten cas para m etodos . . . . . . . . . . . . . . 13.13Resumo do cap tulo . . . . . . . . . . . . . . . . 13.14Exerc cios . . . . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++
SUMARIO 14 Sobrecarga de M etodos 14.1 Prot otipo para sobrecarga de m etodos . . . . . . . 14.2 Como implementar a sobrecarga de m etodos . . . 14.3 Sobrecarga de m etodos conceitos avan cados2 . . 14.3.1 Acessibilidade x visibilidade: como e feita executado . . . . . . . . . . . . . . . . . . . 14.4 Senten ca para sobrecarga de m etodos . . . . . . . . 14.5 Resumo do cap tulo . . . . . . . . . . . . . . . . . 14.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . .
9 295 . 295 . 295 . 297 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 297 298 298 299 299 300 301 302 302 304 305 305 306 306 306 308 308 308 308 308 310 312 313 314 315 315 316 317 318 319 323 325 326 327 328 329 329 330 331 332 334 335
. . . . . . . . . . . . . . . . . . a sele ca o . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . do . . . . . . . .
. . . . . . . . . . . . . . . . . . m etodo a . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . ser . . . . . . . .
15 Ponteiros, Refer encias e Gerenciamento de Mem oria 15.1 Prot otipo para declarar e denir ponteiros e refer encias . . . . . . . . . . . . . 15.2 Ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3 Cria ca o e uso de objetos din amicos com ponteiros . . . . . . . . . . . . . . . . . 15.3.1 O operador new . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3.2 O operador delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.4 Ponteiro this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.5 Ponteiros const e ponteiros para const . . . . . . . . . . . . . . . . . . . . . . 15.5.1 Ponteiro para um objeto constante . . . . . . . . . . . . . . . . . . . . . 15.5.2 Ponteiro constante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.5.3 Ponteiro constante para um objeto constante . . . . . . . . . . . . . . . 15.6 Refer encias (&) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.6.1 Diferen cas entre refer encia e ponteiro . . . . . . . . . . . . . . . . . . . . 15.6.2 Refer encias para ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . 15.7 Conceitos b asicos de gerenciamento de mem oria2 . . . . . . . . . . . . . . . . . 15.7.1 Entendendo o uso de new/delete com vetores . . . . . . . . . . . . . . 15.7.2 Alinhamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.7.3 D uvidas freq uentes no uso de new, delete e gerenciamento de mem oria2 15.8 Senten cas para ponteiros, refer encias e gerenciamento de mem oria . . . . . . . 15.9 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.10Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 M etodos Construtores e Destrutores 16.1 Introdu ca o aos m etodos construtores e destrutores . 16.2 Prot otipo para construtores e destrutores . . . . . . 16.3 Construtor default T() . . . . . . . . . . . . . . . . . 16.4 Inicializa ca o dos atributos da classe nos contrutores 16.5 Construtor de c opia T(const T& obj) . . . . . . . . 16.5.1 Construtor de c opia e objetos din amicos . . . 16.6 Quando o objeto e constru do/destru do . . . . . . . 16.6.1 Ordem de constru ca o dos atributos . . . . . . 16.6.2 Ordem de destrui ca o dos atributos . . . . . . 16.6.3 Constru ca o de objetos globais est aticos . . . 16.7 Construtor e ambig uidade . . . . . . . . . . . . . . . 16.8 Construtor e destrutor conceitos avan cados2 . . . . 16.8.1 Construtor e ambig uidade . . . . . . . . . . . 16.8.2 Construtor e interface . . . . . . . . . . . . . 16.9 Senten cas para construtores e destrutores . . . . . . 16.10Resumo do cap tulo . . . . . . . . . . . . . . . . . . 16.11Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10 17 Heran ca 17.1 Prot otipo para heran ca simples . . . . . . . . . . . . . . 17.2 Como implementar a heran ca simples . . . . . . . . . . 17.3 Especicador de heran ca . . . . . . . . . . . . . . . . . . 17.4 Diferen ca entre heran ca p ublica e privada . . . . . . . . 17.5 Mudando a visibilidade em heran cas com using . . . . . 17.6 Chamando construtores da classe-base explicitamente . 17.7 Redeclara ca o de m etodo ou atributo na classe-derivada . 17.8 Senten cas para heran ca . . . . . . . . . . . . . . . . . . 17.9 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . 17.10Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO 337 337 338 339 341 341 342 342 344 345 346 347 347 347 349 349 351 352 353 355 357 359 361 361 363 363 365 366 367 369 369 369 370 378 379
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
18 Heran ca M ultipla 18.1 Prot otipo para heran ca m ultipla . . . . . . . . . . . . . . . . . 18.2 Como implementar a heran ca m ultipla . . . . . . . . . . . . . . 18.3 Resolvendo ambig uidade em heran ca m ultipla com using . . . 18.4 Heran ca m ultipla com base comum . . . . . . . . . . . . . . . . 18.5 Ordem de cria ca o e destrui ca o dos objetos em heran cas . . . . 18.6 Heran ca m ultipla virtual . . . . . . . . . . . . . . . . . . . . . 18.7 Ordem de cria ca o e destrui ca o dos objetos em heran ca m ultipla 18.8 Senten cas para heran ca m ultipla . . . . . . . . . . . . . . . . . 18.9 Exemplo de heran ca simples e heran ca m ultipla . . . . . . . . . 18.10An alise dos erros emitidos pelo compilador2 . . . . . . . . . . . 18.11Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . 18.12Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Polimorsmo 19.1 M etodos n ao virtuais . . . . . . . . . . . 19.2 M etodos virtuais . . . . . . . . . . . . . 19.2.1 Senten cas para m etodos virtuais 19.3 Como implementar o polimorsmo . . . 19.3.1 Senten cas para polimorsmo . . 19.4 M etodos virtuais puros . . . . . . . . . 19.5 M etodos virtuais sobrecarregados . . . . 19.6 Exemplo completo com polimorsmo . . 19.7 Resumo do cap tulo . . . . . . . . . . . 19.8 Exerc cios . . . . . . . . . . . . . . . . . 20 Friend 20.1 Introdu ca o ao conceito de friend . 20.2 Prot otipo para friend . . . . . . . 20.3 Classes friend . . . . . . . . . . . 20.4 M etodos friend . . . . . . . . . . 20.5 Fun co es globais friend . . . . . . 20.6 Senten cas para friend . . . . . . . 20.7 Resumo do cap tulo . . . . . . . . 20.8 Exerc cios . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . virtual . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
SUMARIO 21 Sobrecarga de Operador 21.1 Introdu ca o ` a sobrecarga de operador . . . . . . . . . . . 21.2 Operadores que podem ser sobrecarregados . . . . . . . 21.3 Prot otipo para sobrecarga de operador . . . . . . . . . . 21.4 Sobrecarga de operador como fun ca o friend . . . . . . 21.5 Sobrecarga de operador como m etodo membro da classe 21.6 Exemplo pr atico de sobrecarga de operador . . . . . . . 21.7 Como sobrecarregar ++ e -- . . . . . . . . . . . . . . . . 21.8 Como sobrecarregar new2 . . . . . . . . . . . . . . . . . 21.8.1 Como sobrecarregar new dentro de uma classe2 . 21.9 Senten cas para sobrecarga de operador . . . . . . . . . . 21.10Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . 21.11Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Entrada e Sa da 22.1 Introdu ca o ` a entrada e sa da de dados com C++ 22.1.1 Streams buferizadas . . . . . . . . . . . . 22.2 Biblioteca de entrada e sa da . . . . . . . . . . . 22.3 A classe ios_base . . . . . . . . . . . . . . . . . 22.4 A classe <iomanip> . . . . . . . . . . . . . . . . . 22.5 A classe <ostream> . . . . . . . . . . . . . . . . . 22.5.1 Senten cas para <ostream> . . . . . . . . . 22.6 A classe <ios> . . . . . . . . . . . . . . . . . . . 22.6.1 Senten cas para <ios> . . . . . . . . . . . 22.7 A classe <istream> . . . . . . . . . . . . . . . . . 22.7.1 Senten cas para <istream> . . . . . . . . . 22.8 A classe <sstream> . . . . . . . . . . . . . . . . . 22.9 Entrada e sa da uso avan cado . . . . . . . . . . 22.9.1 Como criar e usar um manipulador . . . . 22.9.2 A classe locale2 . . . . . . . . . . . . . . 22.9.3 Usando facets 2 . . . . . . . . . . . . . . . 22.10Senten cas para stream . . . . . . . . . . . . . . . 22.11Resumo do cap tulo . . . . . . . . . . . . . . . . 22.12Exerc cios . . . . . . . . . . . . . . . . . . . . . .
11 387 387 388 388 389 390 391 396 396 397 398 400 401 403 403 404 404 405 411 414 415 415 416 417 421 422 423 423 424 427 428 428 429
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
23 Entrada e Sa da com Arquivos de Disco 23.1 Introdu ca o ao acesso a disco . . . . . . . . . . . . . . . . . . . . 23.2 A classe <fstream> . . . . . . . . . . . . . . . . . . . . . . . . . 23.3 Armazenando e lendo objetos . . . . . . . . . . . . . . . . . . . 23.4 Redirecionamento de entrada e sa da . . . . . . . . . . . . . . . 23.5 Entrada e Sa da com Arquivos de Disco - Uso Avan cado . . . 23.5.1 Posicionando ponteiros de arquivos2 . . . . . . . . . . . 23.5.2 Acessando a impressora e a sa da auxiliar2 . . . . . . . . 23.5.3 Arquivos de disco bin arios2 . . . . . . . . . . . . . . . . 23.5.4 Executando e enviando comandos para outro programa2 23.6 Senten cas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23.7 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . 23.8 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
431 . 431 . 431 . 436 . 439 . 441 . 441 . 443 . 444 . 444 . 446 . 446 . 447
12 24 A Classe <string> 24.1 Introdu ca o ` as strings . . . . . . . . . . . . . 24.2 M etodos de <string> . . . . . . . . . . . . . 24.2.1 Construtores e destrutor . . . . . . . . 24.2.2 Iteradores . . . . . . . . . . . . . . . . 24.2.3 Manipula ca o do tamanho da string . 24.2.4 Operadores de acesso . . . . . . . . . 24.2.5 Atribui ca o e concatena ca o . . . . . . . 24.2.6 Inser ca o, remo ca o, substitui ca o, c opia 24.2.7 Compara ca o . . . . . . . . . . . . . . 24.2.8 Substrings . . . . . . . . . . . . . . . . 24.2.9 Pesquisa . . . . . . . . . . . . . . . . . 24.3 Exemplos de uso de <string> . . . . . . . . . 24.4 Senten cas para strings de C++ . . . . . . . . 24.5 Resumo do cap tulo . . . . . . . . . . . . . . 24.6 Exerc cios . . . . . . . . . . . . . . . . . . . .
SUMARIO 449 449 450 450 451 451 452 452 453 453 454 454 455 459 460 460 461 461 462 463 464 465 466 466 468 468 468 469 470 470 473 473 474 475 476 476 477 478 478 479 479 479 482 483 483 484 486 486
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25 Convers oes 25.1 Prot otipo para convers oes . . . . . . . . . . . . . . . 25.2 Necessidade de convers ao . . . . . . . . . . . . . . . 25.3 Construtor de convers ao . . . . . . . . . . . . . . . . 25.4 Operador de convers ao - cast . . . . . . . . . . . . . 25.5 Convers ao explicita nos construtores com explicit . 25.6 Convers ao est atica com static_cast<> . . . . . . . 25.7 Convers ao din amica com dynamic_cast<> . . . . . . 25.7.1 dynamic_cast<> e refer encias . . . . . . . . . 25.8 Convers ao com const_cast<> . . . . . . . . . . . . . 25.9 Convers ao com reinterpret_cast<> . . . . . . . . 25.10Senten cas para convers oes . . . . . . . . . . . . . . . 25.11Resumo do cap tulo . . . . . . . . . . . . . . . . . . 25.12Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . 26 Exce co es 26.1 Introdu ca o ` as exce co es . . . . . . . . . . . . . . . . . 26.2 Prot otipo para exce co es . . . . . . . . . . . . . . . . 26.3 Conceitos b asicos de exce co es . . . . . . . . . . . . . 26.3.1 try . . . . . . . . . . . . . . . . . . . . . . . 26.3.2 throw . . . . . . . . . . . . . . . . . . . . . . 26.3.3 catch . . . . . . . . . . . . . . . . . . . . . . 26.4 Exce co es-padr ao . . . . . . . . . . . . . . . . . . . . 26.5 Seq uencia de execu ca o . . . . . . . . . . . . . . . . . 26.5.1 Seq uencia de execu ca o sem exce ca o . . . . . . 26.5.2 Seq uencia de execu ca o com exce ca o . . . . . 26.6 Como ca a pilha (heap ) . . . . . . . . . . . . . . . . 26.7 Exce co es n ao tratadas . . . . . . . . . . . . . . . . . 26.8 Exce co es - Uso avan cado . . . . . . . . . . . . . . . . 26.8.1 Exce ca o para new2 . . . . . . . . . . . . . . . 26.8.2 Controlando entrada com exce co es2 . . . . . 26.8.3 Adotando uma pol tica para uso de exce co es2 26.9 Senten cas para exce co es . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++
SUMARIO
13
26.10Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 26.11Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 27 Templates ou Gabaritos 27.1 Introdu ca o aos templates (gabaritos) . . . . . . . . . . . . . . . . 27.2 Fun co es templates . . . . . . . . . . . . . . . . . . . . . . . . . . 27.2.1 Prot otipo para fun co es templates . . . . . . . . . . . . . . 27.2.2 Inst ancias de fun co es template e dedu ca o de argumentos 27.2.3 Declara ca o expl cita de fun ca o template . . . . . . . . . . 27.2.4 Resolvendo problemas de convers oes . . . . . . . . . . . . 27.2.5 Sobrecarga de fun ca o template . . . . . . . . . . . . . . . 27.2.6 Fun ca o template com objeto est atico . . . . . . . . . . . 27.3 Classes templates ou tipos param etricos . . . . . . . . . . . . . . 27.3.1 Prot otipo para classes template . . . . . . . . . . . . . . 27.3.2 Regras gerais para classes template . . . . . . . . . . . . . 27.3.3 Argumentos pr e-denidos em classes templates . . . . . . 27.4 Senten cas para templates . . . . . . . . . . . . . . . . . . . . . . 27.5 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . 27.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Templates - Uso Avan cado 28.1 Fun co es template uso avan cado . . . . . . . . . . . . . . . . 28.1.1 Especializa ca o de fun co es template . . . . . . . . . . 28.1.2 Fun co es expandidas em tempo de compila ca o . . . . . 28.1.3 Usando typename com templates . . . . . . . . . . . . 28.1.4 Mapeando fun co es template utilizando especializa co es 28.1.5 Fun co es template e friend . . . . . . . . . . . . . . . 28.2 Classes template uso avan cado . . . . . . . . . . . . . . . . . 28.2.1 Templates dentro de uma classe template . . . . . . . 28.2.2 Especializa ca o de classes templates . . . . . . . . . . . 28.2.3 Instanciando fun co es e classes template2 . . . . . . . . 28.3 Uso de export com templates3 . . . . . . . . . . . . . . . . . 28.4 Senten cas para uso avan cado de templates . . . . . . . . . . . 28.5 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . 28.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Implementando Associa co es em C++ 29.1 Introdu ca o ` as associa co es em C++ . . 29.2 Associa ca o sem atributo . . . . . . . . 29.3 Associa ca o com atributo . . . . . . . . 29.4 Resumo do cap tulo . . . . . . . . . . 29.5 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 492 492 492 493 494 495 495 496 496 496 497 500 503 505 505 507 507 507 509 510 511 513 513 513 517 518 520 520 522 522 523 523 523 524 525 525 527 527 527 529 530 530 532
30 As Classes <complex>, <bitset> e as Fun co es Matem aticas de <cmath> 30.1 Introdu ca o ` a biblioteca <cmath> de C . . . . . . . . . . . . . . . . . . . . 30.1.1 Fun coes de <cmath> . . . . . . . . . . . . . . . . . . . . . . . . . . 30.1.2 Exemplos de uso de <cmath> . . . . . . . . . . . . . . . . . . . . . 30.2 Introdu ca o ` a classe <complex> . . . . . . . . . . . . . . . . . . . . . . . . 30.2.1 M etodos de <complex> . . . . . . . . . . . . . . . . . . . . . . . . 30.2.2 Exemplo de uso de <complex> . . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++
14 30.2.3 Resumo da classe <complex> fornecida pela biblioteca padr ao 30.3 Introdu ca o ` a classe <bitset> . . . . . . . . . . . . . . . . . . . . . . 30.3.1 M etodos de <bitset> . . . . . . . . . . . . . . . . . . . . . 30.3.2 Exemplos de uso da classe <bitset> . . . . . . . . . . . . . 30.3.3 Exemplo de uso de <bitset> com <vector>2 . . . . . . . . . 30.4 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . . . 30.5 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
III
Introdu c ao a STL
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
541
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 543 544 544 545 545 546 547 547 547 548 549 549 550 552 552 554 555 555 555 557 557 558 559 560 561 561 561 562 562 564 565 565 566 566 566 567 568
31 Introdu c ao a Biblioteca Padr ao de Gabaritos de C++ - STL 31.1 O que e a STL? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.1.1 Caracter sticas da STL . . . . . . . . . . . . . . . . . . . . 31.1.2 Componentes da STL . . . . . . . . . . . . . . . . . . . . 31.2 Introdu ca o aos containers . . . . . . . . . . . . . . . . . . . . . . 31.2.1 Containers seq uencias . . . . . . . . . . . . . . . . . . . . 31.2.2 Containers associativos . . . . . . . . . . . . . . . . . . . 31.2.3 Containers adaptativos . . . . . . . . . . . . . . . . . . . 31.2.4 M etodos e operadores comuns aos diversos containers . . 31.2.5 M etodos v alidos apenas para os containers seq uenciais . 31.2.6 Typedefs comuns aos diversos containers2 . . . . . . . . 31.3 Introdu ca o aos iteradores - iterators . . . . . . . . . . . . . . . 31.3.1 Tipos de iteradores . . . . . . . . . . . . . . . . . . . . . . 31.3.2 Opera co es comuns com iteradores2 . . . . . . . . . . . . . 31.4 Iteradores - Uso avan cado2 . . . . . . . . . . . . . . . . . . . . . 31.4.1 Iteradores de inser ca o . . . . . . . . . . . . . . . . . . . . 31.5 Senten cas para STL e iteradores . . . . . . . . . . . . . . . . . . 31.6 Fun ca o predicado . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.7 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . 31.8 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Os Containers Sequ enciais <vector>, <list>, <deque> 32.1 A classe container <vector> . . . . . . . . . . . . . . . 32.1.1 Construtores e destrutor . . . . . . . . . . . . . 32.1.2 Iteradores de <vector> . . . . . . . . . . . . . 32.1.3 Refer encias e acesso . . . . . . . . . . . . . . . 32.1.4 Operadores . . . . . . . . . . . . . . . . . . . . 32.1.5 Capacidade e redimensionamento . . . . . . . . 32.1.6 Inser ca o, dele ca o e atribui ca o . . . . . . . . . . 32.1.7 Operadores sobrecarregados . . . . . . . . . . . 32.1.8 Exemplo de <vector> . . . . . . . . . . . . . . 32.1.9 Senten cas para <vector> . . . . . . . . . . . . 32.2 A classe container <list> . . . . . . . . . . . . . . . . 32.2.1 Construtores e destrutor . . . . . . . . . . . . . 32.2.2 Operadores . . . . . . . . . . . . . . . . . . . . 32.2.3 Refer encia e acesso . . . . . . . . . . . . . . . . 32.2.4 Inser ca o, mistura e ordena ca o . . . . . . . . . . 32.2.5 Remo ca o e c opia u nica . . . . . . . . . . . . . . 32.2.6 Exemplo de <list> . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO 32.2.7 Senten cas para <list> . 32.3 A classe container <deque> . . 32.3.1 Construtores e destrutor 32.3.2 Exemplo de <deque> . . 32.4 Resumo do cap tulo . . . . . . 32.5 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15 571 571 572 572 573 574 577 577 578 578 579 580 581 581 582 582 583 583 585 585 585 586 586 586 587 587 587 588 589 589 589 590 590 590 590 591 593 594 594 594 597 598 598 598 598 599 600
33 Os Containers Adaptativos <stack>, <queue> e <priority_queue> 33.1 A classe container <stack> . . . . . . . . . . . . . . . . . . . . . . 33.1.1 M etodos de <stack> . . . . . . . . . . . . . . . . . . . . . . 33.1.2 A listagem da classe <stack> . . . . . . . . . . . . . . . . . 33.1.3 Exemplo de <stack> . . . . . . . . . . . . . . . . . . . . . . 33.2 A classe container <queue> . . . . . . . . . . . . . . . . . . . . . . 33.2.1 M etodos de <queue> . . . . . . . . . . . . . . . . . . . . . . 33.2.2 A listagem da classe <queue> . . . . . . . . . . . . . . . . . 33.2.3 Exemplo de <queue> . . . . . . . . . . . . . . . . . . . . . . 33.3 A classe container <priority_queue> . . . . . . . . . . . . . . . . 33.4 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . . 33.5 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Os Containers Associativos <set>, 34.1 A classe <pair> . . . . . . . . . . 34.2 A classe container <set> . . . . . 34.2.1 Contrutores e destrutor . 34.2.2 Trocas . . . . . . . . . . . 34.2.3 Inser ca o e dele ca o . . . . 34.2.4 Pesquisa e contagem . . . 34.2.5 Operadores . . . . . . . . 34.2.6 Exemplo de <set> . . . . 34.3 A classe container <multiset> . 34.3.1 Contrutores e destrutor . 34.3.2 Operadores . . . . . . . . 34.4 A classe container <map> . . . . . 34.4.1 Construtores e destrutor . 34.4.2 Operadores . . . . . . . . 34.4.3 Inser ca o e dele ca o . . . . 34.4.4 Pesquisa e contagem . . . 34.4.5 Exemplo de <map> . . . . 34.4.6 Senten cas para <map> . . 34.5 A classe container <multimap> . 34.6 Resumo do cap tulo . . . . . . . 34.7 Exerc cios . . . . . . . . . . . . .
35 Programa c ao Gen erica 35.1 Introdu ca o ` a programa ca o gen erica . . . . . . . . . . . 35.2 Classica ca o das fun co es gen ericas . . . . . . . . . . . 35.2.1 Classica ca o quanto ` a modica ca o do container 35.2.2 Classica ca o quanto ` a categoria dos iteradores 35.2.3 Classica ca o quanto ` as opera co es realizadas . . 35.3 Fun co es gen ericas . . . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++
16 35.3.1 Preenchimento . . . . . . . . . . . . . 35.3.2 Compara ca o . . . . . . . . . . . . . . 35.3.3 Remo ca o . . . . . . . . . . . . . . . . 35.3.4 Troca . . . . . . . . . . . . . . . . . . 35.3.5 Misturar/Mesclar/Inverter . . . . . . . 35.3.6 Pesquisa . . . . . . . . . . . . . . . . . 35.3.7 Ordena ca o . . . . . . . . . . . . . . . 35.3.8 Classica ca o . . . . . . . . . . . . . . 35.3.9 Transforma ca o . . . . . . . . . . . . . 35.3.10 Matem aticos . . . . . . . . . . . . . . 35.3.11 Opera co es matem aticas com conjuntos 35.3.12 Ordena ca o de pilhas - heapsort . . . . Exemplos de uso das fun co es gen ericas . . . . Senten cas para c odigo gen erico . . . . . . . . Resumo do cap tulo . . . . . . . . . . . . . . Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600 600 601 601 602 602 603 604 604 605 606 606 607 612 612 613 615 615 615 616 616 616 617 618 629 629 629 629 630 630 631
36 Objetos Fun co es da STL 36.1 Introdu ca o aos objetos fun co es da STL . . . . . . . . . . . . . . . . . . . 36.1.1 Fun co es un arias . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.1.2 Fun co es bin arias . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.2 Objetos fun co es fornecidos pela STL . . . . . . . . . . . . . . . . . . . . 36.2.1 Fun co es aritm eticas . . . . . . . . . . . . . . . . . . . . . . . . . 36.2.2 Fun co es de compara ca o . . . . . . . . . . . . . . . . . . . . . . . 36.2.3 Fun co es l ogicas . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.3 STL - Uso Avan cado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.3.1 O adaptador bin2nd() . . . . . . . . . . . . . . . . . . . . . . . . 36.3.2 Os adaptadores not1(),not2() . . . . . . . . . . . . . . . . . . . 36.3.3 Os adaptadores - men_fun(), men_fun_ptr() e men_fun_ref() . 36.3.4 Extendendo a STL - especializa ca o para std::swap . . . . . . . 36.4 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.5 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
IV
Ap endices
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
637
. . . . . . . . . . . . . 639 639 639 640 640 640 641 641 641 642 642 643 643 643
A Diretrizes de Pr e-Processador A.1 Fase de pr e-processamento . . . . . . . . . A.2 Inclus ao de arquivos . . . . . . . . . . . . A.3 Compila ca o condicional . . . . . . . . . . A.3.1 #define . . . . . . . . . . . . . . . A.3.2 #ifdef . . . . . . . . . . . . . . . A.3.3 #ifndef . . . . . . . . . . . . . . . A.3.4 #undef . . . . . . . . . . . . . . . A.3.5 #if . . . . . . . . . . . . . . . . . A.3.6 #ifdef...else . . . . . . . . . . . A.3.7 #if...else . . . . . . . . . . . . . A.3.8 #if...#elif...#elif...#endif . A.4 Macros . . . . . . . . . . . . . . . . . . . . A.4.1 Macros pr e-denidas . . . . . . . .
SUMARIO A.5 A.6 A.7 A.8 Instru co es de guarda . . Senten cas para diretrizes Resumo do cap tulo . . Exerc cios . . . . . . . . . . . . . . . . . . . de pr e-processador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17 644 645 645 645 647 647 648 649 652 653 654 655 655 657 658 658 659 659 659 660 661 662 662 663 663 664 664 664 664 664 664 665 665 665 667 667 668 668 668 669 669 671 671 671 672 673 673
B Conceitos Uteis Para Programa c ao em C B.1 Especicador de classe de armazenamento - tempo de vida . B.2 Especicador de linkagem . . . . . . . . . . . . . . . . . . . B.2.1 Uso de extern . . . . . . . . . . . . . . . . . . . . . B.3 Modicadores de acesso . . . . . . . . . . . . . . . . . . . . B.4 Escopo das vari aveis . . . . . . . . . . . . . . . . . . . . . . B.5 Senten cas . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.6 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . . . B.7 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . C Operadores C.1 Introdu ca o aos operadores . . . . . . . . . . . . . . . . . C.1.1 Operadores aritm eticos (+,-,*,/,%) . . . . . . . C.1.2 Operadores de atribui ca o (=) . . . . . . . . . . . C.1.3 Operadores compostos (+=, -=, *=, /=) . . . . C.1.4 Operadores relacionais (>, >=, <, <=, ==, !=) C.1.5 Operadores l ogicos (&&, ||, !, ==, !=) . . . . C.1.6 Operadores de bits (&, |) . . . . . . . . . . . . . C.1.7 Operador condicional (?) . . . . . . . . . . . . . C.1.8 Operador incremento (++) e decremento (--) . . C.1.9 Operador v rgula (a,b) . . . . . . . . . . . . . . C.1.10 Operador m odulo (%) . . . . . . . . . . . . . . . C.1.11 Operador new . . . . . . . . . . . . . . . . . . . . C.1.12 Operador delete . . . . . . . . . . . . . . . . . . C.1.13 Operador typedef . . . . . . . . . . . . . . . . . C.1.14 Operador sizeof . . . . . . . . . . . . . . . . . C.1.15 Operador size_t . . . . . . . . . . . . . . . . . . C.1.16 Operador de resolu ca o de escopo (::) . . . . . . C.2 Senten cas para operadores . . . . . . . . . . . . . . . . . C.3 Resumo do cap tulo . . . . . . . . . . . . . . . . . . . . C.4 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
D Estruturas de Controle D.1 Introdu ca o ` as estruturas de controle . . . . . . . . . . . . . . . . . . . . D.2 Estruturas condicionais . . . . . . . . . . . . . . . . . . . . . . . . . . . D.2.1 if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D.2.2 if.....else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D.2.3 if......else if......else if......else . . . . . . . . . . . D.2.4 switch....case . . . . . . . . . . . . . . . . . . . . . . . . . . . D.2.5 express~ ao_condicional? a c~ ao_verdadeira : a c~ ao_falsa; D.3 Estruturas de repeti ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . D.3.1 for ( in cializa c~ ao ; condi c~ ao ; a c~ ao2 ) a c~ ao1; . . . . . D.3.2 while (condi c~ ao) {a c~ ao;}; . . . . . . . . . . . . . . . . . . . . D.3.3 do {a c~ ao} while (condi c~ ao); . . . . . . . . . . . . . . . . . . D.3.4 break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++
18 D.3.5 continue . . . . . . . . . . . . D.4 Senten cas para estruturas de controle . D.5 Resumo do cap tulo . . . . . . . . . . D.6 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674 675 675 676 677 677 678 679 680 681 682 682 685 685 686 687 688 688 691 692 693 694 695 695 697 697 697 698 699 699 700 700 701 701 704 705 705 707 707 707 708 708 713 713 715 Andr e Duarte Bueno
E Fun co es - Uso Avan cado E.1 A fun ca o main() e a entrada na linha de comando E.2 Processando par ametros de main() com getopt() E.3 Fun co es recursivas . . . . . . . . . . . . . . . . . . E.4 Uso de elipse ... em fun co es . . . . . . . . . . . . E.5 Senten cas para fun co es . . . . . . . . . . . . . . . . E.6 Resumo do cap tulo . . . . . . . . . . . . . . . . . E.7 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . F Ponteiros - Uso Avan cado F.1 Opera co es com ponteiros (+/-) . . F.2 Ponteiro void* . . . . . . . . . . . F.3 Ponteiro para ponteiro . . . . . . . F.4 Convers ao de ponteiros . . . . . . . F.5 Utilizando auto_ptr . . . . . . . . F.6 Ponteiro de fun ca o . . . . . . . . . F.7 Ponteiros para m etodos e atributos F.8 Ponteiros em hierarquias . . . . . . F.9 Senten cas para ponteiros . . . . . . F.10 Resumo do cap tulo . . . . . . . . F.11 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . da classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
G Estruturas, Uni oes, e Enumera co es G.1 Estruturas - struct . . . . . . . . . . . . . . . . . . G.1.1 Prot otipo para declarar e denir estruturas . G.1.2 Estruturas e fun co es . . . . . . . . . . . . . . G.1.3 Estruturas aninhadas . . . . . . . . . . . . . G.1.4 Senten cas para estruturas . . . . . . . . . . . G.2 Uni oes - union . . . . . . . . . . . . . . . . . . . . . G.2.1 Prot otipo para declarar e denir uni oes . . . G.3 Enumera co es - enum . . . . . . . . . . . . . . . . . . G.3.1 Prot otipo para declarar e denir enumera co es G.3.2 Senten cas para enumera co es . . . . . . . . . . G.4 Resumo do cap tulo . . . . . . . . . . . . . . . . . . G.5 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . H Vetores e Matrizes - Arrays H.1 Introdu ca o aos vetores e matrizes de C . . H.2 Como criar e usar vetores unidimensionais H.3 Como criar e usar matrizes bidimensionais H.4 Exemplo de uso de vetores e matrizes . . H.5 Resumo do cap tulo . . . . . . . . . . . . H.6 Exerc cios . . . . . . . . . . . . . . . . . . I Gloss ario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SUMARIO J Links Para Sites em C++ J.1 Bookmark . . . . . . . . . . . . . . . . . . . . . . . J.2 HOWTO - Como fazer . . . . . . . . . . . . . . . . J.3 Sites UML . . . . . . . . . . . . . . . . . . . . . . J.4 Sites C++ . . . . . . . . . . . . . . . . . . . . . . J.4.1 Ambientes de desenvolvimento . . . . . . . J.4.2 Compiladores . . . . . . . . . . . . . . . . . J.4.3 Exemplos . . . . . . . . . . . . . . . . . . . J.4.4 Tutoriais . . . . . . . . . . . . . . . . . . . J.4.5 FAQ . . . . . . . . . . . . . . . . . . . . . . J.4.6 Usu arios avan cados de C++ . . . . . . . . J.5 Sites STL - Standart Template Library . . . . . . . J.6 Sites Programa ca o multiplataforma (GNU/Linux) J.6.1 Software Livre . . . . . . . . . . . . . . . . J.6.2 Portabilidade . . . . . . . . . . . . . . . . . J.6.3 Software multiplataforma . . . . . . . . . . J.6.4 Auditoria e proler . . . . . . . . . . . . . . J.6.5 CVS . . . . . . . . . . . . . . . . . . . . . . J.6.6 Documenta ca o . . . . . . . . . . . . . . . . J.7 Sites Cluster e Programa ca o Paralela . . . . . . . J.8 Sites Bibliotecas . . . . . . . . . . . . . . . . . . . J.8.1 Bibliotecas e ferramentas . . . . . . . . . . J.8.2 Programa ca o cient ca . . . . . . . . . . . . J.9 Sites Grupos . . . . . . . . . . . . . . . . . . . . . J.10 Sites Revistas . . . . . . . . . . . . . . . . . . . . . J.11 Livros de C++ . . . . . . . . . . . . . . . . . . . . J.12 Fedora . . . . . . . . . . . . . . . . . . . . . . . . . K Arquivos de Cabe calho K.1 Introdu ca o aos arquivos de cabe calho . . . . . K.2 Entrada e sa da (streams) . . . . . . . . . . . K.3 Strings de C++ . . . . . . . . . . . . . . . . . K.4 STL . . . . . . . . . . . . . . . . . . . . . . . K.4.1 Containers da STL . . . . . . . . . . . K.4.2 Objetos fun co es e algoritmos gen ericos K.4.3 Matem aticos, num ericos . . . . . . . . K.5 Tratamento de erro, exce co es . . . . . . . . . K.6 Utilit arios . . . . . . . . . . . . . . . . . . . . K.7 Bibliotecas de C . . . . . . . . . . . . . . . . K.7.1 <cstdlib> . . . . . . . . . . . . . . . K.7.2 <cstdio> . . . . . . . . . . . . . . . . K.7.3 <ctime> . . . . . . . . . . . . . . . . K.7.4 <cstring> . . . . . . . . . . . . . . . K.7.5 Diversos . . . . . . . . . . . . . . . . K.8 Unix, GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19 727 727 727 728 729 729 729 730 730 730 730 731 731 731 732 732 732 733 733 733 734 734 735 735 736 736 736 737 737 737 738 738 738 739 739 739 739 739 740 741 742 742 743 744
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
L Licen ca P ublica Geral GNU 745 L.1 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 L.2 Licen ca p ublica geral GNU condi co es para c opia, distribui ca o e modica ca o . . . 746 L.3 Como aplicar estes termos aos seus novos programas . . . . . . . . . . . . . . . . 750 Novatec - Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
20
SUMARIO
Lista de Figuras
1 1.1 1.2 1.3 3.1 3.2 3.3 3.4 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 5.1 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 6.10 6.11 6.12 6.13 6.14 6.15 6.16 Por onde come car? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Em (a) programa de reconstru ca o tridimensional, em (b) o programa Octave. . . 56 Programa com interface em modo texto e mecanismos de recupera ca o. . . . . . . 57 Programas com interface gr aca. . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 O processo de abstra ca o. . . O que voc e v e? . . . . . . . Um rel oogio e um cachorro. Uma hierarquia de rel ogios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 71 72 75 83 87 88 89 89 94 95 95 96
Modelos da realidade a planta de uma casa. . . . . . . . . . . . . . . . . . . . . Relacionamento dos diagramas estruturais da UML. . . . . . . . . . . . . . . . . Relacionamento dos diagramas din amicos da UML. . . . . . . . . . . . . . . . . . Elementos da UML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Outros elementos da UML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . O programa dia manipulando uma estrutura UML com representa co es de classes. A tela do programa Umbrello: Um diagrama de componentes. . . . . . . . . . . . A tela do programa umbrello um diagrama de classes. . . . . . . . . . . . . . . A tela do programa Visual-Paradigm um diagrama de caso de uso. . . . . . . .
Etapas de desenvolvimento de um software e os documentos gerados. . . . . . . . 107 Diagrama de caso de uso um caso de uso geral. . . . . . . . . . . . . Diagrama de caso de uso calcular area fun ca o. . . . . . . . . . . . . Diagrama de caso de uso: analisar resultados (uso de generaliza ca o). . Diagrama de caso de uso Analisar v arias fun co es (uso de inclus ao). . Diagrama de caso de uso entrada de dados errada (uso de extens ao). Elabora ca o e an alise de dom nio (adaptado de [Pressman, 2002]). . . . Interface gr aca e eventos. . . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de classes representando classes. . . . . . . . . . . . . . . . Diagrama de classes representando associa co es. . . . . . . . . . . . . Diagrama de classes representando classes de associa ca o. . . . . . . . Diagrama de classes representando agrega co es. . . . . . . . . . . . . Diagrama de classes representando heran cas. . . . . . . . . . . . . . Classe de interface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de objetos representando objetos e inst ancias. . . . . . . . Diagrama de seq u encia elementos. . . . . . . . . . . . . . . . . . . . Diagrama de seq u encia montando uma prova. . . . . . . . . . . . . . 21 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 112 113 113 114 116 118 122 124 126 127 128 129 131 135 136
22 6.17 6.18 6.19 6.20 6.21 6.22 6.23 6.24 6.25 6.26 6.27 6.28 6.29 6.30 6.31 6.32 6.33 7.1 8.1 8.2 9.1
LISTA DE FIGURAS Diagrama de seq u encia seq u encia para c alculo da area de uma fun ca o. . . . . Diagrama de comunica ca o montando uma prova. . . . . . . . . . . . . . . . . Diagrama de comunica ca o seq u encia para c alculo da area de uma fun ca o. . . Diagrama de m aquina de estado um aluno. . . . . . . . . . . . . . . . . . . . Diagrama de m aquina de estado estados do objeto simulador. . . . . . . . . . Diagrama de m aquina de estado: Estados compostos do objeto simulador. . . . Diagrama de m aquina de estado estados concorrentes do objeto simulador. . Em (a) o prot otipo de um diagrama de atividades. Em (b) o diagrama de atividades de um m etodo de binariza ca o. . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de atividades m etodo do Trap ezio para c alculo da area. . . . . . . Diagrama de atividades uso de raios de nata ca o. . . . . . . . . . . . . . . . . A tela do programa Dev C++. . . . . . . . . . . . . . . . . . . . . . . . . . . . A tela do programa kdevelop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . A tela do programa qt-designer. . . . . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de componentes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de implanta ca o. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Cart oes CRC: cClasse, responsabilidade, colabora ca o. . . . . . . . . . . . . . Exerc cio modelagem sistema aeroporto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 137 138 140 140 140 141 144 145 145 154 155 156 159 160 172 179
Seq u encia de montagem de um programa. . . . . . . . . . . . . . . . . . . . . . . 188 Diagrama mostrando entrada e sa da de dados em C++. . . . . . . . . . . . . . . 203 Compilando e executando programas no shell. . . . . . . . . . . . . . . . . . . . . 205 Tipos predenidos de C++ e suas dimens oes (32 bits). . . . . . . . . . . . . . . . 218
12.1 Como cam os objetos do tipo CTeste e CEndereco na mem oria. . . . . . . . . . 263 12.2 Como cam os objetos na mem oria quando a classe tem atributos est aticos. . . . 265 13.1 A classe CPessoa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 13.2 Como cam os m etodos inline. . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 13.3 A classe CPonto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 15.1 15.2 15.3 15.4 Ilustra ca o da cria ca o e uso de ponteiros. . . . . . . . Como declarar e usar um ponteiro. . . . . . . . . . . Consumo real de mem oria de um vetor de inteiros. . Desperd cio de mem oria em fun ca o do alinhamento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 301 309 310
16.1 Por que devemos criar um construtor de c opia. . . . . . . . . . . . . . . . . . . . 323 17.1 Heran ca simples: CPonto e CCirculo. . . . . . . . . . . . . . . . . . . . . . . . . 338 18.1 18.2 18.3 18.4 18.5 18.6 18.7 18.8 18.9 Heran ca m ultipla. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 Como cam os objetos b1, b2 e d em uma heran ca m ultipla. . . . . . . . . . . . . 348 Heran ca m ultipla com classe base comum. . . . . . . . . . . . . . . . . . . . . . . 350 Como cam os objetos b0, b1, b2 e d em uma heran ca m ultipla com base comum.351 Seq u encia de constru ca o e destrui ca o dos objetos em uma heran ca. . . . . . . . . 351 Heran ca m ultipla virtual. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 Como cam os objetos b0, b1, B2 e d em uma heran ca m ultipla com base virtual.353 Heran ca m ultipla normal e virtual. . . . . . . . . . . . . . . . . . . . . . . . . . 354 Hierarquia de classes CPonto, CCirculo, CElipse, CCirculoElipse. . . . . . . . . 357 Andr e Duarte Bueno
Lista de Figuras
23
19.1 Ilustra ca o do funcionamento da liga ca o din amica. . . . . . . . . . . . . . . . . . . 366 19.2 Hierarquia CPessoa, CAluno, CFuncionario, CAlunoFuncionario. . . . . . . . . 371 22.1 Diagrama UML da biblioteca de manipula ca o de entrada e sa da. . . . . . . . . . 406 23.1 Sa da gerada pelo programa gnuplot. . . . . . . . . . . . . . . . . . . . . . . . . . 445 26.1 Hierarquia de exce co es-padrao. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479 26.2 Seq u encia de execu ca o sem exce ca o (a) e com exce ca o (b). . . . . . . . . . . . . . 480 30.1 Pequena hierarquia de m etodos num ericos (solver e integral num erica de fun co es do tipo polin omios). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 31.1 31.2 31.3 31.4 32.1 32.2 32.3 32.4 Diagrama UML da biblioteca padr ao de C++. . . . . . . . . . . . Containers seq uenciais - <vector>, <list>, <deque>. . . . . . . . Containers associativos - <set>, <multiset>, <map>, <multimap>. Exemplos de m etodos presentes em alguns containers. . . . . . . . M etodos M etodos M etodos M etodos disponibilizados para <vector>. que retornam iteradores. . . . . . disponibilizados para <list>. . . disponibilizados para <deque>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544 545 546 549 558 560 566 572
33.1 M etodos disponibilizados para <stack>. . . . . . . . . . . . . . . . . . . . . . . . 577 33.2 A classe <stack> funciona como uma interface de acesso a <deque>, <list> ou <vector>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578 33.3 M etodos disponibilizados para <queue>. . . . . . . . . . . . . . . . . . . . . . . . 580 34.1 M etodos disponibilizados para <set>. . . . . . . . . . . . . . . . . . . . . . . . . 586 34.2 M etodos disponibilizados para <multiset>. . . . . . . . . . . . . . . . . . . . . . 588 34.3 M etodos disponibilizados para <map>. . . . . . . . . . . . . . . . . . . . . . . . . 589 H.1 As sa das do programa de binariza ca o. . . . . . . . . . . . . . . . . . . . . . . . . 714
24
Lista de Figuras
Lista de Tabelas
6.1 7.1 7.2 8.1 8.2 8.3 9.1 Exemplo de caso de uso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Diferen cas na nomenclatura da POO e de C++. . . . . . . . . . . . . . . . . . . 186 Extens oes usuais dos arquivos nas diferentes plataformas. . . . . . . . . . . . . . 188 Palavras chaves do ANSI C++. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 Conven ca o para nomes de objetos. . . . . . . . . . . . . . . . . . . . . . . . . . . 199 Exemplos de declara co es e deni co es. . . . . . . . . . . . . . . . . . . . . . . . . . 200 Tipos predenidos e intervalos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
17.1 Acesso herdado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340 19.1 M etodos com liga ca o est atica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 19.2 M etodos com liga ca o din amica . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 21.1 Operadores que podem ser sobrecarregados. . . . . . . . . . . . . . . . . . . . . . 388 22.1 22.2 22.3 22.4 Flags para o m etodo setf(). . . . . . . . . . . . . . Manipuladores da classe <iomanip>. . . . . . . . . . Caracteres de escape. . . . . . . . . . . . . . . . . . . Informa co es fornecidas pelo m etodo locale.name(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 412 414 425
23.1 Modos de abertura do m etodo open(). . . . . . . . . . . . . . . . . . . . . . . . . 432 23.2 Modos de prote ca o do m etodo open() (atributos de arquivo). . . . . . . . . . . . 432 23.3 Manipuladores seekdir para os m etodos seekp() e seekg(). . . . . . . . . . . . . 433 31.1 M etodos e operadores comuns a todos os containers. . . . . . . . . . . . . . . . . 548 31.2 Iteradores e m etodos dos containers sequenciais. . . . . . . . . . . . . . . . . . . 550 31.3 Typedefs comuns aos diversos containers. . . . . . . . . . . . . . . . . . . . . . . 551 C.1 Preced encia dos operadores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658
25
26
Lista de Programas
Listings
1 Exemplo de uma listagem (Listing). . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap00/List1ExemploDeListing.out . . . . . . . . . . . . . . . . . . . 7.1 Exemplo b asico: Arquivo de cabe calho da classe. . . . . . . . . . . . . . . . . . 7.2 Exemplo b asico: Arquivo de implementa ca o da classe. . . . . . . . . . . . . . . 7.3 Exemplo b asico: Arquivo de implementa ca o da fun ca o main(). . . . . . . . . . ../listagens/Cap07/Programa.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1 Usando sa da para tela, nova linha, tabula ca o e beep. . . . . . . . . . . . . . . . ../listagens/Cap08/novaLinhatabbeep.out . . . . . . . . . . . . . . . . . . . . . . 8.2 Declara ca o de objetos e uso de cin e cout. . . . . . . . . . . . . . . . . . . . . 8.3 Usando diretrizes de pr e-processador: #ifdef. . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/UsandoDiretrizesDePreProcessadorifdef.out . . . . . . . . . . 8.4 Usando for. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/UsandoFor.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.5 Usando for encadeado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/UsandoForFor.out . . . . . . . . . . . . . . . . . . . . . . . . . . 8.6 Usando while: Calculando a pot encia. . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/UsandoWhile.out . . . . . . . . . . . . . . . . . . . . . . . . . . 8.7 Usando os operadores de compara ca o, incremento, decremento, e os operadores compostos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/UsandoOperadoresDeComparacao.out . . . . . . . . . . . . . . . 8.8 Fun ca o cubo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/funcao.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.9 Fun ca o com void. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/funcaoretornovoid.out . . . . . . . . . . . . . . . . . . . . . . 8.10 Fun ca o em linha: volume esfera. . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/funcaoparametroconst.out . . . . . . . . . . . . . . . . . . . . 8.11 Exemplo de uso da biblioteca <cstdlib>. . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap08/funcaorandomico.out . . . . . . . . . . . . . . . . . . . . . . . . 9.1 Usando os tipos pr e-denidos de C++. . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap09/UsandoOsTiposPreDenidos.out . . . . . . . . . . . . . . . . . 9.2 Diferen cas no uso de inteiro com sinal (signed) e sem sinal (unsigned). . . . . ../listagens/Cap09/signedunsigned.out . . . . . . . . . . . . . . . . . . . . . . . . . 9.3 Vericando os limites dos tipos pr e-denidos de C++. . . . . . . . . . . . . . . ../listagens/Cap09/LimitesDosTiposPreDenidos32.out . . . . . . . . . . . . . . 9.4 Usando struct. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap09/Struct.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.5 Usando union. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap09/Union.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 45 190 191 192 192 202 203 204 206 206 207 207 207 207 208 208 209 210 210 211 211 211 212 212 212 213 218 219 220 221 222 222 226 227 228 228
28
Lista de Programas 9.6 Exemplo preliminar de deni ca o de classe do usu ario. . . . . . . . . . . . . . . . 229 ../listagens/Cap09/Complex.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 9.7 Exemplo preliminar de uso da classe <string> de C++. . . . . . . . . . . . . . . 232 ../listagens/Cap09/String.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 9.8 Exemplo preliminar de uso da classe <vector> da biblioteca STL. . . . . . . . . 234 ../listagens/Cap09/vector1.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 9.9 Usando sizeof(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 ../listagens/Cap09/sizeof.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 9.10 Usando typeid(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 ../listagens/Cap09/typeid.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 10.1 Denindo e usando um namespace. . . . . . . . . . . . . . . . . . . . . . . . . . . 245 ../listagens/Cap10/namespace.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 10.2 Usando using para colocar fun co es no mesmo escopo. . . . . . . . . . . . . . . . 246 ../listagens/Cap10/using.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 10.3 Usando vari aveis est aticas em um namespace. . . . . . . . . . . . . . . . . . . . . 248 ../listagens/Cap10/namespaceestatic.out . . . . . . . . . . . . . . . . . . . . . . . . 249 12.1 Usando atributos de objeto em uma classe. . . . . . . . . . . . . . . . . . . . . . 262 ../listagens/Cap12/UsandoAtributosDeObjeto.out . . . . . . . . . . . . . . . . . . . . 263 13.1 Passando par ametros por valor, refer encia e ponteiro. . . . . . . . . . . . . . . . . 276 ../listagens/Cap13/PassandoParametrosPorValorReferenciaPonteiro.out . . . . . . . 277 13.2 Classe com atributo e m etodo normal. . . . . . . . . . . . . . . . . . . . . . . . . 279 ../listagens/Cap13/classatributometodonormal.out . . . . . . . . . . . . . . . . . 280 13.3 Classe com m etodo const. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 ../listagens/Cap13/classatributometodoconst.out . . . . . . . . . . . . . . . . . . 283 13.4 Classe com atributo e m etodo est atico. . . . . . . . . . . . . . . . . . . . . . . . . 284 ../listagens/Cap13/classatributometodostatic.out . . . . . . . . . . . . . . . . . . 286 13.5 A classe CPonto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 13.6 Implementa ca o da classe CPonto. . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 13.7 Usando m etodos e atributos de uma classe. . . . . . . . . . . . . . . . . . . . . . 289 ../listagens/Cap13/ProgCPonto.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 15.1 Usando ponteiros para criar e usar objetos din amicos. . . . . . . . . . . . . . . . 303 ../listagens/Cap15/ProgCPontoDinamico.out . . . . . . . . . . . . . . . . . . . . . . 303 15.2 Usando refer encias. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 ../listagens/Cap15/referencia.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 15.3 Entendendo o alinhamento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 ../listagens/Cap15/sizeofealinhamento.out . . . . . . . . . . . . . . . . . . . . . . . 309 16.1 Usando construtor default e de c opia. . . . . . . . . . . . . . . . . . . . . . . . . 320 ../listagens/Cap16/classconstrutorcopia.out . . . . . . . . . . . . . . . . . . . . . . 322 16.2 Problemas com a falta do construtor de c opia em objetos com atributos din amicos.324 ../listagens/Cap16/ObjDinamico.out . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 16.3 Ordem de constru ca o dos atributos de um objeto. . . . . . . . . . . . . . . . . . . 327 ../listagens/Cap16/OrdemConstrucao.out . . . . . . . . . . . . . . . . . . . . . . . . 327 16.4 Objetos est aticos globais. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 ../listagens/Cap16/ObjEstatico.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 16.5 Erro ao denir o construtor default e um construtor sobrecarregado com inicializadores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 ../listagens/Cap16/construtorambiguidade.out . . . . . . . . . . . . . . . . . . . . . 329 16.6 Construindo objetos ou declarando fun co es? . . . . . . . . . . . . . . . . . . . . . 330 ../listagens/Cap16/DeclaracaoEConstrucaoAmbiguidade.out . . . . . . . . . . . . . 331
Lista de Programas 16.7 Construtor e interface: erro na passagem de par ametros. . . . . . . . 16.8 Construtor e interface: erro na passagem de par ametros corrigidos. . 17.1 A classe CCirculo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17.2 Implementa ca o da classe CCirculo. . . . . . . . . . . . . . . . . . . . 17.3 Usando especicador de acesso e de heran ca. . . . . . . . . . . . . . ../listagens/Cap17/especicadorheranca.out . . . . . . . . . . . . . . . . 17.4 Usando using em heran cas. . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap17/UsandoUsingEmHerancas.out . . . . . . . . . . . . . 17.5 Redeclara ca o de m etodo ou atributo na classe-derivada. . . . . . . . ../listagens/Cap17/herancaERedeclaracao.out . . . . . . . . . . . . . . . 18.1 Seq u encia de constru ca o e destrui ca o em heran ca m ultipla virtual. ../listagens/Cap18/herancaMultiplaVirtual.out . . . . . . . . . . . . . . 18.2 A classe CElipse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18.3 Implementa ca o da classe CElipse. . . . . . . . . . . . . . . . . . . . 18.4 Usando as classes CPonto, CCirculo e CElipse. . . . . . . . . . . . . ../listagens/Cap18/UsandoCPontoCCirculoCElipse.out . . . . . . . . . . 18.5 A classe CCirculoElipse. . . . . . . . . . . . . . . . . . . . . . . . . 18.6 Implementa ca o da classe CCirculoElipse. . . . . . . . . . . . . . . . ../listagens/Cap18/CCirculoElipse.out . . . . . . . . . . . . . . . . . . . 19.1 Exemplo de uso do polimorsmo. . . . . . . . . . . . . . . . . . . . . ../listagens/Cap19/Polimorsmo.out . . . . . . . . . . . . . . . . . . . . 19.2 A classe CPessoa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.3 Implementa ca o da classe CPessoa. . . . . . . . . . . . . . . . . . . . 19.4 A classe CAluno. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.5 Implementa ca o da classe CAluno. . . . . . . . . . . . . . . . . . . . . 19.6 A classe CFuncionario. . . . . . . . . . . . . . . . . . . . . . . . . . 19.7 Implementa ca o da classe CFuncionario. . . . . . . . . . . . . . . . . 19.8 A classe CAlunoFuncionario. . . . . . . . . . . . . . . . . . . . . . . 19.9 Implementa ca o da classe CAlunoFuncionario. . . . . . . . . . . . . 19.10Testando a heran ca m ultipla. . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap19/HerancaMultiplaa.out . . . . . . . . . . . . . . . . 20.1 Usando classes friend. . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap20/classesfriend.out . . . . . . . . . . . . . . . . . . . . 20.2 Usando m etodos friend. . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap20/metodofriend.out . . . . . . . . . . . . . . . . . . . . 20.3 Usando fun co es globais friend. . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap20/funcaoGlobalfriend.out . . . . . . . . . . . . . . . . 21.1 A classe CPonto com sobrecarga de operador. . . . . . . . . . . . . . 21.2 Implementa ca o da classe CPonto com sobrecarga de operador. . . . . 21.3 Usando a sobrecarga de operador. . . . . . . . . . . . . . . . . . . . . ../listagens/Cap21/TesteCPontoComSobrecarga.out . . . . . . . . . . . . 21.4 Sobrecarregando new em uma classe. . . . . . . . . . . . . . . . . . . ../listagens/Cap21/sobrecarregandonew.out . . . . . . . . . . . . . . . . 22.1 Formata ca o b asica da sa da de dados. . . . . . . . . . . . . . . . . . ../listagens/Cap22/FormatacaoBasicaDaSaidaDeDados.out . . . . . . . . 22.2 Formata ca o da sa da de dados usando o m etodo setf(). . . . . . . . ../listagens/Cap22/Usandosetf.out . . . . . . . . . . . . . . . . . . . . . 22.3 Formata ca o da sa da de dados usando a classe <iomanip>. . . . . . . ../listagens/Cap22/Usandoiomanip.out . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29 331 331 338 339 340 341 341 342 343 344 354 355 357 358 358 359 359 360 360 368 368 371 371 372 373 374 374 375 375 376 377 383 383 384 384 384 385 391 392 394 395 397 398 408 409 410 411 412 413
30
Lista de Programas 22.4 Contando n umero de linhas, palavras e caracteres. . . . . . . . . . . . . . . . . ../listagens/Cap22/ContandoNumeroLinhasPalavrasCaracteres.out . . . . . . . . . 22.5 Controle de entrada. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap22/controleEntrada.out . . . . . . . . . . . . . . . . . . . . . . . . . 22.6 Usando sstream (ostringstream e istringstream). . . . . . . . . . . . . . . . ../listagens/Cap22/Usandosstrean.out . . . . . . . . . . . . . . . . . . . . . . . . . 22.7 Usando a classe locale. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap22/UsandoLocale.out . . . . . . . . . . . . . . . . . . . . . . . . . . 22.8 Usando facets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap22/UsandoFacets.out . . . . . . . . . . . . . . . . . . . . . . . . . . 23.1 Uso de stream de disco (ifstream e ofstream). . . . . . . . . . . . . . . . . . ../listagens/Cap23/Usandofstream.out . . . . . . . . . . . . . . . . . . . . . . . . . 23.2 Lendo um arquivo com dados e coment arios. . . . . . . . . . . . . . . . . . . . ../listagens/Cap23/Usandofstreamcomcomentario.out . . . . . . . . . . . . . . . 23.3 Leitura e grava ca o de objetos simples usando read() e write(). . . . . . . . . ../listagens/Cap23/LeituraGravacaoDeObjetos.out . . . . . . . . . . . . . . . . . . 23.4 Usando redirecionamento de arquivo. . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap23/UsandoRedirecionamento.out . . . . . . . . . . . . . . . . . . . 23.5 Usando read(), write() e seekg(). . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap23/Usandoseekgseekp.out . . . . . . . . . . . . . . . . . . . . . . 23.6 Executando e enviando comandos para um outro programa (com <opstream>). ../listagens/Cap23/Usandopstream.out . . . . . . . . . . . . . . . . . . . . . . . . 24.1 Usando a classe <string> de C++. . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap24/Usandostring.out . . . . . . . . . . . . . . . . . . . . . . . . . . 24.2 Usando os m etodos de pesquisa da classe string de C++. . . . . . . . . . . . . ../listagens/Cap24/Usandostringpesquisa.out . . . . . . . . . . . . . . . . . . . . 24.3 Usando as classes <string> e sstream para executar comandos do shell. . . . . ../listagens/Cap24/interfaceShell.out . . . . . . . . . . . . . . . . . . . . . . . . . . 25.1 Mostrando a necessidade de convers oes. . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap25/necessidadeConversao.out . . . . . . . . . . . . . . . . . . . . . 25.2 Usando construtor com explicit. . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap25/Usandoexplicit.out . . . . . . . . . . . . . . . . . . . . . . . . . 25.3 Usando dynamic_cast e typeid. . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap25/Usandodynamiccast.out . . . . . . . . . . . . . . . . . . . . . 26.1 Exce co es: Divis ao por zero. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap26/DivisaoPorZero.out . . . . . . . . . . . . . . . . . . . . . . . . . 26.2 Exce co es: Divis ao por zero com controle simples. . . . . . . . . . . . . . . . . . ../listagens/Cap26/DivisaoPorZeroComControleSimples.out . . . . . . . . . . . . . 26.3 Exce co es: Divis ao por zero com exce co es. . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap26/DivisaoPorZeroComExcecoes.out . . . . . . . . . . . . . . . . . 26.4 Exce co es e desempilhamento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap26/ExcecoesDesempilhamento.out . . . . . . . . . . . . . . . . . . 26.5 Usando set_unexpected() e set_terminate(). . . . . . . . . . . . . . . . . . ../listagens/Cap26/TesteListaExcecoes.out . . . . . . . . . . . . . . . . . . . . . . . 26.6 Exce ca o para new. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap26/Excecoesnew.out . . . . . . . . . . . . . . . . . . . . . . . . . . 26.7 Usando exce co es para controle de entrada e sa da. . . . . . . . . . . . . . . . . ../listagens/Cap26/ExcecoesControleEntradaSaida.out . . . . . . . . . . . . . . . . 27.1 Deni ca o de classe template com argumentos pr e-denidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 420 420 421 423 423 425 426 427 427 434 435 435 436 437 438 440 441 442 443 445 446 455 457 457 458 458 459 462 463 465 465 467 468 473 473 474 474 475 476 481 481 482 483 483 484 484 485 500
Lista de Programas 27.2 Deni ca o dos m etodos da classe template com argumentos pr e-denidos. 27.3 Usando a classe template com argumentos pr e-denidos. . . . . . . . . . ../listagens/Cap27/UsandoClasseTemplateComArgumentosPreDenidos.out 28.1 Exemplo de fun ca o expandida em tempo de compila ca o. . . . . . . . . . . ../listagens/Cap28/FuncaoExpandidaEmTempoDeCompilacao.out . . . . . . . 28.2 Fun ca o pot encia expandida em tempo de compila ca o. . . . . . . . . . . . ../listagens/Cap28/FuncaoExpandidaEmTempoDeCompilacaopotencia.out . 28.3 Exemplo de mapeamento de tipo com templates. . . . . . . . . . . . . . . ../listagens/Cap28/MapeamentoDeTipo.out . . . . . . . . . . . . . . . . . . . 28.4 Problema na chamada a m etodos template. . . . . . . . . . . . . . . . . . ../listagens/Cap28/ProblemaNaChamadaAMetodosTemplate.out . . . . . . . ../listagens/Cap28/TemplatesComErro.out . . . . . . . . . . . . . . . . . . . . 28.5 Deni ca o de classe template com template adicional. . . . . . . . . . . . 28.6 Implementa ca o dos m etodos da classe template com template adicional. 28.7 Uso de classe template com template adicional. . . . . . . . . . . . . . . ../listagens/Cap28/UsandoTemplateComTemplateAdicional.out . . . . . . . 28.8 Exemplo: Instanciando fun co es e classes template. . . . . . . . . . . . . . ../listagens/Cap27/InstanciandoFuncoesEClassesTemplate.out . . . . . . . . . 29.1 Associa ca o com atributo de liga ca o. . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap29/associacoes.out . . . . . . . . . . . . . . . . . . . . . . . . 30.1 Usando fun co es matem aticas de <cmath>. . . . . . . . . . . . . . . . . . . ../listagens/Cap30/Usandocmath.out . . . . . . . . . . . . . . . . . . . . . . 30.2 Usando <complex>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap30/UsandoComplex.out . . . . . . . . . . . . . . . . . . . . . . 30.3 A classe <complex> da biblioteca padr ao. . . . . . . . . . . . . . . . . . . 30.4 Exemplo descritivo da classe <bitset>. . . . . . . . . . . . . . . . . . . . ../listagens/Cap30/ExemploDescritivoDaClassebitset.out . . . . . . . . . . . . 30.5 Usando <bitset> com <vector>, criando uma matriz de bits. . . . . . . . ../listagens/Cap30/Usandobitsetvector.out . . . . . . . . . . . . . . . . . . . 31.1 Usando insert_iterator e fun ca o predicado. . . . . . . . . . . . . . . . . ../listagens/Cap31/insertIterator.out . . . . . . . . . . . . . . . . . . . . . . . 32.1 Usando <vector>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap32/Usandovector.out . . . . . . . . . . . . . . . . . . . . . . 32.2 Usando <list>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap32/Usandolist.out . . . . . . . . . . . . . . . . . . . . . . . . 32.3 Usando <list> com as fun co es gen ericas (algoritmos gen ericos). . . . . . ../listagens/Cap32/Usandolist2.out . . . . . . . . . . . . . . . . . . . . . . . 32.4 Usando <deque>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap32/Usandodeque.out . . . . . . . . . . . . . . . . . . . . . . . 33.1 A classe container <stack>. . . . . . . . . . . . . . . . . . . . . . . . . . . 33.2 Usando <stack>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap33/Usandostack.out . . . . . . . . . . . . . . . . . . . . . . . 33.3 A classe container <queue>. . . . . . . . . . . . . . . . . . . . . . . . . . . 33.4 Usando <queue>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap33/Usandoqueue.out . . . . . . . . . . . . . . . . . . . . . . . 34.1 Usando <set>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap34/Usandoset.out . . . . . . . . . . . . . . . . . . . . . . . . 34.2 Usando <map>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap34/Usandomap.out . . . . . . . . . . . . . . . . . . . . . . . Novatec - Programa ca o Orientada a Objeto com C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31 501 501 502 509 509 509 510 512 513 513 514 514 514 515 516 516 518 519 524 525 529 529 532 532 533 535 537 537 538 553 554 563 563 568 569 569 571 573 573 578 579 580 581 582 582 587 588 591 593
32
Lista de Programas 35.1 Usando sort(), find(), find_if(), fill(). . . . . . . . . . . . . . . . . . . . ../listagens/Cap35/Usandosortndnd ifll.out . . . . . . . . . . . . . . . . . . 35.2 Usando sort() e copy() para ordenar linhas de texto. . . . . . . . . . . . . . . ../listagens/Cap35/ordenandoTexto.out . . . . . . . . . . . . . . . . . . . . . . . . . 35.3 Usando copy() para copiar dados de um arquivo de disco para um <vector>. . ../listagens/Cap35/dadosParaVector.out . . . . . . . . . . . . . . . . . . . . . . . . 35.4 Usando <vector> com algoritmos gen ericos: C alculo da mediana. . . . . . . . . ../listagens/Cap35/CalculoMediana.out . . . . . . . . . . . . . . . . . . . . . . . . . 35.5 Usando generator_n() para gerar uma s erie de dados. . . . . . . . . . . . . . ../listagens/Cap35/TCSeries.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.1 Usando divides<>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap36/divides.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.2 Usando multiplies<>. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap36/multiplies.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36.3 Criando e usando uma classe fun ca o. . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/Cap36/CriandoEUsandoClassefuncao.out . . . . . . . . . . . . . . . . 36.4 Usando fun co es gen ericas e objetos da STL. . . . . . . . . . . . . . . . . . . . . A.1 Pr e-processamento: Usando #ifdef..else. . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceA/ifelse.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 Pr e-processamento: Usando #if..else. . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceA/ifelse3.out . . . . . . . . . . . . . . . . . . . . . . . . . . . A.3 Pr e-processamento: Usando macros pr e-denidas. . . . . . . . . . . . . . . . . . ../listagens/ApendiceA/Macros.out . . . . . . . . . . . . . . . . . . . . . . . . . . . B.1 Classe Autixliar Cteste. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.2 Fun ca o e escopo A. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.3 Fun ca o e escopo B. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceB/escopoa.out . . . . . . . . . . . . . . . . . . . . . . . . . . B.4 Usando modicadores de acesso. . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceB/const.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.1 Usando os operadores de compara ca o, incremento, decremento, e os operadores compostos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceC/comparacao.out . . . . . . . . . . . . . . . . . . . . . . . . C.2 Usando os operadores l ogicos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 Usando os operadores de bits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceC/RepresentandoInteirosCombits.out . . . . . . . . . . . . . C.4 Usando operador de incremento. . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceC/incremento.out . . . . . . . . . . . . . . . . . . . . . . . . . C.5 Usando operador m odulo % e operador tern ario ? . . . . . . . . . . . . . . . . . ../listagens/ApendiceC/while3.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . D.1 Usando switch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceD/switch.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . D.2 Usando while. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceD/while2.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . D.3 Usando do..while. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceD/dowhile.out . . . . . . . . . . . . . . . . . . . . . . . . . . D.4 Usando break, continue, do..while, e switch. . . . . . . . . . . . . . . . . . ../listagens/ApendiceD/breakecontinue.out . . . . . . . . . . . . . . . . . . . . . E.1 Fun ca o main() e a entrada na linha de comando. . . . . . . . . . . . . . . . . . ../listagens/ApendiceE/entradalinhacomando.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 608 609 609 610 610 610 611 611 612 617 617 617 617 618 619 620 642 642 642 643 644 644 650 650 651 651 652 652 659 660 661 661 662 662 663 664 664 670 670 672 673 673 673 674 675 677 678
Lista de Programas E.2 Processando par ametros de main() com getopt(). . . . . . . . . . . . . . . . . ../listagens/ApendiceE/maingetopt.out . . . . . . . . . . . . . . . . . . . . . . . . E.3 Fun ca o recursiva: c alculo do fatorial. . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceE/funcaorecursiva.out . . . . . . . . . . . . . . . . . . . . . . E.4 Usando elipses (...) : fun ca o m edia. . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceE/UsoDeElipse.out . . . . . . . . . . . . . . . . . . . . . . . . F.1 Ponteiro de ponteiro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceF/ponteirodeponteiro.out . . . . . . . . . . . . . . . . . . . F.2 Comparando o uso de vetores est aticos de C, din amicos de C++, com auto_ptr de C++ e <vector> da stl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceF/autoptr.out . . . . . . . . . . . . . . . . . . . . . . . . . . F.3 Usando ponteiro de fun ca o. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceF/ponteiroDeFuncao.out . . . . . . . . . . . . . . . . . . . . . F.4 Ponteiro para m etodos da classe. . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceF/PonteiroParaMetodo.out . . . . . . . . . . . . . . . . . . . . F.5 Ponteiro em hierarquias e oset. . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceF/oset.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . F.6 Usando operador de endere co (&) e sizeof(). . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceF/enderecosizeof.out . . . . . . . . . . . . . . . . . . . . . . . G.1 Usando estruturas aninhadas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceG/EstruturasAninhadas.out . . . . . . . . . . . . . . . . . . . G.2 Usando enumera co es: Um calend ario. . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceG/Enumeracoesdia.out . . . . . . . . . . . . . . . . . . . . . G.3 Usando enumera ca o anonima. . . . . . . . . . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceG/enumeracaoanonima.out . . . . . . . . . . . . . . . . . . . . ../listagens/ApendiceH/FormatosPBMPGM . . . . . . . . . . . . . . . . . . . . . H.1 Usando arrays: Um programa de binariza ca o. . . . . . . . . . . . . . . . . . . . Lista de programas . . . . . . . . . . . . . . . . . . . . . . . . . .
33 678 679 680 680 681 681 687 687 689 690 691 691 692 693 693 693 694 694 699 699 702 703 703 704 709 709
34
Pref acio
Agradecimentos
Gostaria de agradecer aos amigos e companheiros que em algum momento e de alguma forma contribu ram para o desenvolvimento deste livro. Do LENEP - Laborat orio de Engenharia e Explora c ao de Petr oleo da UENF - Universidade Estadual do Norte Fluminense Darcy Ribeiro, Antonio A. G. Carrasquilla, Viatcheslav Priimenko (Slava), George Mitrofanov, Luiz O. E. dos Santos, Pavel Bedrikovetsky, Themis Carageorgos, Adolfo Puime, Severiano Ribeiro, Jorge Triguis, Marilia Barbosa, Victor Hugo, Eliane Souza, Roseane Miss agea, Geraldo Loures, S ergio Oliveira, Carlos Dias, Fernando Moraes, Bena Rodrigues, Alexandre Servulo, Luciano Botelho, Marcos Pinheiro, Pedro Mesquita, Cristofer, Debora Mendon ca, Eli ezer Freire, Sidna Abreu, Ana Pacheco, Kenedy Tavares, Verlaine Pereira, Remilson Rosa, e Marco Ceia. Da UFSC - Universidade Federal de Santa Catarina, Paulo C. Philippi, Roberto Lamberts, Jos e A. B. da Cunha Neto, Celso Fernandes, Saulo Guths, Vicente Nicolau, Amir de Oliveira, Fabiano Wolf, Lu s Hegele, Paulo Facin, Rodrigo Surmas, Carlos Ortiz, Carlos Paghi, Diego Silva, Geziel de Oliveira, Henrique de Gaspari, Jaison Meiss e Rodrigo Homann. Da PUC, Nathan Mendes, Luis Moura. Da UFRN, Adriano Santos, Aldomar Pedrini. Da UPFE, F abio Magnani. Da UEZO, Vania Estrela, Alfredo Boente, Rosana Pinheiro. Da ANP, S ergio Almeida (Biotita). Da ESSS, Marcos Damiani, Clovis Maliska. E os amigos extrangeiros, Jean F. Daian, Liang Zhirong. Aos alunos das disciplinas de Programa c ao Orientada a Objeto com C++, Programa c ao Pr atica, Software Livre e An alise de Imagens Aplicada, pelas constantes sugest oes apresentadas. Ao pessoal da Revista do Linux, que publicou no CD dessa publica c ao, edi c ao 33, a Apostila de Programa c ao Orientada a Objeto com C++, um embri ao da primeira edi c ao. Ao Rubens Prates, editor da Novatec, e sua equipe Marcelo Ferreira Paiva e Patrizia Zagni. Aos desenvolvedores do GNU/Linux a id eia do software livre . Ao GUFSC, o grupo de usu arios de software livre da UFSC. Em especial ao Ricardo, que me enviou uma lista de termos sobre software livre . Quero fazer um agradecimento especial a este pessoal maravilhoso que tive a oportunidade de conhecer em eventos como a Confer encia Internacional de Software Livre , o CONISLI, o LATINOWARE e em pequenos eventos de divulga c ao do software livre , e que tem defendido e lutado pelo software livre no Brasil: Cesar Brod, Rubens Queiros, Sulamita Garcia, Isabel Valverde, Timoty Ney, John Maddog Hall, Lucas Santos, Rafael Peregrino, S ergio Amadeo, Rog erio Santana, Julio Cezar Neves, Augusto Campos, Pablo DallOglio, Piter Punk, Walter Pinheiro, Djalma Valois. A PETROBRAS, Guilherme Castro, Farid S. Schecaira, Jos e Ten orio, pelo constante apoio as atividades de pesquisa desenvolvidas no setor de geo-inform atica do LENEP (LDSC). Nos u ltimos anos adquirimos dezenas de livros e equipamentos computacionais com recursos de projetos de pesquisa apoiados pela PETROBRAS, FAPERJ, FENORTE e CNPq. As pessoas que ajudaram na revis ao desta segunda edi c ao, Tiago Schaewer, Tiago Calimman, Irineu Silva, Allan Galante, Giovanni Colonese, Tiago Camara, Tayne Martins, Vitor Seraphim. Ao meu amigo de inf ancia, Luiz Alberto Alano. Aos meus sobrinhos e sobrinhas, Alessandra, Andr ea, Adroaldo, Alissa, Patricia, Angela, Isabel, Ana Paula, Gabriel, Beatriz, Manoela e Gustavo, que representam o futuro. Finalmente, gostaria de dedicar esta segunda edi c ao ` a minha esposa F atima e minhas lhas J ulia e Soa. No momento em que escrevo esta dedicat oria estou ausente. Pe co a J ulia e Soa desculpas pela minha aus encia, na sua inf ancia, quando fazia doutorado, e na sua adolesc encia, entre 13 e 16 anos quando fazia, nos ns de semana e a noite, esta segunda edi c ao.
35
36
Pref acio
38
Pref acio
39
40
Pref acio
Pr e-requisitos
A leitura do presente livro n ao requer nenhum pr e-requisito. Entretanto, para um melhor acompanhamento dos assuntos da Parte ?? - Programa ca o Multiplataforma com Software Livre, e aconselh avel um conhecimento pr evio de software livre e alguma experi encia com GNU/Linux. Voc e obt em material sobre software livre no s tio da Disciplina de Software Livre, veja tem disciplinas no endere co http://www.lenep.uenf.br/~bueno.
Pref acio
41
Alguns exemplos pr aticos de programas relacionados a area de an alise e processamento de imagens ser ao inclu dos no site da disciplina An alise e Processamento de Imagens.
Disciplinas Alvo
A nova estrutura do livro e mais did atica, foi montada de modo a fornecer a voc e um livro que possa ser utilizado como livro texto das seguintes disciplinas: Introdu ca o a Programa ca o Orientada a Objeto e UML. C++ e STL. Programa ca o Multiplataforma e Programa ca o com Software Livre (GNU/Linux). Introdu cao a Programa ca o Paralela e Distribu da. Cobre ainda o uso de algumas bibliotecas GPL e programa ca o gr aca com Qt 4. Did atica Este livro tem uma diferen ca did atica e conceitual muito clara em rela ca o a grande maioria dos livros programa ca o orientada a objeto e programa ca o em C++. Historicamente os livros de programa ca o usam uma abordagem estruturada - v cio dos velhos tempos. Os mesmos iniciam direta ou indiretamente com estruturas de controle, fun co es, arrays, vetores e ponteiros, ou seja, iniciam com os conceitos b asicos de linguagens estruturadas - como C e Fortran. Isto se explica em boa parte porque seus autores - pelo menos a maioria - come cou a desenvolver programas quando n ao existia programa ca o orientada a objeto. Outro problema comum na maioria dos livros de programa ca o e tratar o leitor como um quase idiota. Dezenas de livros repetem o mesmo conceito e as mesmas frases v arias vezes. O mesmo exemplo de c odigo e listado dezenas de vezes, e a cada nova apresenta ca o apenas pequenas inova co es s ao apresentadas. O livro ca enorme e com pouco conte udo. Misturam o desenvolvimento de um assunto com dezenas de dicas alheias ao conceito que esta sendo apresentado, distraindo o leitor. Alguns livros perdem muito tempo com os conceitos b asicos - f aceis de aprender. E dedicam pouco espa co para os conceitos mais dif ceis. O leitor tem a impress ao de que aprendeu o necess ario, quando ainda falta muito a aprender. Este livro e claramente diferente. O livro trabalha com conceitos de orienta ca o a objeto desde os primeiros cap tulos. De uma maneira geral cada cap tulo apresenta um conceito, abordando sua concep ca o te orica e pr atica, indo do mais f acil (usu arios iniciantes) ao mais dif cel (usu arios avan cados). Ou seja, voc e leitor e tratado com respeito e seriedade. Novatec - Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
Sobre o livro
Quando poss vel, a apresenta ca o dos conceitos segue uma did atica pr e-denida. Por exemplo, na parte de UML os conceitos s ao apresentados na seguinte ordem: Conceito geral. Exemplo e ilustra ca o/gura. Como o conceito e aplicado em orienta ca o a objeto (formalismo). Descri ca o formal do conceito aplicado a orienta ca o a objeto. Exemplo e ilustra ca o/gura. Conceitos correlatos. Exemplo real. Exemplo e ilustra ca o/gura.
Sobre o livro
O livro est a dividido nas seguintes partes: Parte I - Filosoa e Modelagem Orientada a Objeto: Destina-se a transmitir os conceitos b asicos de POO - Programa ca o Orientada a Objeto, a id eia, a losoa e a nomenclatura utilizada. Veremos alguns exemplos de objetos, os mecanismos b asicos e os conceitos-chave da POO; a modelagem orientada a objeto utilizando a UML - Unied Modelling Language ; como montar os diagramas de uma AOO - An alise Orientada a Objeto, utilizando a UML. Apresenta as etapas de desenvolvimento de um programa: a concep ca o, a elabora ca o, a an alise orientada a objeto, o projeto do sistema, o projeto orientado a objeto, a implementa ca o e o teste; a manuten ca o e a documenta ca o. Parte II - POO Utilizando C++: Apresenta a sintaxe de C++. Tipos pr e-denidos de C++, tipos do usu ario e tipos da STL - Standard Template Library. Como declarar, denir e utilizar classes, objetos, atributos e m etodos. Como implementar a heran ca simples, a heran ca m ultipla, a utiliza ca o de polimorsmo, a sobrecarga de operadores, a convers ao de tipos, e os tipos gen ericos (templates). Apresenta a entrada e a sa da de dados com as classes <ios_base>, <istream>, <ostream> e <sstream>. Como realizar opera co es com arquivos de disco utilizando as classes <fstream>, <ofstream> e <ifstream>. Apresenta um grupo de classes-padr ao de C++. A classe de strings-padr ao de C++, a <string>, a classe para tratar n umeros complexos <complex> e a classe <bitset>. Parte III - Introdu c ao ` a STL: Apresenta a STL, uma biblioteca de objetos em C++. Descrevem-se os conceitos b asicos de containers e iteradores. Voc e aprender a a utilizar um <vector> para vetores, <list> para listas duplamente encadeadas, <queue> que representa uma la, <stack> que representa uma pilha (como em uma calculadora HP ), <deque> que e uma la com duas extremidades e classes containers para tratamento de conjunto de dados com chaves, <set>, <multi_set>, <map> e <multi_map>. O uso de algoritmos gen ericos e fun co es objeto. Novatec - Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
Sobre o livro
43
Parte IV: Programa c ao Multiplataforma com Software Livre : Uma introdu ca o aos comandos de shell do GNU/Linux, programas u teis como ftp, telnet, ssh. Descreve conceitos de programa ca o multiplataforma. Apresenta as ferramentas de programa ca o com software livre, cobrindo emacs, gcc /g++, make, automake, autoconf, libtool, gdb, oes com cvs, cervisia, ddd, documenta ca o com JAVA DOC e doxygen, controle de vers subversion, e programas como di, patch e indent. Parte V: Cluster de Computadores e Processamento Paralelo: Apresenta os conceitos e os diferentes tipos de clusters de computadores. Uma introdu ca o ao processamento paralelo. As diferentes formas de processamento paralelo incluindo: i) a utiliza ca o de m aquinas com mais de um processador (SMP); ii) a utiliza ca o de processamento distribu do em um cluster com OpenMosix, e as vantagens e desvantagens da utiliza ca o de bibliotecas, como PVM - Paralel Virtual Machine e MPI - Message Passing Interface. A programa ca o com m ultiplos-processos e com m ultiplas-threads e apresentada com exemplos pr aticos. Os resultados de tempo de processamento de um cluster real s ao apresentados. Parte VI: Bibliotecas: S ao apresentadas algumas bibliotecas GPL, como Magick++, Common C++, Boost, Blitz++, Matpack, GSL e Qt 4. Parte VII: Ap endices: Descreve conceitos gerais de programa ca o em C/C++, como: diretrizes de pr e-processador, classes de armazenamento e modicadores de acesso, operadores, estruturas de controle, fun co es, ponteiros, refer encias, estruturas, uni oes e enumerac o es. Nos ap endices s ao apresentados ainda um gloss ario de C++, arquivos de cabe calho e a licen ca geral da GNU, a GPL. imAo longo da apresenta ca o dos temas, s ao inclu dos exemplos de programas completos. E portante que voc e compile os programas e verique o seu funcionamento.
44
Dica: se voc e tem pressa em instalar uma IDE a dica e: usu arios do GNU/Linux devem instalar o pacote de desenvolvimento da GNU, o gcc/g++. Usu arios do Windows podem instalar o programa DevC++, dispon vel em http://www.bloodshed.net/dev/.
Experi encia do autor Exemplos textuais podem ser apresentados como nesta frase. /* Os exemplos embutidos no texto tem a linha de comando em fonte fixa n~ ao s~ ao programas completos, s~ ao partes de programas. Apenas ilustram determinada caracter stica da linguagem e sua sintaxe. Os exemplos de c odigo fonte s~ ao apresentados em fonte fixa.*/ int x = 2;
45
Comandos embutidos no texto usam fonte normal, it alico e negrito, e a sa da aparece indentada, com fonte xa em it alico, como abaixo. libtool mode=compile g++ -c List-15-2-TCirculo.cpp mkdir .libs g++ -c List-15-2-TCirculo.cpp -fPIC -DPIC -o .libs/List-15-2-TCirculo.o g++ -c List-15-2-TCirculo.cpp -o List-15-2-TCirculo.o >/dev/null 2> &1
In umeras listagens de programas completos e testados foram inclu dos no livro. Cada programa e documentado, assim, o leitor entender a o signicado de cada linha. Veja a seguir, um exemplo de listagem que apresenta um programa funcional em C++, o tradicional Ol a Mundo. Logo a seguir apresenta-se a sa da. Listing 1: Exemplo de uma listagem (Listing).
/* * @ c o p y r i g h t ( C ) Andre Duarte Bueno # include < iostream > int main () { std :: cout << " Ol a mundo !\ n " ; return 0; } Ol a mundo ! @file List -1 - E x e m p l o D e L i s t i n g . cpp */
Senten cas: Senten cas s ao regras, exemplos e deni co es curtas e diretas. Se voc e encontrar termos desconhecidos d e uma olhada no gloss ario. 2 Senten ca de n vel 2 e recomentada para quem j a conhece C++ e quer se aperfei coar. 3 Senten ca de n vel 3 e recomendada para programadores avan cados. Algumas senten cas podem incluir extrato de c odigo, como abaixo. // Coment arios em C++ iniciam com //
46
<<C++>>
Biblioteca STL
+28,29,30,31,32,33
Filosofia POO
+1,2
Bsico
+5,6,7,8,9,10,11,24,26 +A,C,D
Modelagem OO
<< C++>> +3,4
Intermedirio
<< C++>> +12,13,14,15,17,18,19,20,25 +B,E,G
Avanado
+16,20,21,22,23,27, +F
Classes
+2,3,4,9,10,11,12,14,19,21
debug
+41
Documentao
+44
Herana
+2,3,4,15,16,17
Associaes
+2,3,4,20
Controle Verses
+47
Ferramentas
+4,35,36,37,38,40,41,42,44,47
Multiplataforma
+4,34,45,46
Pr.Paralelo
+48,49,50,51
Portabilidade
+45,46
47
Errata
Nos esfor camos ao m aximo para fornecer a voc e um livro de primeira qualidade. Entretanto, atividades de revis ao e testes, parecem nunca serem sucientes. Se encontrar erros, omiss oes, entre em contato com bueno@lenep.uenf.br. Antes entretanto, aconselha-se dar uma olhada na se ca o errata. http://www.lenep.uenf.br/~bueno/LivroCpp, veja arquivo Errata.html Errata.html.
Contatando o autor
Embora tenha sido realizado um esfor co enorme no sentido de se fazer um bom livro de programa ca o orientada a objeto com C++, a extens ao do livro e a sua abrang encia, tornam dif cel a sua manuten ca o (inclus ao de novos conceitos). Neste sentido, se voc e tiver dicas, sugest oes, e exemplos para melhoria deste livro, favor entrar em contato com:
Prof. Andr e Duarte Bueno. Software Enginering, Image Analysis and Processing Petroleum Engineering and Exploration Laboratory Science and Technology Center North Fluminense State University Rodovia Amaral Peixoto, km 163, Avenida Brenand S/N CEP 27925-310 - Imboassica - Maca e - RJ - Brasil e-mail: bueno@lenep.uenf.br http://www.lenep.uenf.br/~bueno Site do LENEP - Laborat orio de Engenharia e Explora ca o de Petr oleo http://www.lenep.uenf.br
48
LISTINGS
Parte I
49
Cap tulo 1
Introdu c ao ` a Programa c ao
Neste primeiro cap tulo apresentaremos o conceito de software (se ca o 1.1), o que e um programa, um software (se ca o 1.1.1), as diferen cas entre o software livre e o software propriet ario (se ca o 1.2). Al em disso, apresentaremos diferentes tipos de interface dos programas (se ca o 1.3), kernel num erico (se ca o 1.3.1), linha de comando (se ca o 1.3.2), modo texto (se ca o 1.3.3) e gr aca (se ca o 1.3.4). Discutiremos tamb em qual tipo de software voc e deve desenvolver (se ca o 1.4). Finalizaremos o cap tulo com um resumo e alguns exerc cios.
1.1
Programas e softwares
O objetivo de um programa de computador e facilitar a vida do usu ario, aumentar sua produtividade, principalmente para a realiza ca o de tarefas repetitivas e tamb em para possibilitar uma comunica ca o e intera ca o com o mundo de forma mais efetiva, r apida e globalizada. J a e poss vel a um usu ario de computador escrever documentos, montar planilhas, fazer gr acos e apresenta co es, enviar e receber mensagens e arquivos, fazer transa co es banc arias com seguran ca, montar projetos de engenharia, navegar na internet, ouvir m usicas, ver lmes e realizar diversas outras atividades de rotina e de lazer. Numa passagem r apida, podemos citar programas do dia a dia como o Oce (Power Point, Excel, Word), OpenOce (Impress, Calc, Write), Internet Explorer, Firefox, E-mail, Orkut, Players, programas t picos de servidores, como SSH, Telnet, FTP, programas especialistas de engenharia (Octave, Gnuplot, Matlab, Scilab, Autocad) e programas para o desenvolvimento de software (g++, make, gdb, ddd, cvs, cervisia, kdevelop, glade). Como podemos ver, temos ` a nossa disposi ca o centenas de softwares e programas, livres e propriet arios, com as mais variadas interfaces e formas de uso.
1.1.1
Software ou programa de computador e uma seq u encia de instru co es a serem seguidas e/ou executadas, na manipula ca o, redirecionamento ou modica ca o de um dado/informa ca o ou acontecimento. Quando um software est a escrito usando instru co es que podem ser executadas diretamente por um processador dizemos que est a escrito em linguagem de m aquina. O dispositivo mais conhecido que disp oe de um processador e o computador. Existem outras m aquinas program aveis, como telefone celular, m aquinas de automa ca o industrial, calculadora, etc. Um programa e feito usando Linguagens de Programa ca o. [Wikipedia, 2007]. 51
52
Eu prero uma deni ca o mais simples, como: conjunto de instru co es l ogicas, em linguagem de m aquina, utilizadas para realiza ca o de tarefas de nosso cotidiano por interm edio de um computador. Formalmente n ao existe diferen ca entre o conceito de software e programa. Mas particularmente uso o termo software, para um programa com interface gr aca amig avel e documenta ca o disponibilizada. Costumo usar o termo programa para um sistema que tem uma interface pobre e n ao tem documenta ca o (ou e mal documentado); Observe que essa e uma diferencia ca o de que gostamos de fazer, embora outros autores tenham suas pr oprias deni co es.
1.2
A seguir, ser ao apresentadas a deni ca o e as caracter sticas dos softwares propriet arios e dos softwares livres. Veja maiores detalhes nas refer encias: [Comunidade-GNU, 1996, http://www.fsl.org, 2004, Comunidade-Software-Livre, 1996]. [Anais, 2000, Queiroz, 2002, Amadeo., 2003].
1.2.1
Veja a seguir as principais caracter sticas do software propriet ario: Segundo a refer encia [Wikipedia, 2007], o software propriet ario e um conceito criado por empresas de software com a inten ca o de proteger o seu produto de qualquer tipo de altera ca o. Sua licen ca pro be a distribui ca o ou c opia sem a autoriza ca o do propriet ario. Possui licen ca propriet aria, n ao podendo ser copiado em outros computadores, pois o usu ario compra uma licen ca de uso para um computador e sistema espec co. desenvolvido por empresas comerciais como Microsoft, Borland etc. E N ao pode ser modicado, uma vez queo c odigo-fonte n ao e distribu do. Possui suporte ocial, geralmente bem documentado.
1.2.2
Veja a seguir as principais caracter sticas do software livre: Garante ao usu ario plenas liberdades de uso, acesso e modica ca o do c odigo-fonte, c opia e publica ca o de vers oes modicadas. A deni ca o completa de software livre pode ser encontrada em http://www.gnu.org/philosophy/free-sw.html. A licen ca GPL e a licen ca de software livre mais utilizada no mundo, mas existem outras licen cas de software livre, como: BSD, LGPL, Artistic Licence, CC. A caracter stica e que qualquer trabalho derivado de um software livre obrigatoriamente deve permanecer livre. Uma descri ca o da GPL pode ser obtida em http://www.gnu.org/licenses/gpl.html e no Ap endice L Licen ca P ublica Geral GNU. Desenvolvido a partir do movimento pelo software livre, o qual surgiu na d ecada de 1970 em conseq u encia da crescente press ao recebida para a ado ca o de softwares propriet arios e assinaturas de tratados de n ao-divulga ca o. O movimento ganhou for ca a partir da d ecada Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
53
de 1980 com o projeto GNU, que libertava os usu arios dos sistemas UNIX propriet arios. O GNU consolidou-se na d ecada de 1990 como um sistema operacional completo e funcional, atingindo uma qualidade t ecnica compar avel a ` dos melhores sistemas operacionais propriet arios. Em 1998 surgiu a Iniciativa Open Source 1 (c odigo aberto), grupo desmembrado do movimento pelo software livre em 1998 que rejeita a luta pela liberdade na utiliza ca o do software. Seu objetivo e disseminar a id eia de que o c odigo-fonte esteja dispon vel e que as modica co es sejam permitidas, gerando, assim, programas melhores. Apesar disso, esse grupo costuma recomendar a utiliza ca o da licen ca GPL, que representa melhor o esp rito do software livre. Isto torna os dois grupos cooperativos, do ponto de vista de cria ca o de softwares. Na maioria dos casos n ao possui suporte ocial (mas existem exce co es como o RedHat Enterprise, da RedHat, e o SUSE Linux Enterprise, da Novell). Nem sempre e bem documentado. Veja a seguir outros termos utilizados no mundo do software livre. O que e GNU? Acr onimo para GNU, n ao e UNIX. GNU e o nome de um sistema operacional completo e compat vel com UNIX escrito em 1983 por Richard Stallman e in umeros hackers da comunidade de software livre espalhados pela internet. O GNU e totalmente livre, ou seja, ele fornece as quatro liberdades b asicas do software livre: liberdade de uso, modica ca o, c opia e publica ca o de vers oes modicadas. O que e Linux? Clone livre do kernel do UNIX, escrito a partir do zero por Linus Torvalds, que contou com a ajuda de um grupo de programadores espalhados pela internet (isto e, o Linux e somente um kernel). Foi projetado para estar em conformidade com o POSIX e com a Single Unix Specication. O que e GNU/Linux? o sistema operacional GNU totalmente livre que utiliza o Linux como kernel; sendo a E variante mais conhecida do sistema GNU. Em resumo, Linux e um kernel, e n ao um sistema operacional. Apesar de Linux ser comumente utilizado em refer encia ao sistema operacional GNU/Linux, devemos evitar este uso equivocado por quest oes de clareza t ecnica e de cr edito ao projeto GNU, que forneceu o seu sistema operacional para ser adaptado ao kernel Linux. Sempre que quisermos falar deste sistema operacional, devemos usar o termo GNU/Linux. Desta forma, estaremos levando adiante os ideais do software livre que est ao representados no projeto GNU. Nota: uma descri ca o detalhada da licen ca GPL pode ser vista no Ap endice L Licen ca P ublica Geral GNU. Dicas e refer encias para migrar para software livre est ao dispon veis no , [GuiaLivre, 2004].
1 C odigo aberto: express ao utilizada para indicar que voc e pode ver o c odigo-fonte do programa. Entretanto, nada pode ser dito a respeito das condi co es sob as quais o c odigo-fonte se encontra. Existem programas de c odigo aberto que n ao s ao livres, pois o usu ario, dependendo da licen ca, pode ser proibido de alterar e publicar o c odigo.
54
1.2.3
Exemplo de sistemas operacionais propriet arios: Windows Mac OS X Unix Exemplo de sistemas operacionais livres: GNU/Linux Free-BSD Exemplos de programas propriet arios: Microsoft Oce Internet Explorer Borland Builder C++ Exemplos de programas livres GPL (equivalentes): OpenOce Firefox Kdevelop, Glade, Qt Designer J a sabemos o que e um software e as diferen cas entre software livre e software propriet ario. Tamb em vimos alguns exemplos de programas. Veremos a seguir os diferentes tipos de interface de um programa.
1.3
A interface de um programa e a forma como ele interage com o usu ario. Embora estejamos, na maior parte do tempo, utilizando programas com interface gr aca, ainda temos, muitas vezes, de utilizar programas com interface em modo texto. Usu arios avanc ados de Unix e GNU/Linux preferem utilizar programas neste modo, alegando conseguirem melhor produtividade. Nesta se ca o apresentaremos quatro tipos de interface de programas: Um programa sem nenhum tipo de interface kernel num erico (veja se ca o 1.3.1) . Um programa com interface via linha de comando (veja se ca o 1.3.2). Um programa com interface em modo texto (veja se ca o 1.3.3). Um software com interface em modo gr aco (veja se ca o 1.3.4). Nosso objetivo e apresentar as caracter sticas e as diferen cas entre esses programas, al em de apresentar o n vel de complexidade da sua interface. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
55
1.3.1
De uma maneira geral, um kernel num erico e um programa sem nenhum tipo de interface com o usu ario, sendo utilizado para realiza ca o de algum processamento de dados. Veja as caracter sticas de um programa do tipo kernel num erico: N ao tem interface com o usu ario (entradas e sa das). Tem como objetivo realizar algum processamento, geralmente um processamento pesado, ou a realiza ca o de tarefas bem espec cas. Uma documenta ca o simplicada pode ou n ao estar disponibilizada. Veja a seguir um exemplo de programa do tipo kernel num erico em C++. A classe TRotulador3D e usada para separar e identicar os objetos presentes em uma imagem binarizada. Para tanto, e utilizado um algoritmo de rotulagem dos pixels da imagem. Neste exemplo n ao existe nenhuma intera ca o com o usu ario; o arquivo com a imagem imagem.pbm e carregado do disco em (1), a rotulagem e realizada em (2) e o resultado e armazenado em disco com o nome rotulada.pgm em (3). Veremos na se ca o ?? outros exemplos de programas do tipo kernel num erico. Nota: n ao se preocupe em entender o programa, o objetivo e mostrar que neste exemplo n ao temos intera ca o com o usu ario. // Exemplo de rotulagem de imagens 3D #include <iostream> #include <TRotulador/TRotulador3D.h> int main(int argc, char* argv[]) { TRotulador3D rot("imagem.pbm"); // (1) Cria rotulador e carrega imagem rot.Go(); // (2) Executa rotulagem rot.Write("rotulada.pgm"); // (3) Salva resultado em disco return 0; }
1.3.2
Um programa pode ser desenvolvido de forma a receber a entrada do usu ario utilizando a linha de comando. Como exemplo, temos os programas dir e ls, os quais podem receber par ametros opcionais e s ao utilizados para visualiza ca o dos arquivos de um determinado diret orio. Observe que neste caso j a existe algum tipo de intera ca o entre o usu ario e o programa. Veja as caracter sticas de um programa com interface via linha de comando: A passagem dos par ametros e feita na chamada do programa, via linha de comando. Os par ametros podem ser opcionais como em ls -lah , dir /w . Para ver as op co es do programa ls, abra um terminal e digite ls - -help ou man ls . A sa da de dados e opcional, pode ser para tela, para um arquivo de disco ou para outro dispositivo. Este tipo de programa permite o uso de redirecionamentos (exemplo: ls > saida.txt ), uso de pipes (ex: ls | sort ) (veja se ca o 23.4). Veremos exemplos de programas com interface via linha de comando nas se co es E.1 e E.2. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
56
1.3.3
Um programa com interface em modo texto inclui entrada e sa da de dados usando uma interface simplicada (teclado e monitor). Veja a seguir as caracter sticas de um programa com interface neste modo: Apresenta interface simplicada, em modo texto. As entradas s ao executadas via teclado e as sa das, usando a tela, geralmente por meio de um terminal. Muito utilizado em servidores, em programas para manuten ca o do sistema, em programas cient cos, em engenharia e em sistemas antigos (legados). O programa de reconstru ca o tridimensional, ilustrado na Figura 1.1(a), e um exemplo de programa com interface em modo texto, o qual cria uma imagem 3D a partir de dados medidos em imagens 2D. O programa inicia mostrando valores-padr ao a serem utilizados na reconstru ca o e um menu simplicado, no qual o usu ario pode selecionar uma das seguintes op co es: iniciar a reconstru ca o, modicar os valores a serem utilizados ou abandonar o programa. Observe que, depois de selecionar a op ca o Valores corretos, iniciar reconstru ca o.....(r), cada etapa executada pelo programa e mostrada na tela, indicando que a mesma foi conclu da. Na Figura 1.1(b), e apresentada a tela inicial do programa Octave, utilizado para a realiza ca o de c alculos t picos de m etodos num ericos. No exemplo, o Octave e utilizado para somar dois vetores. Para maiores detalhes do programa Octave, consulte o site http://www.gnu.org/ software/octave/. Ao longo deste livro apresentaremos dezenas de exemplos de programas com interface em modo texto.
Um programa com interface em modo texto e mecanismo de recupera c ao O programa do grafo de conex ao serial, apresentado na Figura 1.2, e utilizado para determinar a permeabilidade de rochas usando representa co es 3D (imagens tridimensionais). Sua Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
57
entrada e a imagem gerada pelo programa de reconstru ca o (veja Figura 1.1(a)). Observe ainda na Figura 1.2 que o programa tamb em tem uma interface em modo texto semelhante ao programa de reconstru ca o, mas apresenta alguns diferenciais interessantes: Salva valores parciais da simula ca o em disco. Permite o rein cio do programa ap os queda de energia. N ao repete a simula ca o de imagens j a processadas (trabalha com lista de imagens). Essas caracter sticas s ao bastante u teis em programas de engenharia, programas cient cos e programas que envolvam o processamento de grandes quantidades de dados. O sistema de rein cio e bastante simples: a m aquina e programada para iniciar automaticamente o programa quando for reiniciada. O programa l e o arquivo com a lista de imagens a serem processadas, verica quais j a foram processadas, e ent ao reinicia a simula ca o da imagem que estava sendo processada quando a energia caiu.
1.3.4
O software Anaimp apresentado na Figura 1.3(a) e um software educativo para an alise de imagens e que possui interface em modo gr aco. Veja a seguir as caracter sticas de um software com interface em modo gr aco: ca o automatizada. Tem programa para instala Tem interface gr aca e amig avel (menus, bot oes, di alogos, barra de tarefa e de status). Tem previs ao de impress ao, possibilidade de desenho das imagens, sistema de controle dos processamentos (exemplo: visualiza ca o passo a passo dos processos realizados). Tem manual do usu ario. Infelizmente o programa Anaimp n ao foi nalizado, uma vez que, por utilizar uma biblioteca gr aca propriet aria que foi descontinuada a OWL da Borland , decidimos abandonar o desenvolvimento do programa Anaimp e posteriormente constru -lo utilizando bibliotecas GPL, como a Qt. Na se ca o ??, veremos diversos exemplos de uso da biblioteca Qt 4, utilizada para a montagem de programas com interface gr aca. Um exemplo de software prossional e completo com este tipo de interface e o Imago (veja Figura 1.3(b)), . O Imago e exemplo de software nacional, premiado, desenvolvido numa parceria da ind ustria (Petrobras) com a universidade (UFSC) e a empresa ESSS.
58
1.4
Bem, agora que voc e j a conhece as principais diferen cas entre o software propriet ario e o software livre e os diferentes tipos de interface com o usu ario, voc e precisa responder quest oes como: Devo desenvolver software propriet ario ou software livre? Devo desenvolver software com interface em modo texto ou em modo gr aco? Devo desenvolver software propriet ario ou software livre? A resposta para esta quest ao n ao e f acil. Voc e ter a de analisar os pr os e contras de cada modelo, e ent ao escolher o modelo de desenvolvimento de software que mais se aproxima de seu perl. Como sou defensor do modelo de software livre, aconselho a leitura das seguintes refer encias: O que e a losoa do SL? [Comunidade-GNU, 1996, http://www.fsl.org, 2004] Porque usar SL? [Queiroz, 2002] Quem paga pelo SL?[Comunidade-Software-Livre, 1996, Amadeo., 2003] Devo desenvolver software com interface em modo texto ou em modo gr aco? Esta resposta e mais f acil. Se o programa e um programa cient co, que envolve c alculos/processamentos pesados e que tem pouca necessidade de intera ca o com o usu ario, voc e pode usar uma interface em modo texto. No entanto, se o programa requer uma intera ca o constante com o usu ario, a op ca o correta e o software com interface em modo gr aco. Dica: tente montar o programa usando os conceitos prossionais da engenharia de software, pois viabilizam o desenvolvimento de softwares complexos e facilitam a migra ca o de um programa com interface em modo texto para interface em modo gr aco. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
59
1.5
Neste primeiro cap tulo aprendemos o conceito de software, de programa e as diferen cas entre o software livre e o software propriet ario. Ademais, foi colocada a quest ao sobre o que desenvolver: software propriet ario ou software livre. Vimos que um programa de computador pode ter diferentes tipos de interface e que um kernel num erico e um programa sem interface. Um programa em linha de comando, por sua vez, recebe seus par ametros na chamada do programa e pode ou n ao apresentar uma sa da na tela do computador. Um programa em modo texto, como o Octave, apresenta uma interface simplicada, em modo texto, e e utilizado por usu arios experientes. J a os softwares mais amig aveis contam com interface gr aca com menus, bot oes e di alogos que facilitam seu uso. No pr oximo cap tulo apresentaremos uma breve introdu ca o ` a programa ca o orientada a objeto. Dica: embora o computador possibilite uma intera ca o mais universal, seja por meio de um jogo de xadrez pela internet com pessoas de qualquer parte do mundo, seja por meio da cria ca o e desenvolvimento de sua pr opria tribo, n ao deixe de apreciar e viver a vida na sua comunidade. Aprenda a conciliar estes dois universos.
1.6
Exerc cios
1. Explique com suas palavras o que e um programa e porque desenvolvemos programas de computador? 2. Quais as principais diferen cas entre sistemas operacionais livres e propriet arios? 3. Porque devemos ler a licen ca de um software quando o instalamos? 4. Voc e j a deve ter utilizado um navegador para fazer o download de arquivos pela internet (como o Firefox/Explorer), mas existem programas em modo texto, como o FTP (veja se ca o ??) e o Wget (http://www.gnu.org/software/wget/wget.html), que tamb em s ao utilizados para fazer download de arquivos. Descreva quais as vantagens e desvantagens dos programas em modo gr aco e dos programas em modo texto. 5. Qual a vantagem de um programa que pode ser reinicializado automaticamente pelo sistema? 6. Um programa escrito por voc e pode usar componentes fornecidos por um programa livre como o OpenOce Impress? E se o programa fosse o Microsoft Word, voc e poderia utilizar componentes do Microsoft Word em seu programa? 7. Um sistema de engenharia gera uma quantidade enorme de dados, sendo necess ario fazer 100 gr acos. Estes gr acos podem ser mais rapidamente feitos em uma planilha como o OpenOce Calc ou em programas em modo texto como o Gnuplot (http: //www.gnuplot.info/)? 8. Quais as aplica co es e vantagens de programas do tipo kernel num erico? 9. Quais os programas com interface via linha de comando que voc e costuma utilizar? 10. Fa ca um breve hist orico de programas novos e antigos utilizados na sua area de estudo. Al em de perquisar na internet, converse com professores e prossionais antigos; tente entender as transforma co es que t em ocorrido no mundo da inform atica. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
60
Cap tulo 2
2.1
Entendendo os objetos
Para explicar os conceitos b asicos de orienta ca o a objeto, costumo usar primeiramente os objetos que est ao na sala de aula: cadeiras, mesas, computadores, projetor, cabos de energia e de rede, tomadas, l ampadas, pincel, quadro, apagador. Uma pergunta que sempre fa co e: como uma crian ca v e uma sala de aula? uma cadeira?. O objetivo desta pergunta e relembrar como aprendemos a entender o mundo em que vivemos. Entendemos o mundo por meio de classica co es e associa c oes. Estamos o tempo todo classicando, identicando os atributos (propriedades) e fun co es (a co es, m etodos) que determinado objeto e capaz de realizar. Na maioria dos casos conseguimos encaixar o objeto numa classe pr e-existente. Em alguns casos o objeto n ao e exatamente do mesmo tipo, mas e uma varia ca o, uma evolu ca o ou adapta ca o de um objeto conhecido. Assim, para uma crian ca, uma cadeira e um objeto cuja fun ca o e ser utilizada para se sentar. Neste sentido, uma cadeira de uma sala de aula, de um restaurante, ou at e mesmo um sof a e um tipo de cadeira. Rapidamente a crian ca come ca a fazer outras classica co es sobre as cadeiras, como, cadeira branca, cadeira com apoio para bra co, cadeira com rodinhas. Identicamos assim diversos atributos do objeto cadeira. Estes atributos (propriedades ou caracter sticas) s ao utilizados para diferenciar uma cadeira da outra, criando eventualmente subgrupos, mas o conceito essencial de objeto para se sentar permanece. Segundo [Guedes, 2004], sempre que precisamos compreender um conceito novo, criamos uma nova classe para este conceito e determinamos que todo objeto com as mesmas caracter sticas desta classe e um exemplo, uma inst ancia dela. Vamos a um exemplo: ao ver pela 61
62
primeira vez um SkySurf, voc e automaticamente o associa ao Surf e a esportes como AsaDelta. Neste caso, criamos um conceito novo baseado na composi ca o de conceitos j a conhecidos. Outro exemplo: uma c elula PVT. Possivelmente voc e vai perguntar que raio de objeto e esta tal c elula PVT? Uma c elula PVT e um equipamento utilizado em engenharia de petr oleo para determinar propriedades do oleo baseando-se em an alises de Press ao, Volume, Temperatura, ou seja, e um equipamento de medi ca o. Observe que e um conceito novo, um equipamento totalmente desconhecido. Nosso c erebro precisa criar este novo conceito, criando uma nova classe de objetos. Agora que j a sabemos mesmo que basicamente a forma como identicamos e classicamos os objetos, vamos apresentar um exemplo de objeto e a seguir o conceito de objeto.
2.2
Exemplo de objeto
Veja a seguir um exemplo de objeto do mundo real e a an alise de algumas de suas caracter sticas. Concluiremos que a programa ca o orientada a objeto e baseada em conceitos que j a conhecemos.
Um rel ogio Retire o seu rel ogio do pulso e comece a analis a-lo. Verique que ele e um objeto real, que lhe d a algumas informa co es como hora, data e dia da semana e que tem cron ometro e alarmes. Essas informa co es s ao atributos que s ao manipulados pelo rel ogio, ou seja, um objeto tem atributos. O rel ogio tamb em tem bot oes, como um bot ao de ilumina c ao, um bot ao para selecionar o atributo a ser visto, um bot ao para acertar a hora. Podemos dizer que o acionamento desses bot oes corresponde a um evento, uma mensagem enviada para o objeto solicitando que determinada fun ca o do rel ogio seja executada. Logo, um objeto tem fun co es (m etodos). Al em dos bot oes, o rel ogio tamb em tem uma caixa externa e uma pulseira, ou seja, um objeto rel ogio e composto de outros objetos. Um objeto pode ser formado a partir de um conjunto de objetos que s ao agregados/agrupados. Falamos de um rel ogio moderno, com alarmes e cron ometros; mas um rel ogio antigo s o informava a hora; de um rel ogio de bolso evoluiu-se para rel ogios de pulso, para rel ogios de parede, para rel ogios com alarmes, com cron ometros etc., ou seja, um objeto pode evoluir e esta evolu ca o est a associada a uma heran ca, uma hierarquia. Apesar de todas essas informa co es, a informa ca o principal do rel ogio e a hora certa. Visto que o rel ogio n ao e uma m aquina perfeita, ele pode atrasar. Neste caso, o dono do rel ogio utiliza a informa ca o de um rel ogio-padr ao, com a hora certa, para acertar a hora. Nesse exemplo, um objeto homem interagiu com o objeto rel ogio, logo, podem existir intera co es entre os objetos. Uma informa ca o de um rel ogio-padr ao (a hora certa) foi usada para acertar outro rel ogio. Observe que um objeto tamb em pode acessar diretamente informa co es de outros objetos. Voc e tamb em sabe que existe uma f abrica de rel ogios e que nela est ao as informa co es para se construir o rel ogio. Veremos que uma classe e uma f abrica de objetos, e e na classe que se encontram as informa co es de como montar o objeto. Os conceitos discutidos neste exemplo, atributos, eventos, m etodos, agrega ca o, heran ca, classes, al em da abstra ca o, s ao os conceitos b asicos da POO e j a s ao nossos conhecidos. Os mesmos ser ao detalhados no Cap tulo 3 Conceitos B asicos de Orienta ca o a Objeto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
63
2.3
Objetos s ao coisas do mundo real ou imagin ario que podemos, de alguma forma, identicar, como uma pedra, uma caneta, um copo ou uma fada. Segundo [Rezende, 2002], um objeto pode ser uma entidade externa, coisas, unidades organizacionais, lugares, estruturas. Um objeto possui determinadas propriedades que o caracterizam e que s ao armazenadas nele mesmo. Suas propriedades s ao chamadas de atributos e s ao utilizadas para identicar o estado do objeto. O objeto interage com o meio e, em fun ca o de excita co es que sofre, realiza determinadas a co es que alteram o seu estado (seus atributos). Observe que os atributos do objeto n ao s ao est aticos, pois sofrem altera co es com o tempo. Para a AOO (An alise Orientada a Objeto), um objeto e uma entidade u nica que re une atributos e m etodos, ou seja, re une as propriedades do objeto e os m etodos respons aveis pela realiza ca o de opera co es sobre o objeto (as rea co es ` as excita co es que sofre). Nota: por conven ca o, o nome dos objetos e escrito como em RioDasOstras (e n ao Rio das Ostras ou Rio das Ostras).
2.4
As linguagens de programa ca o de primeira gera ca o eram bastante r usticas, de baixo n vel (como o Assembler), e obrigavam o programador a conhecer em excesso as caracter sticas do hardware que estava usando. Um programa se dirigia para um equipamento espec co, era extremamente complexo de desenvolver, e n ao podia ser utilizado em outras m aquinas. N ao era poss vel reaproveitar os c odigos desenvolvidos. Com o passar dos anos, desenvolveram-se novas linguagens de programa ca o, que foram desvinculando os programas do hardware, de tal forma que um mesmo c odigo poderia ser compilado e executado em diferentes plataformas. Entre as linguagens de segunda gera ca o, podemos citar Fortran e Algol. Estas linguagens proporcionaram um grande avan co no desenvolvimento do software. Observe que persistiam dois problemas: o execut avel ainda era espec co e n ao existia reaproveitamento de c odigo. Enquanto o desenvolvimento de hardware se dava a passos largos, o desenvolvimento de softwares estava atrasado cerca de 20 anos. As linguagens de programa ca o de terceira gera ca o, como C e Pascal, s ao linguagens procedurais, que permitem o uso de programa ca o estruturada , na qual as fun co es manipulam os dados, mas n ao t em uma liga ca o ntima com eles. O enfoque e a implementa ca o de m odulos de programas que s ao desenvolvidos utilizando metodologias como bottom-up ou top-down. Com o desenvolvimento das t ecnicas de programa ca o estruturada, o problema da falta de reaproveitamento de c odigo diminuiu, pois foram desenvolvidas bibliotecas que podiam ser reaproveitadas. Para uma descri ca o completa das t ecnicas de programa ca o estruturada, consulte [Martin and McClure, 1993, Sonerviile, 1993, Pressman, 2002]. Mesmo com o surgimento dos primeiros modelos de engenharia de software e das t ecnicas de programa ca o estruturada, as equipes de desenvolvimento sempre tiveram enormes problemas para o desenvolvimento de seus programas. Tinham de partir praticamente do zero para o desenvolvimento de um programa ou reaproveitar muito pouco os c odigos e bibliotecas j a desenvolvidos. Para solucionar o problema do reduzido reaproveitamento dos c odigos, deniu-se melhor a id eia da Programa ca o Orientada a Objeto. A POO n ao e nova; sua formula ca o data de 1960, Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
64
mas passou a ser efetivamente utilizada a partir da d ecada de 1990, de modo que todas as grandes empresas de inform atica t em desenvolvido os seus softwares utilizando a POO. A programa ca o orientada a objeto e diferente da programa ca o estruturada. Nela, fun co es e dados est ao juntos, formando o objeto. Essa abordagem cria uma nova forma de analisar, projetar e desenvolver programas; uma forma mais abstrata e gen erica, que permite maior reaproveitamento dos c odigos e facilita a sua manuten ca o. Observe que a POO n ao e somente uma nova forma de programar, mas uma nova forma de pensar um problema, utilizando conceitos do mundo real e n ao conceitos computacionais. Por exemplo: o usu ario nal ver a todos os cones e janelas da tela como objetos e associar a a manipula ca o desses objetos visuais ` a manipula ca o dos objetos reais que eles representam. Um cone impressora representar a a impressora de seu sistema computacional e permitir a a execu ca o de impress ao, a sele ca o do tamanho da p agina, entre outras opera co es realizadas com esse objeto. Na modelagem orientada a objeto, o conceito de objeto deve acompanhar todo o ciclo de desenvolvimento do software. Ela tamb em inclui uma nova nota ca o e exige do analista/programador o conhecimento desta (diagramas). Em resumo, A ess encia do desenvolvimento orientado a objeto e a identica ca o e a organiza ca o de conceitos da aplica ca o, tendo como pe ca b asica de todo desenvolvimento o conceito um modo de pensar natural e universal e n de objeto. E ao uma t ecnica de programa ca o. [Blaha and Rumbaugh, 2006]. As linguagens de programa ca o mais modernas permitem que um programa seja compilado e executado em diferentes plataformas. Em alguns casos, o c odigo bin ario do programa pode ser executado em diferentes plataformas, sem necessidade de recompila ca o e com grande reaproveitamento de c odigo. Atualmente existem centenas de bibliotecas cuidadosamente desenhadas para dar suporte aos programadores menos sosticados, de modo que estes podem montar seus programas unindo as bibliotecas externas com alguns objetos que criaram, ou seja, podem montar suas aplica co es rapidamente, contando com m odulos pr e-fabricados. O paradigma da POO e, como veremos a seguir, uma resposta eciente a uma s erie de problemas da area de desenvolvimento de software. Veremos exemplos de bibliotecas externas na se ca o ?? Bibliotecas Uteis.
2.4.1
Esta se ca o apresenta tr es formas de desenvolvimento de um programa simples, o qual realiza a integra ca o num erica de uma fun ca o parab olica. Mesmo n ao entendendo nada de m etodos num ericos, voc e deve ler esse exemplo; o que importa e o conceito abordado. Especica ca o: quero desenvolver um programa que realize a integra ca o num erica da equa ca o de uma par abola y = a + b.x + c.x2 , no intervalo que vai de limiteInferior a limiteSuperior, usando 100 subintervalos (numeroPontos = 100). Vis ao desorganizada O programador desorganizado come ca imediatamente a desenvolver o seu programa. Cria um arquivo u nico no qual dene as vari aveis, a fun ca o e nalmente inclui o c odigo para realizar a integra ca o pelo m etodo de Simpson (porque e o que ele conhece e domina). Os nomes das vari aveis s ao v1 (o valor de y), v2 (o a da equa ca o), v3 (o b), v4 (o c), v5 (ele n ao utiliza, mas deixa denida). Dene ainda s1, s2, s3 e s4 (vari aveis utilizadas pelo m etodo de integra ca o). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
65
O programa funcionar a; o programador ent ao dar a um nome como prog1 e o armazenar a num diret orio qualquer. Depois de um m es, ele j a n ao se lembra mais do nome do programa e de onde o guardou, e agora precisa desenvolver um programa de integra ca o para uma outra fun ca o. Bem, come ca tudo de novo, pois, mesmo que localize o arquivo, n ao se lembrar a do que signica v1, v2 etc. Vis ao estruturada Na vis ao estruturada o programador se preocupa em dividir/separar as fun co es. Em um arquivo prog.cpp, o usu ario inclui as bibliotecas-padr ao do sistema que utilizar a. O usu ario declara fun co es globais, uma para c alculo da fun ca o parab olica y = f(x) = a + b.x + c.x2 ;, e outra para c alculo da integral com o nome AreaSimpson(f, limiteInferior, limiteSuperior, numeroPontos);. Uma fun ca o principal main() e encarregada da entrada de dados, da chamada da fun ca o AreaSimpson(f, limiteInferior, limiteSuperior, numeroPontos); e da sa da dos resultados. Observe que, com uma vis ao estruturada, o programa apresentar a alguma organiza ca o. Vis ao orientada a objeto Na vis ao orientada a objeto todo o desenvolvimento do software e feito de forma diferente. A inten ca o nunca e a de resolver um problema u nico e imediato. 1. Especico com clareza o que quero: resolver uma integra ca o num erica de uma equa ca o gen erica por qualquer m etodo. 2. Elaboro melhor o problema, estudando materiais relacionados ao programa a ser desenvolvido, lendo alguns livros de matem atica e m etodos num ericos relacionados ao tema. 3. Em seguida, fa co uma an alise para identicar os objetos e seus relacionamentos. Ao olhar um livro de m etodos num ericos, descubro que existe um conjunto de m etodos que podem ser utilizados para resolver o problema. As equa co es podem ser as mais diversas poss veis, mas possuem algumas caracter sticas em comum. A fun ca o parab olica obedece ` a forma y = f(x). Com rela ca o aos m etodos num ericos, ela identica os m etodos mais conhecidos: Trap ezio, Simpson e Gauss, que possuem em comum atributos como limiteInferior, limiteSuperior, numeroPontos e o intervalo dx. Assim, identicam-se alguns objetos: i) um objeto gen erico de integra ca o num erica, um objeto de integra ca o por Simpson, outro por Trap ezio e outro por Gauss; ii) um objeto fun ca o da forma y = f(x), que tem os atributos y, x; e- iii) um m etodo de c alculo que executa a fun ca o em si. O objeto integra ca o deve receber o objeto fun ca o e realizar a integra ca o dessa fun ca o. 4. Antes de iniciar o desenvolvimento do programa, o programador deve considerar as caracter sticas da linguagem que vou utilizar e do hardware que est a dispon vel. Devo revisar a an alise desenvolvida considerando o hardware e a linguagem de programa ca o escolhida. 5. Agora sim, come co a escrever o programa, que utiliza uma nota ca o uniforme. 6. Finalmente o programa e testado e os erros (bugs) s ao eliminados. 7. N ao me esque co de documentar tudo o que foi feito, para que possa reaproveitar o programa em uma outra ocasi ao. A documenta ca o tamb em ajuda nas etapas de teste e manuten ca o. 8. O programa nal e armazenado em um reposit orio, podendo ser facilmente localizado, reaproveitado e/ou extendido. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
66
2.4.2
Vantagens da POO
Comparando a vis ao desorganizada e a vis ao estruturada com a vis ao orientada a objeto, podemos identicar as seguintes vantagens da POO: Os objetos s ao representa co es de conceitos j a conhecidos. Os objetos, as fun co es e as vari aveis t em nomes claros e precisos. Os objetos se relacionam da forma esperada, de modo que um programador iniciante ter a uma vis ao facilitada do programa. Os diagramas desenvolvidos na etapa de an alise facilitam o entendimento de todo o programa (os diagramas ser ao apresentados no Cap tulo 6 Etapas para o Desenvolvimento de um Programa). O programa e documentado, facilitando o reaproveitamento dos c odigos desenvolvidos. O trabalho desenvolvido e gravado como uma biblioteca de objetos em um local adequado (normalmente um reposit orio). Para desenvolvedores, programadores, analistas ou gerentes, as vantagens da POO podem ser resumidas a: Gerentes maior velocidade e menores custos no desenvolvimento do programa. Analistas e desenvolvedores processo de modelagem mais simples, com maior reaproveitamento de c odigos e facilidade de manuten ca o. Programadores aumento da produtividade.
2.5
Neste cap tulo vimos que C e Pascal s ao linguagens procedurais, de terceira gera ca o, e que a linguagem C++ pode ser considerada uma linguagem de quinta gera ca o. Destacamos que a programa ca o orientada a objeto e mais natural e organizada que a programa ca o estruturada e camos conhecendo as vantagens da POO, como a maior velocidade e o aumento da produtividade no desenvolvimento de sistemas complexos. Passamos a entender o conceito de objeto e vimos que os conceitos utilizados na POO s ao nossos conhecidos. No Cap tulo 3 Conceitos B asicos de Orienta ca o a Objeto, aprenderemos os conceitos de abstra ca o, encapsulamento, objeto, heran ca e polimorsmo. Depois, no Cap tulo 4 Modelagem Orientada a Objeto, analisaremos a vantagem do uso de modelos, o hist orico e o uso da UML Veremos ainda a evolu ca o hist orica do ciclo de desenvolvimento de um software no Cap tulo 5 Engenharia de software. Finalmente, no Cap tulo 6 Etapas para o desenvolvimento de um software, descrevemos todo o ciclo de desenvolvimento de um software
2.6
Exerc cios
1. Procure na internet material que compare a programa ca o estruturada e a programa ca o orientada a objeto. Fa ca um resumo comparativo. 2. Diga, com suas palavras, as principais diferen cas entre a vis ao estruturada e a vis ao orientada a objeto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
67
4. Quando estiver dentro de um carro, procure identicar quais s ao os objetos agregados (que fazem parte do carro). 5. Pense num carro de 40 anos atr as. Quais as principais diferen cas em rela ca o a um carro atual? 6. Para um objeto impressora, quais s ao seus atributos? Quais s ao seus m etodos? 7. Releia a se ca o 2.2 Exemplo de objeto e verique que os conceitos apresentados objetos, atributos, fun co es, composi ca o, evolu ca o, heran ca, intera co es s ao conceitos que j a conhecemos, ou seja, a orienta ca o a objetos j a faz parte de nosso dia-a-dia. Voc e concorda com esta arma ca o? 8. Diga com suas palavras o que e um objeto? 9. Quando estiver em casa, fa ca uma an alise dos atributos e das fun co es dos objetos: sof a, televisor, mesa, cadeira, escrivaninha, torneira etc. 10. Para cada grupo de objetos ou de palavras a seguir, identique as caracter sticas em comum e depois suas diferen cas: Pasta, mala, mochila. Cadeira, poltrona, sof a. Carro, caminh ao, trator. Winchester, zip drive, CD-RW, DVD-RW, pen-drive. 11. Separe alguns objetos reais e procure identicar seus atributos, funcionalidades e como os mesmos interagem com outros objetos.
68
Cap tulo 3
3.1
Abstra c ao
No dicion ario Aur elio, abstra ca o signica considerar isoladamente coisas que est ao unidas, ou seja, partimos do enfoque global de um determinado problema e procuramos separar os elementos fundamentais e coloc a-los de uma forma mais pr oxima da solu ca o. A id eia da abstra ca o e identicar os elementos essenciais de um problema e suas propriedades fundamentais, separando ocorr encias e atributos acidentais (isolando detalhes menos importantes). Para a an alise orientada a objeto, abstra ca o e o processo de identica ca o dos objetos e seus relacionamentos. Ela permite ao analista concentrar-se no que um objeto e e faz, sem se preocupar como ele o faz. A abstra ca o se d a em diferentes n veis: inicialmente, abstrai-se o objeto; em seguida, procuramos identicar seus atributos e funcionalidades. De um conjunto de objetos, cria-se um conjunto de classes relacionadas, geralmente uma hierarquia ou um assunto. Por exemplo: em nossa sala de aula temos um interruptor e l ampadas. Todos sabemos que o interruptor e o objeto a ser acionado para que a l ampada acenda/apague. Existe uma clara rela ca o entre o interruptor e a l ampada. Juntamente com os os e o disjuntor eles formam o sistema de ilumina ca o. Observe as Figuras 3.1 (a) e 3.1 (b). Qual imagem e mais confusa? Em 3.1(a), est ao representados elementos do sistema de ilumina ca o, do sistema de telefonia, do cluster e os computadores da sala. A Figura 3.1(b) e mais simples, pois eliminamos os detalhes que n ao s ao importantes, deixando apenas os elementos essenciais ao sistema de ilumina ca o. A partir da Figura 3.1(b), podemos identicar mais claramente os objetos do sistema de ilumina ca o. 69
70
Observe que podemos ver o interruptor e a l ampada como sendo um objeto u nico ou como dois objetos que se relacionam. Outra percep ca o importante: nossa vis ao natural. Nossos conceitos b asicos enfocam os objetos e n ao os sistemas dos quais fazem parte. Por exemplo: focamo-nos no objeto l ampada, no objeto interruptor, e n ao no sistema de ilumina ca o. Finalmente e importante destacar que uma boa abstra ca o do sistema e conseguida ap os v arias itera co es, muita an alise e um pouco de experi encia. Figura 3.1: O processo de abstra ca o.
servidor
interruptor
interruptor
(a)
(b)
No exemplo da Figura 3.1 identicamos os seguintes objetos: Quadro de distribui ca o Fios Interruptor L ampadas
3.2
Encapsulamento e oculta c ao
Todos os equipamentos que utilizamos s ao altamente encapsulados. Tome como exemplo seu monitor de computador. Ele tem um pequeno conjunto de bot oes que lhe permitem manipular os atributos do objeto monitor que s ao de seu interesse, como: ligar/desligar, controlar o brilho, o contraste, a resolu ca o. Mas voc e sabe que o funcionamento do objeto monitor e extremamente complexo e que, ao mudar a resolu ca o, uma s erie de atributos internos s ao processados e alterados. Um monitor CRT tem um tubo de raios cat odicos, dezenas de os, placas internas, resistores, capacitores e uma innidade de dispositivos el etricos que est ao ocultos, encapsulados, escondidos do usu ario; ou seja, o encapsulamento separa o que e vis vel (p ublico) do que e oculto (protegido/privado). Na Figura 3.2, temos a imagem de dois monitores: em (a) a vis ao de um usu ario comum; em (b) a vis ao de um engenheiro eletricista. A vis ao de cada um e diferente, depende de suas especialidades. Observe que os engenheiros eletricistas zeram um bom trabalho de encapsulamento, deixando acess vel apenas o que e de nosso efetivo interesse. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
71
Exemplos: Um computador e um objeto extremamente complexo, mas para o usu ario o que importa e o teclado, o monitor de v deo, o DVD, o mouse e o gabinete. Ao utilizar um software como o OpenOce, a forma de uso e a mesma, seja em um Windows com Pentium IV ou em um GNU/Linux com AMD Athlon 64. Os elementos invis veis do computador (placa-m ae, processador e mem oria) e do sistema operacional n ao alteram a forma de uso do programa. As propriedades f sicas de um determinado material de constru ca o (telha) e os m etodos de c alculo de suas propriedades (resist encia ` a compress ao, condutividade t ermica etc.). Aqui, a telha e o objeto, as propriedades s ao seus atributos e o c alculo de suas propriedades s ao os m etodos. Para o usu ario o que interessa s ao as propriedades conhecidas, e n ao as equa co es, as vari aveis intermedi arias e a forma de c alculo, pois isto ca escondido. Para a an alise orientada a objeto, encapsulamento e o ato de esconder do usu ario informa co es que n ao s ao de seu interesse. O objeto atua como uma caixa preta, que realiza determinada opera ca o, mas o usu ario n ao sabe, e n ao precisa saber, exatamente como e feita; ou seja, o encapsulamento envolve a separa ca o dos elementos vis veis de um objeto dos invis veis. Os elementos vis veis formam a interface de acesso ao objeto. Veja a seguir um exemplo: Em um programa que calcula a area da curva normal, o c alculo interno pode ser realizado por um polin omio que aproxima a area da normal ou pela integra ca o num erica da equa ca o da normal. A decis ao de qual m etodo de c alculo ser a utilizado e realizada pelo objeto TNormal em fun ca o de um atributo interno, o limiteErro. O usu ario externo cria o objeto TNormal, informa o limite de erro e solicita o c alculo da area. O usu ario n ao sabe qual m etodo de c alculo ser a utilizado, pois isto ca escondido. A vantagem do encapsulamento surge quando ocorre a necessidade de se modicar um programa existente. Por exemplo: voc e pode modicar todas as opera co es invis veis de um objeto (os sistemas internos), para melhorar o desempenho dele, sem se preocupar com o resto do programa. Como estes m etodos n ao s ao acess veis ao resto do sistema, eles podem ser modicados sem causar efeitos colaterais. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
72
3.3. CLASSES
Segundo [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006], o encapsulamento evita que um programa se torne t ao interdependente que uma pequena modica ca o tenha um efeito de propaga ca o grave. [Pressman, 2002] lembra que os detalhes internos de implementa ca o dos dados e procedimentos s ao ocultados do mundo exterior (oculta ca o de informa ca o). Isso reduz a propaga ca o de efeitos colaterais quando ocorrem modica co es. Segundo [Parga, 2006], como conseq u encia do encapsulamento temos uma diminui ca o consider avel do n vel de acoplamento entre as classes que fazem parte do sistema. O n vel de acoplamento e avaliado pela interdepend encia entre os c odigos de duas ou mais classes, ou seja, o quanto o funcionamento de uma determinada classe e afetado por altera co es em uma outra classe que interaja com ela. O encapsulamento permite a implementa ca o de uma abstra ca o com a separa ca o clara entre a interface com o usu ario e a implementa ca o.
3.3
Classes
Quando falamos de classes, lembramo-nos de classes sociais, de classes de objetos da natureza, de hierarquias (por exemplo, a classe dos animais vertebrados). De um modo geral, uma classe descreve um grupo de objetos com os mesmos atributos e comportamentos, al em dos mesmos relacionamentos com outros objetos. Veja a seguir alguns exemplos de classes: Cachorros buldogue, pastor alem ao, vira-lata. Rel ogios de ponteiro, digital, com alarmes, com cron ometros, com calculadoras. A classe cont em a descri ca o da forma do objeto; e um molde para a cria ca o do objeto, e uma f abrica de objetos. Uma classe tamb em e um tipo denido pelo usu ario. Para a an alise orientada a objeto, uma classe e um conjunto de c odigos de programa ca o que incluem a deni ca o dos atributos e dos m etodos necess arios ` a cria ca o de um ou mais objetos. Grady Booch [Booch, 1986], diz que um objeto e uma entidade concreta que existe no tempo e no espa co, uma classe representa apenas uma abstra ca o, a ess encia do objeto. [Blaha and Rumbaugh, 2006] lembra que qualquer escolha de classe e arbitr aria e depende da aplica ca o. No exemplo da Figura 3.3 apresentamos um rel ogio e um cachorro. Podemos associar a estes dois objetos uma classe e uma classe Cachorro. Figura 3.3: Um rel oogio e um cachorro.
73
3.4
Podemos relacionar alguns atributos (propriedades) a todo objeto. No exemplo do rel ogio, podemos relacionar a hora e a data. Uma cadeira pode ser branca ou preta, ter apoio para os bra cos, ter rodinhas. Um monitor de computador pode ter 15, 17, 19 ou 21 (polegadas) e sua resolu ca o m axima em pixels pode ser 1024x768, 1280x1024, 1600x1280; ou seja, todo objeto tem seus pr oprios atributos, propriedades. Os atributos do objeto s ao utilizados para diferenciar os objetos e para identicar o estado do objeto. Na programa ca o orientada a objeto, os atributos s ao denidos na classe e armazenados de forma individual ou coletiva pelos objetos. Quando um atributo e individual (ou de inst ancia), ele e armazenado no objeto. Exemplo: A hora de um rel ogio. Cada rel ogio tem uma hora, que pode ou n~ ao estar certa. Quando um atributo e compartilhado entre todos os objetos de uma classe, ele e armazenado nela e e conhecido como atributo coletivo ou de classe. Este tipo de atributo dene uma caracter stica de toda classe. Exemplo: Um contador de rel ogios criados. Quando um atributo n ao muda nunca, ele e denominado constante. Exemplo: O n umero constante pi = 3.1415... Veremos na se ca o 6.4.2 como identicar os atributos usando AOO, e na se ca o 6.4.4, como representar os atributos usando UML. No Cap tulo 12 Atributos, veremos como implementar os conceitos de atributos em C++.
3.5
Podemos relacionar determinados comportamentos, fun co es, opera co es, a co es e rea co es a um objeto. Veja a seguir alguns exemplos: Um autom ovel tem o comportamento de se locomover. Uma edica ca o tem a fun ca o de dar abrigo. Um equipamento de medi ca o e utilizado para realizar medidas. Um computador processa os programas, realizando as opera co es codicadas. Um meio poroso permite o uxo de massa. Na an alise orientada a objeto, as fun co es, opera co es e os comportamentos dos objetos s ao descritos pelos m etodos, os quais tamb em servem para manipular e alterar os atributos do objeto (alteram o estado do objeto). Em um programa orientado a objeto os est mulos s ao representados por eventos. Por exemplo: um evento ocorre quando o usu ario clica o mouse sobre o cone impressora, o qual envia uma mensagem para o objeto impressora solicitando a impress ao do arquivo selecionado. O m etodo Imprimir() recebe o nome do arquivo a ser impresso, realiza a impress ao do mesmo Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
74
3.6. HERANCA
e ent ao retorna um ag indicando que a opera ca o de impress ao terminou com sucesso ou falhou. Observe que o objeto impressora e representado na tela por seu cone. Na maioria dos programas, um item de menu e usado para acessar um di alogo com propriedades do objeto impressora. Podemos dizer que um m etodo e uma opera ca o realizada sobre um objeto e e descrito por uma classe. Um m etodo e a implementa ca o de uma opera ca o. S ao elementos de um m etodo: Retorno todo m etodo retorna um objeto ap os sua execu ca o. Nome o nome de um m etodo deve identicar com clareza o que ele faz. Par ametros s ao as vari aveis e objetos passados para o m etodo para realiza ca o de suas tarefas. Veremos na se ca o 6.4.3 como identicar os m etodos usando AOO, e na se ca o 6.4.4, como representar os m etodos usando UML. No Cap tulo 13 M etodos, veremos como implementar os m etodos em C++. Veremos tamb em, na se ca o 3.6, que, numa hierarquia de classes, m etodos com a mesma assinatura podem apresentar comportamento polim orco. Observe ainda que todos os objetos criados a partir de uma mesma classe-base compartilham os m etodos da classe.
3.6
Heran ca
A heran ca est a relacionada ` as hierarquias e ` as rela co es entre os objetos. No dia-a-dia, quando se fala de heran ca, refere-se ` a transfer encia de propriedades de um pai aos seus lhos, ou seja, aquilo que e do pai passa a ser do lho. comum ainda o dito popular puxou o pai, que signica que o lho tem as mesmas E caracter sticas do pai. De uma maneira geral, as pessoas sabem que o lho assemelha-se ao pai, mas n ao s ao a mesma pessoa. Al em disso, o lho apresenta determinadas caracter sticas diferentes de seu pai. Veja a seguir outros exemplos: Um processador Pentium IV tem preservadas todas as caracter sticas do Pentium III, mas acrescentou mais mem oria cache (a mem oria cache j a existia, mas foi ampliada). Alguns modelos apresentam a tecnologia de Hyper-Threading que antes n ao existia. Uma placa-m ae nova apresenta a interface USB; trata-se de uma novidade que antes tamb em n ao existia. Na an alise orientada a objeto, heran ca e o mecanismo em que uma classe-lha herda automaticamente todos os atributos e m etodos de sua classe-pai (classe-base). Heran ca e a propriedade de podermos criar classes que se ampliam a partir de deni co es b asicas. De classes mais simples e gen ericas para classes mais complexas e espec cas. A heran ca permite criar classes-lhas implementando apenas os m etodos e atributos que se diferenciam da classe-pai. A maior vantagem do uso do conceito de heran ca est a associada ` a compreens ao de que os objetos que fazem parte da heran ca t em o mesmo comportamento, possibilitando um maior reaproveitamento de c odigo com conseq uente aumento da seguran ca. Existem dois tipos de heran ca: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
3.7. POLIMORFISMO
75
Heran ca simples ocorre quando uma classe herda as propriedades de uma u nica classe-pai. Heran ca m ultipla1 ocorre quando uma classe tem mais de um pai. Exemplo: heran ca de comportamento; muitas vezes dizemos que um menino herdou o jeito engra cado do tio e e estudioso como o pai, ou seja, o menino herdou caracter sticas comportamentais de mais de uma pessoa. Antecipando um pouco nosso estudo, veja na Figura 3.4 como representamos pela UML o conceito de heran ca. Observe que evolu mos de um rel ogio que s o tem hora para um rel ogio com hora e data. A seguir temos um rel ogio com hora, data e cron ometro. O nosso modelo mais moderno tem embutido uma calculadora. Observe que temos heran ca-m ultipla, uma vez que o rel ogio com calculadora e uma mistura de um rel ogio com uma calculadora. Figura 3.4: Uma hierarquia de rel ogios.
Relogio
+hora: int
Calculadora
RelogioData RelogioCalculadora
+hora: int +data: int +hora: int +data: int +tempoCronometro +calculadora: void
RelogioDataCronometro
+hora: int +data: int +tempoCronometro
Na Figura 6.12 a classe-base e Rel ogio. Esta possui um atributo, a hora, e dois m etodos usados para ler a Hora() ou acertar a Hora(int horaCerta). A classe Rel ogioAlarme e herdeira de Rel ogio, recebendo automaticamente os atributos e m etodos denidos em Rel ogio. Ademais, esta acrescenta o atributo horaAlarme, alarmeAtivo e os m etodos para ler e denir a hora em que o alarme deve tocar. Veremos na se ca o 6.4.10 como identicar heran cas usando AOO, e, na se ca o 6.4.11, como representar heran cas usando UML. No Cap tulo 17 Heran ca, veremos como implementar heran cas em C++, e no Cap tulo 18 Heran ca M ultipla, como implementar heran ca m ultipla. Nota: os termos classe-pai e classe-base s ao sin onimos. O termo superclasse indica a classe mais b asica de uma hierarquia. J a o termo classe-lha e sin onimo de classe-derivada.
3.7
Polimorsmo
A palavra polimorsmo signica muitas formas e representa o fato de uma determinada caracter stica (por exemplo, a pot encia do motor do ve culo) ser diferente para cada lho (tipo de ve culo). Quem j a andou de Volks e de Mercedes sabe bem a diferen ca.
1A
76
Na natureza, o conceito de polimorsmo e inerente ao processo de desenvolvimento; os seres evoluem, modicam-se. Por exemplo: o homo-sapiens e uma evolu ca o de seus ancestrais e tem atributos melhorados e atributos novos. Em suma, estamos partindo de um objeto mais simples e evoluindo, mas os conceitos do objeto-pai continuam a existir nos objetos descendentes, mesmo que tenham sofrido modica co es, aperfei coamentos e tenham assumido novas formas (polimorsmo). Para a AOO, polimorsmo e o processo de redeni ca o dos m etodos nas classes-derivadas. Os m etodos da classe-base s ao reescritos para realizarem as mesmas tarefas de uma forma mais especializada. O conceito de polimorsmo e fundamental para a an alise orientada a objeto; sua aplica ca o se fundamenta no uso de uma superclasse, por meio da qual vamos desenvolver nossa hierarquia de classes. Por exemplo: em um programa de simula ca o num erica utilizado para calcular a area de uma fun ca o, pode-se ter a evolu ca o dos m etodos de integra ca o. Do m etodo do Trap ezio para o m etodo de Simpson, para o m etodo de Gauss. O m etodo de Simpson e uma evolu ca o do m etodo do Trap ezio; seu algoritmo de c alculo e um pouco mais complexo, mais especializado, e apresenta resultados mais precisos. No Cap tulo 19 Polimorsmo, veremos como implementar o polimorsmo em C++.
3.8
Apresenta-se aqui, brevemente, outros conceitos relacionados ` a programa ca o orientada a objeto. Ao longo do livro estes conceitos ser ao reapresentados e detalhados com exemplos. Todos estes conceitos s ao suportados por C++, alguns deles s ao suportados por Java. Associado ao conceito de objeto temos os conceitos de inst ancia, identidade, persist encia e delega ca o: Inst ancia um outro nome que se d E a ao objeto e que, geralmente, refere-se a um objeto espec co. Identidade uma propriedade que permite identicar univocamente um objeto. Os objetos se distinE guem por sua pr opria exist encia, sendo distintos mesmo que todos os seus atributos sejam iguais, ou seja, existe um u nico identicador para cada objeto. Em C++ o endere co do objeto e seu identicador. Persist encia o tempo de vida de um objeto, podendo ser tempor E ario ou permanente: tempor ario quando ele s o existe durante a execu ca o do programa. Por exemplo: um objeto pode ser criado com new e destru do com delete; permanente quando ele e armazenado em um meio f sico, como o disco r gido. A vantagem dos objetos permanentes (persistentes) e que eles podem ser acessados por mais de um programa, pelo mesmo programa em uma outra ocasi ao, ou como um dep osito de dados (banco de dados). Delega c ao o mecanismo pelo qual um objeto transfere a execu E ca o de uma tarefa para outro. Veja a seguir outros conceitos relacionados ` a id eia de classe: Tipica c ao As classes representam os tipos de dados denidos pelo usu ario. A tipica ca o e a capacidade de o sistema distinguir as diferentes classes e resolver as convers oes. Veremos os Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
77
conceitos de tipos em C++ no Cap tulo 9 Tipos. Os conceitos de convers oes ser ao vistos no Cap tulo 25 Convers oes. Classica c ao Os objetos com a mesma estrutura de dados e com os mesmos m etodos s ao agrupados em uma classe. Todo objeto cont em uma refer encia impl cita ` a sua classe e sabe a qual classe pertence (identidade). Classes abstratas Uma classe e abstrata quando n ao e completa e n ao pode criar objetos, podendo surgir naturalmente ou pela migra ca o de m etodos das classes-derivadas para uma classe-base (gen erica). Uma classe abstrata costuma ser uma classe de interface. Veremos os conceitos de classes no Cap tulo 11 Classe. Protocolo o conjunto de m E etodos p ublicos da classe que podem ser acessados pelo usu ario, o conjunto de mensagens a que o objeto responde. O protocolo pode ser denido por uma classe de interface. Classes de interface Interfaces s ao classes abstratas que cont em apenas m etodos puros (n ao podem criar objetos). S ao utilizadas para mostrar ao usu ario a forma de acesso aos objetos. Veremos as classes de interface na se ca o 11.5.2. Responsabilidades Pode-se incluir na descri ca o da classe as suas responsabilidades pequenas frases que descrevem as obriga co es do objeto. Tamb em podemos incluir a descri ca o das colabora co es (veja na se ca o 6.10.2 o uso dos cart oes CRC Classe/Responsabilidade/Colaboradores). Veja a seguir informa co es adicionais sobre heran cas: Nomes de classe Em uma fam lia, os lhos e netos compartilham os nomes de seus ancestrais; da mesma forma, em uma hierarquia de classes, os nomes devem ser signicativos, semelhantes e esclarecedores. Superclasse Uma superclasse e a classe-base de uma hierarquia de classes; e a classe mais alta na hierarquia ( e a origem da arvore). Veremos como implementar heran ca em C++ no Cap tulo 17 Heran ca. Compartilhamento As t ecnicas orientadas a objeto facilitam o compartilhamento de c odigo por meio do conceito de heran ca. Al em do maior compartilhamento do c odigo, a an alise orientada a objeto reduz a codica ca o em fun ca o da maior clareza dos diagramas desenvolvidos. Veja a seguir informa co es adicionais sobre m etodos: Assinatura A assinatura de um m etodo e seu nome, a ordem e o tipo de seus par ametros. Observe que o tipo de retorno n ao faz parte da assinatura. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
78
Liga c ao est atica/din amica Liga ca o e o processo de identicar a posi ca o dos m etodos a serem executados. Na liga ca o est atica, o endere co dos m etodos e denido durante a compila ca o do programa. Na liga ca o din amica, o endere co dos m etodos e denido somente durante a execu ca o do programa. Sobrecarga de m etodos: O conceito de sobrecarga de um m etodo esta associado a preserva ca o do nome do m etodo, mesmo que este receba tipos ou n umero de par ametros diferentes. Por exemplo, um m etodo Soma() poderia realizar a soma de n umeros inteiros ou utuantes, sem a necessidade de se criar SomaInt() e SomaFloat(). Com o conceito de sobrecarga o programador tem de aprender a usar um n umero menor de m etodos, tendo um aumento de seu desempenho (veremos no Cap tulo 14 - Sobrecarga de M etodos, como implementar sobrecarga de m etodos). Sobrecarga de operador Algumas linguagens de programa ca o permitem a sobrecarga dos operadores, isto e, um operador + (soma) poderia ser reescrito para os diferentes tipos de objetos criados. Por exemplo: o programador pode denir um operador + que vai atuar sobre n umeros complexos. Veremos como implementar sobrecarga de operador em C++ no Cap tulo 21 Sobrecarga de operador. Cancelamento a substitui E ca o de um m etodo da classe-base por outro na classe-derivada. Pode ocorrer com os seguintes objetivos: cancelamento para extens ao (amplia ca o das tarefas que eram realizadas), cancelamento para restri ca o (quando a tarefa n ao e mais necess aria), cancelamento para otimiza ca o (quando se deseja aumentar o desempenho), cancelamento por conveni encia (quando o cancelamento pode ser conveniente por um motivo qualquer; deve ser evitado pois os m etodos n ao devem ser substitu dos com a nalidade de terem um comportamento diferente do esperado). Veja a seguir outros conceitos u teis: Friend (ou amizade) Um desconhecido n ao tem acesso ` a sua casa, aos seus bens pessoais. Um amigo pode entrar na sua casa e fazer uso de alguns objetos. A programa ca o orientada a objeto funciona da mesma forma. Voc e pode criar objetos diferentes e informar que um objeto A e amigo do objeto B, podendo acessar determinadas funcionalidades de B. Veremos a implementa ca o do conceito de amizade no Cap tulo 20 Friend. Ponteiros Em C/C++, um ponteiro e um objeto pequeno que aponta para outro objeto (que pode ser grande). Ponteiros s ao muito utilizados em C/C++ e ser ao vistos em detalhes no Cap tulo 15 Ponteiros, Refer encias e Gerenciamento de Mem oriae no Ap endice F Uso Avan cado de Ponteiros. Refer encias C++ acrescentou o conceito de refer encias, um tipo de apelido que substitui em grande parte o uso de ponteiros (veja como usar refer encias em C++ no Cap tulo 15 Ponteiros e refer encias). Convers oes Em um programa real e comum a necessidade de se converter um objeto de um tipo para Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
79
outro. Por exemplo: um determinado m etodo espera receber como par ametro um n umero utuante, mas o programador passou um n umero inteiro. Neste caso, o n umero inteiro vai ser convertido para utuante. Veremos como implementar convers oes em C++ no Cap tulo 25 Convers oes. Templates O conceito de template est a associado ao uso de programa c ao gen erica, a qual e extensivamente utilizada na STL Standard Template Library. Veja os conceitos de templates no Cap tulo 27 Templates (ou Gabaritos). A STL ser a vista a partir do Cap tulo 31 Introdu ca o ` a Biblioteca Padr ao de Gabaritos de C++ (STL). Exce co es O problema de erros em programas e sua solu ca o sempre foi complicado. O uso cada vez mais intenso de interfaces elaboradas e a necessidade de se terminar o projeto em tempo limitado provocam a ocorr encia de um n umero cada vez maior de erros em programas. Veremos como implementar solu co es para tratamento de erros utilizando os conceitos de exce co es no Cap tulo 26 Exce co es. Modularidade Um programa pode ser desenvolvido utilizando-se m odulos que podem ser compilados separadamente. Um m odulo costuma ser constru do a partir de um conjunto de classes relacionadas (geralmente um assunto). Em C++ os assuntos s ao empacotados com o uso da palavra-chave namespace; tamb em e usual separar a deni ca o das classes de sua implementa ca o (arquivos .h e .cpp). Pacotes Um pacote e um conjunto de classes mais fortemente relacionadas entre s . Costumam fazer parte do mesmo assunto. Evento Um evento pode ser um est mulo provocado por um sistema externo ou interno. Um evento provoca a mudan ca do estado de um objeto, representa uma a ca o que ocorre em determinado tempo e tem dura ca o zero. Atividade Uma atividade e uma opera ca o que demora um determinado tempo para ser executada. Sinergia Os conceitos da an alise orientada a objeto apresentam um efeito de sinergia (soma de qualidades), em que a soma dos diversos conceitos da AOO implicam em um resultado mais positivo que o esperado.
3.9
Neste cap tulo aprendemos alguns conceitos b asicos de OO, como a id eia da abstra ca o, que consiste em simplicar os sistemas eliminando detalhes, ou ent ao o conceito de encapsulamento ou ocultamento da informa ca o cujo objetivo e simplicar o objeto, permitindo ao usu ario ver apenas o que ser a efetivamente utilizado. Vimos ainda exemplos reais e imagin arios de classes e objetos, com suas propriedades e funcionalidades. Relembramos o conceito de heran ca e tivemos uma id eia do conceito de polimorsmo. No nal do cap tulo vimos um conjunto de conceitos que ser ao melhor descritos ao longo do livro. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
80
Apresentaremos, no Cap tulo 4 Modelagem Orientada a Objeto, o que e um modelo e porque usamos modelos, o que e a UML e quais seus diagramas. Veremos no Cap tulo 5 Engenharia de Software, o que e, quais as caracter sticas e alguns modelos conhecidos de engenharia de software. No Cap tulo 6 Etapas para o Desenvolvimento de um Programa, ser a apresentada em detalhes uma metodologia para desenvolvimento de programas orientados a objeto usando os diagramas da UML.
3.10
Exerc cios
1. Descreva, com suas palavras, os conceitos de: abstra ca o, classe, heran ca, atributos e m etodos. 2. Fale das vantagens de se usar o conceito de encapsulamento. 3. Descreva, de forma objetiva, as diferen cas entre classe, objeto e heran ca. 4. Descreva o que os objetos em cada uma das listas abaixo t em em comum (caracter sticas e a co es em comum). prateleira, estante, arm ario; moto-serra, faca, tesoura, estilete, machado; prego, parafuso, pino rebite; carro, caminh ao, trator, motocicleta; televis ao, monitor, display de c amera digital, display de lmadora. 5. Nas aplica co es a seguir s ao utilizadas estruturas de suporte. Para cada uma delas, fa ca uma lista de caracter sticas que sejam importantes e explique a import ancia de cada caracter stica para a aplica ca o. Estrutura met alica de um edif cio. Estrutura met alica de um avi ao. Estrutura met alica de uma plataforma de petr oleo. 6. Descreva as principais caracter sticas do paradigma de orienta ca o a objeto. 7. Fa ca uma r apida revis ao dos termos descritos neste cap tulo. Observe que s ao termos conhecidos, que voc e provavelmente j a utilizou, ou seja, a orienta ca o a objetos usa termos e conceitos conhecidos, facilitando seu entendimento e uso. 8. Porque devemos usar o conceito de abstra ca o sempre que temos de tratar um problema complexo?
Cap tulo 4
4.1
Introdu c ao ` a modelagem
Apresenta-se nesta se ca o o que e um modelo, tipos e exemplos e a raz ao pela qual usamos modelos.
4.1.1
O que e um modelo?
Um modelo e uma representa ca o da realidade; e uma liga ca o, uma ponte entre conceitos te oricos e observa co es [Aris, 1978]. O desenvolvimento de um modelo envolve o uso do conceito de abstra ca o, a vis ao do todo e de suas partes. Adaptando [Bender, 1978], podemos dizer que no desenvolvimento de um modelo devemos: i) formular as id eias precisamente [com clareza]; ii) ser concisos no uso da linguagem; e iii) identicar bibliotecas e sistemas dispon veis. Segundo [Bender, 1978], A teoria e util para obter conclus oes gerais dos modelos simples. Computadores s ao u teis para obter conclus oes espec cas de modelos mais complexos. Alguns modelos s ao focados em aspectos estruturais, como um projeto das funda co es e da estrutura de um edif cio. Outros modelos s ao focados na din amica e no comportamento do sistema, como, por exemplo, um modelo da din amica de um sistema de comportas 81
82
A ` MODELAGEM 4.1. INTRODUC AO (canal do Panam a), ou do funcionamento de um motor de combust ao. O uso de diferentes modelos estruturais/comportamentais nos permite ver os sistemas de diferentes formas; cada modelo, cada ator, fornece-nos vis ao/detalhamento de uma parte do sistema, [Sonerviile, 1993].
4.1.2
Veja a seguir alguns exemplos de modelos utilizados pelo homem. Colocamos uma classica ca o n ao-rigorosa indicando ser um modelo estrutural/din amico: Modelos estruturais Maquetes (maquete de uma casa, de um autom ovel). Mapas (mapa das ruas de uma cidade). Projetos (projeto de uma casa). Modelos matem aticos (equa co es diferenciais, fun co es, exemplo: y = f(x) = a + b.x ). Modelos multiescala (miniaturas, modelos reduzidos). Modelos din amicos Modelos f sicos/qu micos/biol ogicos (exemplo: a equa ca o do movimento retil neo uniforme). Modelos num ericos (exemplo: m etodo de integra ca o por Simpson). Algor tmos/uxogramas (s ao diagramas utilizados para representar a din amica de determinado sistema). Nota: de modo geral, um modelo matem atico M1 pode ser utilizado em diferentes areas, como a F sica, a Qu mica, a Biologia. Isto e, um mesmo conjunto de equa co es podem ser utilizadas para representar diferentes problemas [Aris, 1978, Bender, 1978].
4.1.3
O problema da linguagem, a necessidade de linguagens universais A engenharia civil utiliza com freq u encia modelos simplicados da realidade, como, por exemplo, plantas de edif cios e casas. As plantas s ao utilizadas por permitirem o entendimento de como a obra deve car depois de pronta; e o modelo utilizado pelo engenheiro (ou arquiteto) para se comunicar com o propriet ario, bem como com o mestre de obra. Assim, a planta viabiliza a troca de informa co es entre todos os envolvidos no projeto. Veja na Figura 4.1 tr es tipos de plantas usadas pelos engenheiros: uma fachada, uma planta baixa e uma planta isom etrica. Cada uma destas plantas procura destacar determinadas caracter sticas da casa. A fachada tem como objetivo mostrar como car a a frente da casa; a planta baixa, a disposi ca o dos ambientes da casa; a planta isom etrica, como ser ao dispostos os encanamentos de um banheiro. As plantas utilizadas pelo engenheiro/arquiteto t em como objetivo mostrar a estrutura e o funcionamento da casa e s ao utilizadas universalmente. Um engenheiro brasileiro, por exemplo, pode utilizar uma planta feita por um arquiteto russo para construir a casa de um indiano na China. Com rela ca o ao desenvolvimento de software, o uso de uma linguagem universal, como a UML e como a C++, facilita a troca de informa co es e c odigos entre os desenvolvedores. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
83
X
vaso
Cozinha Sala
Varanda
Fachada
Planta Baixa
(a) Fachada
O problema do custo Usamos modelos para reduzir custos. Antigamente, um carro novo era desenvolvido utilizandose prot otipos em tamanho real, a um custo muito elevado e com poucas varia co es e testes. Na pr atica, boa parte dos testes era feita pelos pr oprios propriet arios. Atualmente, um carro e feito valendo-se de modelos de computador, em um programa CAD, reduzindo consideravelmente o custo do desenvolvimento de novos modelos. Os modelos do carro s ao testados em simuladores. O problema da escala (conceito de escala) A maquete de uma casa e um modelo reduzido da casa, em uma outra escala. A vantagem do uso de modelos em escalas reduzidas e seu baixo custo. Por exemplo: o teste da performance aerodin amica de um carro, como um f ormula 1, e normalmente feito em um tunel de vento com modelos reduzidos. Com rela ca o ao desenvolvimento de um software, a quest ao da escala est a associada ao crescimento do software. A cada vers ao novos recursos s ao adicionados, e o uso de modelos permite a previs ao antecipada do crescimento do software. Nota: quando um modelo n ao muda ao modicarmos a escala do problema, dizemos que o mesmo e invari avel com rela ca o ` a escala [Aris, 1978]. Outras vantagens do uso de modelos Maior facilidade para testar uma entidade f sica antes de lhe dar uma forma nal. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
84
A ` MODELAGEM ORIENTADA A OBJETO 4.2. INTRODUC AO Maior facilidade na comunica ca o entre as diversas pessoas envolvidas (pela utiliza ca o de nota ca o uniforme). Redu ca o da complexidade dos sistemas. Possibilidade de testar o sistema em escalas reduzidas.
4.2
Agora que voc e j a sabe a import ancia dos modelos, vamos apresentar uma introdu ca o ` a modelagem orientada a objeto: o que e, quando surgiu e quais s ao suas vantagens.
4.2.1
Reveja a imagem da Figura 3.2; a vis ao do usu ario e diferente da vis ao do engenheiro. Da mesma forma, a vis ao de cada um dos participantes de um grupo de desenvolvimento de software e diferente. Para que nossa linguagem de comunica ca o seja uniformizada, precisamos utilizar a mesma base de informa co es, os mesmos conceitos. Paradigmas de programa ca o tradicionais, como o paradigma de programa ca o estruturada, ensinam-nos uma nova linguagem (centenas de conceitos novos e seus relacionamentos). Todos os programadores devem entender e utilizar esta nova linguagem. Contudo, a modelagem orientada a objeto elimina a necessidade de se aprender uma nova linguagem, pois a mesma e baseada em conceitos que j a conhecemos os objetos e seus relacionamentos. Isto ocorre porque, na modelagem orientada a objeto, os modelos da realidade s ao desenvolvidos tendo como fonte de inspira ca o os objetos. Segundo [Sonerviile, 1993], a modelagem orientada a objeto e baseada na oculta ca o de informa co es, nos objetos e seus relacionamentos. A modelagem orientada a objeto e os diagramas da UML Linguagem de Modelagem Unicada s ao criados e utilizados para permitir a todos os programadores uma vis ao uniforme do sistema que vai ser desenvolvido (da mesma forma que o projeto de uma casa). A modelagem orientada a objeto e um instrumento fundamental para o desenvolvimento de programas com qualidade.
4.2.2
Segundo [Fowler and Scott, 2000], os m etodos de an alise e projeto orientado a objetos surgiram entre 1988 e 1992, destacando-se: i) o enfoque em projetos recursivos de Sally Shlaer e Steve Mellor; ii) os trabalhos de Coad e Yourdan, [Coad and Yourdon, 1993]; iii) os cart oes CRC de Beck e Cunningham (1989); iv) as t ecnicas de Booch, [Booch, 1986]; v) o m etodo TMO - T ecnica de Modelagem de Objetos, de [Rumbaugh et al., 1994]; e vi) os casos de uso de Ivar Jacobson. No in cio existiam v arios m etodos de modelagem orientada a objeto, e uma disputa para ver qual seria o padr ao. Em 1997, o grupo de gerenciamento de objetos, conhecido como OMG Object Management Group, adotou a UML como linguagem-padr ao, o que provocou um impulso na aceita ca o da UML. Em outras palavras, a UML foi desenvolvida para unicar a nota ca o utilizada no desenvolvimento de softwares orientados a objeto. Hoje em dia a UML e utilizada universalmente para modelagem de software orientado a objeto, bem como para modelagem de sistemas em geral; ou seja, voc e pode usar UML para fazer seus softwares ou para auxiliar no desenvolvimento de projetos de engenharia. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
85
4.2.3
Segundo [Pressman, 2002], a modelagem orientada a objeto apresenta algumas vantagens inerentes: Reuso de componentes do programa. Desenvolvimento mais r apido e com melhor qualidade. Facilidade de manuten ca o, adapta ca o e amplia ca o. Veremos a seguir o que e a UML, suas vis oes, seus diagramas, elementos e estere otipos.
4.3
O que e a UML?
A UML e o padr ao utilizado para o desenvolvimento de modelos de software orientados a objeto. Como foi desenvolvida depois da TMO com a participa ca o de Rumbaugh, alguns diagramas utilizados na TMO foram preservados (mas ocorreram algumas altera co es). A UML estendeu a TMO acrescentando novas funcionalidades e novos diagramas, destacando-se os casos de uso. A TMO e descrita brevemente na se ca o 5.3.7. Segundo [Fowler and Scott, 2000], o c odigo e o meio preciso e detalhado, e a linguagem natural e muito imprecisa; UML seria ent ao o meio termo. A UML e uma linguagem visual que usa a id eia uma imagem vale mais do que mil palavras. A UML e uma linguagem de modelagem independente de processo. A UML e din amica; inova co es e ajustes s ao acrescentados a cada nova vers ao. A UML e o padr ao da ind ustria para modelagem de software orientado a objeto. A UML e extens vel, podendo ser adaptada ` as suas necessidades.
4.3.1
A seguir s ao apresentadas as diferentes vis oes da UML e os respectivos diagramas: Vis ao do modelo do usu ario mostra a vis ao do usu ario do sistema, sendo descrita principalmente pelos casos de uso. Diagrama de caso de uso (veja se ca o 6.1.2). Vis ao do modelo estrutural mostra a estrutura do sistema (equivale ao modelo de objetos do m etodo TMO). Diagrama de pacotes (veja se ca o 6.2.3). Diagrama de classes, atributos, m etodos (veja se ca o 6.4.4), associa co es (veja se ca o 6.4.6), agrega co es (veja se ca o 6.4.9), heran cas (veja se ca o 6.4.11), e depend encias (veja se ca o 6.4.15). Diagrama de objetos (veja se ca o 6.4.17). Diagrama de estrutura composta (veja se ca o 6.4.18). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
86
A UML? 4.3. O QUE E Vis ao do modelo din amico mostra a din amica e o comportamento do sistema, sua intera ca o com o usu ario e com sistemas externos (equivale ao modelo din amico e funcional do m etodo TMO).
Diagrama de seq u encia (eventos e mensagens) (veja se ca o 6.5.2). Diagrama de comunica ca o/colabora ca o (veja se ca o 6.5.3). Diagrama de m aquina de estado (estados do objeto) (veja se ca o 6.5.5). Diagrama de atividades (detalha as fun co es/m etodos) (veja se ca o 6.5.7). Diagrama de tempo (veja se ca o 6.5.8).
Vis ao de implementa c ao mostra aspectos estruturais do sistema relacionados ` as necessidades de implementa ca o (equivale em parte ao projeto do sistema do m etodo TMO).
Vis ao do modelo de ambiente mostra o ambiente-alvo e as necessidades para se colocar o sistema em funcionamento.
Veja na Figura 4.2 o relacionamento dos diagramas estruturais da UML. No exemplo apresentamos um sistema para simula ca o de um reservat orio de petr oleo ou de um po co. O diagrama de pacotes e o mais geral e representa todo o sistema. O diagrama de componentes inclui dentro dele os componentes do sistema (sub-sistemas, bibliotecas e m odulos). No exemplo inclu mos um componente biblioteca de simula ca o. O diagrama de classes mostra as classes, seus atributos, m etodos e o relacionamento entre as classes. Por m, a estrutura interna de uma classe pode ser representada em um diagrama de estrutura composta (inclu mos o diagrama de estrutura composta da classe SimPoco). Observe que estamos partindo do geral e descendo para o espec co, de uma vis ao macroestrutural, para uma vis ao microestrutural. Da mesma forma, a din amica do sistema tamb em e representada por diferentes diagramas (veja Figura 4.3). O caso de uso representa a vis ao mais simples da din amica do sistema, a vis ao do usu ario. Os diagramas de seq u encia e de comunica ca o ilustram a intera ca o entre os pacotes, os m odulos e os objetos. Observe no diagrama de comunica c ao que o usu ario cria um simulador, seleciona uma fun ca o e um objeto de integra ca o e em seguida solicita o c alculo da area da fun ca o a ser realizado pelo objeto de integra ca o (veja Figura 6.17 e 6.19). O diagrama de m aquina de estado (veja Figura 6.20) ilustra os estados de um objeto. Na Figura 6.20, o objeto integral est a recebendo a fun ca o, recebendo dados e calculando a integral. O diagrama de atividades, por sua vez, detalha o funcionamento de um m etodo, a descri ca o de uma atividade espec ca. A Figura 4.3 mostra o diagrama de atividades para o m etodo do Trap ezio, respons avel pelo c alculo da area de uma fun ca o (veja exemplo mais detalhado na Figura 6.25). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
87
Biblioteca matemtica
Biblioteca Simulao
Simulador
SimReservatorio
SimPoco
Simulao
88
Ator funo
recebendo funo
recebendo dados
Area=Area+f(x).dx/2
4.3.2
Os elementos da UML
Veja na Figura 4.4 um esbo co dos elementos da UML e observe que a UML tem um conjunto de elementos, como classe (ativa, inativa), gabarito/template, interface, pacote, componente, estado, nota, etiqueta, restri ca o, depend encia, associa ca o, generaliza ca o, agrega ca o/composi ca o, realiza ca o, colabora ca o, intera ca o, estere otipos etc. Veja na Figura 4.5 outros elementos utilizados pela UML, cujos elementos ser ao explicados em detalhes no Cap tulo 6 Etapas para o Desenvolvimento de um Programa. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
89
Classe
Classe
nota
associao
realizao
implementao objeto mensagem receptculo Fonte de evento dissipador de evento atividade estado Componente
note
Ator
incio
fim
ramo bifurcao
esteretipo
4.3.3
Lembre-se que esta e uma se ca o de n vel 2 e s o deve ser lida em uma segunda leitura do livro ou por usu arios experientes. Os estere otipos s ao apresentados nos diagramas da UML dentro de < <> > e s ao utilizados para estender as funcionalidades da UML ou para indicar alguma propriedade de um elemento da UML. Veja a seguir alguns exemplos de estere otipos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
90 Estere otipos para classes: persistente A classe e armazenada em disco ou em uma base de dados.
entity Representa uma classe que tem forte intera ca o com o sistema, recebendo e fornecendo dados [entidade]. boundary Representa uma classe de contorno, utilizada para intera ca o do sistema com elementos externos. Por exemplo, a classe que faz o acesso ` a impressora [contorno]. control Classe utilizada para controle de alguma atividade. Muitas vezes e utilizada uma classe < <control> > entre uma classe < <boundary> > e o sistema [controle]. interface Indica uma classe abstrata que tem apenas m etodos puros. A UML inclui cones especiais para indicar interfaces. bind Especica os tipos utilizados em uma especializa ca o. friend A classe-fonte tem acesso ` a classe-alvo [amigo]. instanceOf Indica uma inst ancia do alvo (usado em rela co es entre classes e objetos) [inst ancia de]. instantiate A classe-fonte cria objetos da classe-alvo. rene Indica ser mais detalhado/renado [rena]. use Indica depend encias de uso [uso]. become Indica ser o mesmo objeto mas com rela co es diferentes (em um estado diferente). call O fonte chama o alvo [chama]. copy Indica ser uma c opia independente [copia]. acess Indica acesso [acesso]. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
A UML? 4.3. O QUE E Estere otipos para atributos: const O atributo e constante, n ao muda. crescente O atributo e um valor crescente. decrescente O atributo e um valor decrescente. Estere otipos para m etodos: const O m etodo n ao altera os atributos do objeto [constante]. sequencial O m etodo n ao aceita acesso concorrente; o acesso deve ser seq uencial. concorrente O m etodo aceita acesso concorrente (processamento paralelo).
91
guarded O acesso concorrente e permitido, e o controle do acesso aos atributos internos e controlado pelo pr oprio objeto. alt Indica uma alternativa; e usado em estruturas de controle [alternativa]. opt Indica item opcional [opcional]. loop Indica um looping [la co]. Estere otipos para mensagens: create A mensagem solicita a cria ca o de um objeto [criar]. destroe A mensagem solicita a destrui ca o de um objeto [destruir]. call A mensagem chama determinado m etodo [chamar]. return Representa uma mensagem de retorno [retornar]. send Representa o envio de um sinal [enviar]. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
92 Estere otipos para associa co es: implicita A associa ca o est a impl cita. ordenada A associa ca o requer dados ordenados. modic avel A associa ca o pode ser modicada. crescente A associa ca o deve ser crescente. constante A associa ca o deve ser constante. Estere otipos para heran cas: implementation Implementa m etodos da classe-base [implementa].
complete A classe completa a hierarquia; a hierarquia est a completa [completa]. incomplete A hierarquia est a incompleta, faltam classes [incompleta]. Estere otipos para processamento paralelo/distribu do: processo Representa um processo do sistema. thread Representa uma thread do sistema. par Indica processamento paralelo. Estere otipos para caso de uso: extende Indica uma extens ao de um caso de uso [estende]. include Indica uma inclus ao de um caso de uso [inclui]. generalize Indica uma generaliza ca o de um caso de uso [generaliza]. Antes de apresentarmos em detalhes os diagramas da UML, vamos olhar rapidamente alguns programas que podem ser utilizados para gerar os diagramas, assim voc e poder a desenhar os diagramas enquanto l e o livro. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
93
4.4
Existem diversos programas para desenho dos diagramas da UML, entre os quais podemos citar: Rational Rose e um pacote prossional que, al em da montagem dos diagramas, per um pacote pago, dispon mite simultaneamente a implementa ca o dos c odigos. E vel para diversas plataformas no endere co http://www.rational.com. With Class e um pacote prossional, que, al em da montagem dos diagramas, per um pacote pago, dispon mite simultaneamente a implementa ca o dos c odigos. E vel para diversas plataformas no endere co http://www.microgold.com/index.html. Dia o modelador dia e muito simples de usar, e software livre e ser a descrito na se ca o 4.4.1. Pode ser obtido em http://www.gnome.org/gnome-office/dia.shtml. Umbrello o modelador umbrello tamb em e muito simples de usar, e software livre e ser a descrito na se ca o 4.4.2. Pode ser obtido em http://uml.sourceforge.net/index.php. Visual Paradigm pacote prossional, com vers ao livre. Ser a descrito na se ca o 4.4.3.
4.4.1
O programa Dia
Parte dos diagramas UML apresentados neste livro foram criados utilizando-se o programa dia, um software livre utilizado para a cria ca o dos mais diversos tipos de diagramas. Veja a seguir uma lista com alguns dos diagramas deste programa: AADL, Cibern etica, Circuitos, equipamentos cisco, engenharia civil, engenharia el etrica, engenharia qu mica, EML, ER, uxograma, cronograma, estrutura funcional, Gane e Sarson, GRAFCET, Lader, l ogica, mapa isom etrico, Miscel aneas, MSE, pneum atico/hidr aulico, rede, rede Jackson, rede KAOS, SADT/IDEF0, SDL, Sybase e, por m, UML. A tela do programa dia e ilustrada na Figura 4.6. Observe que a lista de componentes UML ` esquerda vemos a janela de controle do dia. Observe, na parte superior, est a selecionada. A cones gerais como: sele ca o, aproximar, mover, caixa, elipse, poligono, bezier, linha, arco, zig-zag, polilinha, curva B ezier e inser ca o de gura. No meio da tela de controle temos os elementos da UML, como: classe, modelo, texto, depend encia, interface, heran ca, associa ca o, agrega ca o, implementa ca o, restri ca o, pacote, ator, caso de uso, linha de vida, objeto, mensagem, componente, observa ca o, recept aculo, fonte e dissipador de eventos, n o, estere otipo, estado, atividade, remo, bifurca ca o e transa ca o. Finalmente, na parte de baixo da tela de controle do dia temos: cor de frente e de fundo, espessura da linha, tipo da linha e formato das pontas (setas). Veja nas Figuras 4.4 e 4.5 um esbo co dos elementos da UML disponibilizados pelo programa dia, o qual pode ser obtido no endere co http://www.gnome.org/gnome-office/dia.shtml. N ao e nosso objetivo abordar a utiliza ca o desse programa, e um pequeno manual dele poder a ser obtido em http://www.lysator.liu.se/~alla/dia/ e http://www.togaware.com/ linuxbook/dia.html. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
94
Figura 4.6: O programa dia manipulando uma estrutura UML com representa co es de classes.
4.4.2
O programa umbrello
O programa umbrello e um modelador UML distribu do juntamente com o KDE nas diversas um programa f distribui co es GNU/Linux. E acil de usar e que tem a vantagem de gerar o c odigo dos programas a partir do diagrama de classes. O c odigo pode ser exportado e importado para as seguintes linguagens:
C++, Actionscript, Ada, IDL, Java, JavaScript, Pascal, Perl, PHP, Python, Ruby, SQL, TCL, XMLschema.
Veja na Figura 4.7 a tela do modelador umbrello mostrando um diagrama de componente, e na Figura 4.8, um diagrama de classes. No site http://uml.sourceforge.net/index.php, voc e pode baixar o umbrello, cujo manual j a est a dispon vel em portugu es. . Se voc e usa GNU/Linux, abra um terminal e digite umbrello . A seguir v a em Ajuda>Manual do modelador UML umbrello (ou simplesmente pressione F1).
Dica: no programa umbrello, quando modelar uma associa ca o, indique na linha da associa ca o o nome do papel. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
95
Figura 4.8: A tela do programa umbrello um diagrama de classes. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
96
Nota: veremos na se ca o 6.8.2 como montar o c odigo inicial do programa com o Umbrello.
4.4.3
O programa Visual-Paradigm
O Visual-Paradigm, ilustrado na Figura 4.9, e uma interface de modelagem UML propriet aria. Pode estar integrado a alguns sistemas de desenvolvimento como o Eclipse/IBM, JBuilder, NetBeans/Sun, entre outros. O Visual-Paradigm tem uma vers ao aberta para uso individual e n ao prossional (vers ao com recursos limitados). Tamb em tem uma vers ao standard aberta para comunidade acad emica, com licen ca v alida por um ano. Para obter uma c opia do Visual-Paradigm acesse o site http: //www.visual-paradigm.com/.
4.5
Neste cap tulo aprendemos que um modelo e uma descri ca o simplicada e reduzida da realidade cuja vantagem est a associada ao seu baixo custo e ao uso de uma linguagem universal. Vimos que os modelos (estruturais ou din amicos) podem ser utilizados para nos ajudar a solucionar os mais variados problemas da engenharia. Aprendemos que a id eia da modelagem orientada a objeto e desenvolver modelos tendo como foco o conceito de objeto. A modelagem orientada a objeto surgiu ao longo dos anos de 1980 e cou madura nos anos de 1990 com o surgimento da UML, um sistema de modelagem que Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
97
unicou as antigas nota co es. No nal do cap tulo vimos o que s ao e como obter programas modeladores como o dia e o umbrello. No Cap tulo 5 Engenharia de software, veremos os conceitos b asicos de engenharia de software e uma descri ca o de modelos e processos utilizados para o desenvolvimento de sistemas de softwares. Dica: todos os diagramas da UML aceitam a inclus ao de notas, as quais s ao utilizadas para adicionar qualquer tipo de descri ca o a respeito do modelo que est a sendo desenvolvido, ou para detalhar algum aspecto que possa estar confuso. Nota: conceitos b asicos de modelagem s ao encontrados nas refer encias [Aris, 1978, Bender, 1978, da Silva Neto and Neto, 2005].
4.6
Exerc cios
1. Descreva, com suas palavras, o que e e para que servem os modelos. 2. Descreva, com suas palavras, o que e um paradigma. 3. Cite exemplos de modelos (estruturais e din amicos). 4. Qual a diferen ca entre a vis ao estrutural e a vis ao din amica? 5. Instale em seu computador uma ferramenta de modelagem (exemplo: umbrello ) e leia o manual do software instalado. 6. Monte alguns exemplos de diagramas utilizando a ferramenta de modelagem escolhida. 7. A Figura 4.3 mostra um diagrama de atividades para c alculo da area de uma fun ca o. O diagrama usa uma vari avel x que e comparada com xmax. Troque o uso de x pelo uso de um contador i. 8. Comente a deni ca o de modelo matem atico de [Bender, 1978], Um modelo matem atico e uma abstra ca o, simplicada, uma constru ca o matem atica relacionada ` a parte de uma realidade, sendo criada com um prop osito particular. Como reescrev e-la considerando aspectos computacionais?
98
Cap tulo 5
Engenharia de Software
Neste cap tulo apresentaremos os conceitos b asicos de engenharia de software e uma descric a o de modelos e processos utilizados para o desenvolvimento de sistemas de softwares. Iniciaremos com a deni ca o do que e e quais s ao os objetivos da engenharia de software (se ca o 5.1). Em seguida, apresentaremos um breve hist orico da engenharia de software (se ca o 5.2) e suas caracter sticas gerais (se ca o 5.3). Apresentaremos ent ao os diferentes modelos: Modelo seq uencial linear (se ca o 5.3.1). Modelo iterativo (se ca o 5.3.2). Modelo baseado em prototipagem (se ca o 5.3.3). Modelo RAD Rapid Application Development (se ca o 5.3.4). Modelo incremental (se ca o 5.3.5). Modelo espiral (se ca o 5.3.6). Modelo TMO (se ca o 5.3.7). Modelo UP (se ca o 5.3.8). Modelo XP (se ca o 5.3.9). Finalizaremos apresentando o modelo selecionado (se ca o 5.4). Nota: na literatura especializada, esses modelos s ao tratados como modelos, t ecnicas ou processos. Usei o nome uniforme de modelos, uma vez que a palavra t ecnica se refere a aplica ` ca o pr atica dos modelos, depois de estes terem sido testados e consolidados. J a a palavra processo se refere a uma seq u encia espec ca. Como a apresenta ca o neste cap tulo e breve e simplicada, a palavra modelo e mais adequada.
5.1
A engenharia de software estuda e desenvolve modelos para o desenvolvimento de softwares considerando as caracter sticas b asicas de um sistema de engenharia, isto e, conceitos como 99
100
especica ca o, an alise, projeto, testes, documenta c ao, execu ca o e controle. Inclui ainda itens como an alises de custo, divis ao e montagem de equipes, automatiza ca o de processos etc. Um dos objetivos b asicos da engenharia de software e gerar softwares com qualidade. A Norma Qualidade de Software (ISO/IEC 9126: NBR 13596) inclui as seguintes deni co es: Funcionalidade satisfaz as necessidades. Conabilidade e imune a falhas. Usabilidade e f acil de usar. Eci encia e r apido. Segundo [Teles, 2006], o relat orio The Chaos Report identicou que mais de 70% dos projetos de software falhamem raz ao de fatores como: consomem mais recursos do que o planejado. consomem mais tempo do que o planejado. n ao entregam o combinado. todos os tens acima. Outro aspecto interessante e que apenas 67% das funcionalidades prometidas s ao entregues. Das funcionalidades implementadas, 45% nunca s ao utilizadas e 19% raramente o s ao, ou seja, cerca de 64% de todo c odigo escrito n ao e utilizado. Fica evidente a necessidade de melhoria da comunica ca o, principalmente com o cliente, mas tamb em entre os membros da equipe de desenvolvimento. Esses dados demonstram a necessidade de se adotar um modelo de engenharia de software que se adapte de forma mais eciente aos novos tempos e ` a sua equipe de desenvolvimento. Nas pr oximas se co es apresentaremos um breve hist orico da engenharia de software e v arios modelos utilizados ao longo dos u ltimos anos, incluindo os recentes UP e XP.
5.2
Os primeiros modelos de engenharia de software foram desenvolvidos para linguagens estruturadas, como C e Fortram, e s ao apresentadas em detalhes nas refer encias [Martin and McClure, 1993, Sonerviile, 1993, Pressman, 2002]. Com o surgimento da programa ca o orientada a objetos, desenvolveram-se os primeiros m etodos de modelagem orientada a objetos, os quais foram idealizados e aperfei coados por autores como Coad, Yourdan, Grady Boock, James Rumbaugh, Blaha, Premerlani, Eddy, Lorensen e Ivar Jacobsen. Cada um desses autores desenvolveu uma metodologia de modelagem diferente. Posteriormente, os m etodos de Boock, Rumbaugh e Jacobsen foram unicados na UML Unied Modeling Language ou linguagem de modelagem unicada, descrita na se ca o 4.3. Apresentaremos na se ca o 5.3 alguns conceitos relacionados a diferentes modelos, metodo importante destacar que existem logias, t ecnicas e processos de engenharia de software. E diversos modelos de engenharia de software; cada analista, programador, equipe de desenvolvimento deve escolher o modelo que mais se adapta ` as suas necessidades e ` as suas pr oprias caracter sticas. Segundo [Fowler and Scott, 2000], n ao existe um processo ideal; a deni ca o do melhor modelo depende do tipo de software e do tamanho da equipe de desenvolvimento. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
101
5.3
Uma an alise r apida dos diferentes modelos de engenharia de software nos leva ao entendimento de que todos seguem os paradigmas b asicos da engenharia, isto e, conceitos como especica ca o, an alise, projeto, testes, documenta c ao, execu ca o e controle, e que as diferen cas de um modelo em rela ca o ao outro se devem ` as especicidades das equipes e dos sistemas a serem desenvolvidos. Apresenta-se aqui uma lista de conceitos que s ao comuns aos diferentes modelos de engenharia de software e ao pr oprio senso comum, [Teles, 2006]: Necessidade de planejamento. Deni ca o clara e simplicada dos requisitos do sistema. Necessidade de comunica ca o constante entre os membros da equipe de desenvolvimento e com os clientes. Execu ca o do projeto com compartilhamento de responsabilidades (reuni oes constantes e objetivas, compartilhamento de c odigo, fazer primeiro o que e essencial). Quando identicado um problema (um bug, uma falta de padroniza ca o), tentar resolv e-lo o mais rapidamente poss vel. Controlar os sistemas desenvolvidos (inclui teste dos modelos, algoritmos e softwares desenvolvidos, elimina ca o dos bugs). Dividir as equipes de desenvolvimento em grupos compactos, coesos; aliar experi encia e mocidade. Manter as pessoas atualizadas com a realiza ca o de cursos, a leitura de artigos e livros. Desta forma, os desenvolvedores poder ao, pela refatora ca o ou reengenharia, atualizar os c odigos e algoritmos. Segundo [Pressman, 2002], independente do seu dom nio de enfoque, a engenharia de software abrange uma cole ca o de m etodos descendentes (top-down) e ascendentes (botonup).
5.3.1
O modelo seq uencial linear e um dos modelos mais antigos[Pressman, 2002] e envolve a execu ca o consecutiva das seguintes atividades: An alise, projeto, codica ca o e teste. Existem varia co es do modelo seq uencial linear. [Solter and Kleper, 2005] cita o modelo Stagewise Model, o qual inclui: Planejamento, desenvolvimento, implementa ca o, teste de integra ca o, teste de subsistema e avalia ca o. Entre os problemas do modelo seq uencial linear est a a diculdade do cliente em denir com clareza as especica co es do sistema. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
102
5.3.2
Modelo iterativo
Em 1970 surgiu o modelo iterativo, o qual consiste em realizar revis oes ap os cada etapa do modelo seq uencial linear. An alise->revis ao, projeto->revis ao, codica ca o->revis ao e teste->revis ao.
5.3.3
Segundo [Pressman, 2002], o modelo baseado em prototipagem consiste em criar um prot otipo do programa ap os a etapa de especica ca o do sistema. Ainda de acordo com [Pressman, 2002], na pr atica o prot otipo e descartado, sendo necess ario construir uma vers ao reprojetada. Outro problema deste modelo e que o cliente ao ver o prot otipo acha que o sistema est a quase pronto. O pr oprio programador pode achar que este e o melhor caminho.
5.3.4
O modelo RAD consiste em repetir ciclicamente todas as atividades do modelo seq uencial. A cada ciclo de 60 e 90 dias, desenvolve-se um m odulo diferente que e agregado ao sistema. adequado para aplica E co es em que seus subsistemas possam ser desenvolvidos completa inadequado para sistemas que envolvam novas mente dentro do per odo de 60 a 90 dias. E tecnologias (exemplo: centros de pesquisa, laborat orios de universidades).
5.3.5
Modelo incremental
O modelo incremental mistura os modelos seq uencial, de prototipagem e RAD. Por exemplo: no primeiro ciclo de montagem cria-se um n ucleo do sistema com funcionalidades b asicas. Novas funcionalidades s ao inclu das a cada ciclo. Note que a cada ciclo o sistema deve estar operacional. Este modelo e adequado para equipes pequenas e para centros de pesquisa (nos quais o n umero de pessoas envolvidas no projeto varia constantemente).
5.3.6
Modelo espiral
Em 1988, Barry W. Boehm apresentou o Spiral Method, que consiste em executar todas as atividades de forma iterativa, o que implica na constante revis ao das atividades anteriormente realizadas. A vantagem deste modelo e sua simplicidade, sendo simples de aprender e de utilizar. A diculdade est a em denir o tempo ideal para realiza ca o de cada ciclo. Observe que e um modelo iterativo e incremental. No modelo espiral as primeiras vers oes podem constar apenas do papel, e vers oes incrementais s ao desenvolvidas ao longo de cada ciclo. Segundo [Pressman, 2002], e um modelo realista para o desenvolvimento de sistemas e softwares de grande porte. As etapas a serem desenvolvidas em cada ciclo s ao: Comunica ca o com o cliente Planejamento An alise de risco Engenharia Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
5.3. CARACTER ISTICAS DOS MODELOS DE ENGENHARIA DE SOFTWARE Constru ca o e libera ca o Avalia ca o pelo cliente
103
A seguir ser a apresentado o modelo TMO, um dos primeiros modelos espec cos para o desenvolvimento de software orientado a objeto.
5.3.7
A TMO (ou OMT em ingl es) e um dos modelos de modelagem orientada a objeto que zeram mais sucesso. A TMO possui tr es modelos: Modelo de objetos a estrutura do sistema e modelada atrav es da constru ca o do diagrama de classes (inclui classes, atributos, m etodos, associa co es, agrega co es, heran cas, e depend encias). Modelo din amico a din amica do sistema, sua intera ca o com os usu arios e modelada atrav es dos diagramas de seq u encia (eventos e mensagens), de comunica ca o e de m aquina de estado. Modelo funcional a din amica das funcionalidades dos objetos e modelada pelo diagrama de atividade (detalha as fun co es/m etodos do objeto). Os tr es modelos s ao ortogonais, ou seja, complementam-se, e a maior import ancia de um em rela ca o ao outro depender a do tipo de programa desenvolvido. A TMO e discutida em detalhes em [Rumbaugh et al., 1994]. Veremos a seguir um breve resumo de duas metodologias mais recentes, a UP Rational Unied Process, e a XP eXtreme Programming.
5.3.8
Desenvolvida pela Rational Software, uma subsidi aria da IBM, o modelo UP foi criado pela mesma equipe que desenvolveu a UML. Entre as caracter sticas do modelo pode-se citar: uma metodologia que permite atualiza E ca o e renamento constante. Inclui um conjunto de programas e ferramentas utilizados por toda a equipe de desenvolvimento. Cada processo e um uxo de trabalho individual. Como os programas e ferramentas s ao pagos e caros, n ao e adequado para pequenas empresas. Veja a seguir as etapas do UP: Concep c ao deni ca o do escopo do projeto, prazos, custos. Elabora c ao na elabora ca o realiza-se um estudo mais detalhado sobre o sistema a ser elaborado (o qu e e como). Constru c ao montar um plano para a etapa de constru ca o que e realizada ciclicamente. Isto e, para cada caso de uso ou subsistema, realizam-se as atividades de an alise, projeto, codica ca o, teste e integra ca o. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
104
Transi c ao envolve a corre ca o de erros (bugs) e pode incluir otimiza co es. Itera c ao consiste em repetir as etapas anteriores. Observe que cada etapa de UP pode incluir uma ou mais itera co es e, em cada itera ca o, executase (com maior ou menor enfase) todas as atividades da engenharia de software: levantamento de requisitos, an alise, projeto, implementa ca o, testes e implanta ca o. importante lembrar que UP E e uma framework; cada equipe e cada projeto podem ser customizados de forma diferente. Por exemplo: projetos pequenos podem trabalhar somente com concep ca o, elabora ca o e transi ca o. Projetos maiores podem ter mais fases. Voc e encontra maiores detalhes sobre UP em [Kruchten, 2003].
5.3.9
O eXtreme Programming, conhecido como XP, foi desenvolvido em 1999 por Kent Beck. Veja a seguir as 12 regras de ouro deste modelo: O planejamento do sistema deve ser feito ao longo de todo o ciclo de desenvolvimento. Crie pequenas vers oes de seu sistema. Compartilhe a mesma arquitetura (vis ao do sistema). Simplique sua an alise (design). Evite criar sistemas excessivamente abstratos. Teste o sistema de forma constante. Pode-se, por exemplo, manter uma m aquina em tempo integral realizando testes automatizados. Considere a necessidade de se refazer determinadas partes do sistema na medida em que inova co es estejam ocorrendo (evite deixar seu sistema muito defasado). Crie duas equipes de trabalho. Enquanto uma equipe desenvolve o m odulo do software, a outra equipe desenvolve o m odulo de teste e realiza os testes. Compartilhe o c odigo. Evite que os desenvolvedores se sintam donos de sua parte do c odigo. Todos devem poder alterar qualquer parte do c odigo. Mantenha o sistema integrado de forma cont nua. Novamente o sistema de dupla de trabalho deve ser utilizado para manter o sistema integrado. Evite que a equipe de desenvolvimento trabalhe mais do que 40 horas por semana. Comprovadamente o excesso de trabalho implica na adi ca o de bugs ao sistema. Incentive ou viabilize a participa ca o dos clientes/usu arios no uso e teste do sistema. Toda equipe deve, na medida do poss vel, usar uma mesma nota ca o (estabelecer padr oes de desenvolvimento). Segundo [Teles, 2006], as pr aticas de XP s ao denidas de forma clara, embora cada equipe de desenvolvimento deva decidir como aplic a-las. Voc e encontra maiores detalhes sobre XP em [Teles, 2006, Teles, 2004]. Consideramos que quase todos estes itens devem ser aplicados, mas particularmente discordamos dos seguintes pontos : Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
105
O planejamento do sistema deve ser feito ao longo de todo o ciclo de desenvolvimento. Neste caso, a tend encia e a equipe fazer um planejamento minimalista, com diversos furos; al em do mais, passa a id eia de que erros no planejamento possam ser resolvidos a qualquer momento. Simplique sua an alise (design). Evite criar sistemas excessivamente abstratos. A an alise deve ser detalhada e n ao simplicada. Os modelos devem ser desenvolvidos fazendo-se uma an alise criteriosa de cada aspecto do sistema a ser desenvolvido. Pequenos erros na an alise t em forte impacto na reimplementa ca o e provocam atrasos e descumprimento de prazos. Crie duas equipes de trabalho. um enfoque exagerado no teste (esta necessidade ocorre quando o planejamento e a E an alise s ao mal feitos). Dependendo do tamanho da equipe e da complexidade do sistema, uma rela ca o de dois ou tr es desenvolvedores para cada testador e mais do que suciente.
5.4
O modelo selecionado
O modelo de engenharia de software aqui apresentado e uma adapta ca o do modelo TMO, do modelo espiral, do modelo iterativo e de itens de UP e XP, aconselhada para pequenos grupos de desenvolvimento e laborat orios de pesquisa num erica. Novos conceitos de UP e XP podem ser integrados a esta metodologia ` a medida que seu grupo de trabalho aumenta. Tamb em eliminamos t opicos muito espec cos, tornando o uso da modelagem orientada a objeto mais f acil. A Figura 5.1 ilustra as diversas etapas a serem seguidas no desenvolvimento de um programa com o modelo aqui apresentado. Note que, sempre que se desenvolve um programa, essas etapas est ao presentes, mesmo que n ao sejam documentadas. As etapas iniciais s ao mais te oricas, conceituais, e cada nova etapa envolve maior detalhamento, ocorrendo uma migra ca o do te orico para o aplicado. Observe que o modelo e iterativo. Concep c ao (requisitos/especica c ao) Envolve a concep ca o/id eia do problema, a deni ca o de requisitos a serem satisfeitos e a especica ca o do sistema (descri ca o do objetivo e o que se espera do sistema a ser desenvolvido) (se ca o 6.1). Elabora c ao Etapa em que a equipe de desenvolvimento toma conhecimento mais detalhado da area e do problema a ser resolvido (veja se ca o 6.2). Identica os subsistemas e pacotes, e feita a an alise de riscos, levantamento de custos e prazos. An alise orientada a objeto AOO An alise do problema com o objetivo de identicar a estrutura do sistema (objetos, classes, atributos, m etodos), o relacionamento das classes (associa co es, agrega co es) e a din amica do sistema (veja se ca o 6.3). Projeto do sistema Deni ca o dos conceitos relativos ao sistema a ser implementado e escolha da plataforma do sistema: hardware, sistema operacional, linguagem de programa ca o e bibliotecas a serem utilizadas (veja se ca o 6.6). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
106
Projeto orientado a objeto Acr escimo ` a an alise desenvolvida das caracter sticas da plataforma escolhida, maior detalhamento do funcionamento do programa (veja se ca o 6.7). Implementa c ao do programa Transforma ca o do projeto em c odigo. Integrar os diversos m odulos, compilar e linkar (veja se ca o 6.8). Teste e depura c ao No teste vericamos se o programa satisfaz os requisitos. Devemos testar o programa ` medida que o programa realizando as tarefas usuais e depois as excepcionais. A e testado, os erros encontrados s ao corrigidos (veja se ca o 6.9). Documenta c ao Das especica co es, dos assuntos, das classes, das associa co es, dos m etodos e dos atributos. Descri ca o do c odigo para programadores. Cria ca o do arquivo de Ajuda [help] e dos manuais do programa (veja se ca o 6.10). Manuten c ao do programa Objetiva incluir aperfei coamentos e corrigir problemas (veja se ca o 6.11). Nota: embora o teste esteja representado como uma etapa estanque (por quest oes de did atica), ele deve ser realizado ao longo de todo o ciclo de desenvolvimento. Pessoalmente gosto de vericar e testar tudo o que j a desenvolvi a cada ciclo de itera ca o.
5.5
Vimos que o uso de um modelo de engenharia de software eu til para o desenvolvimento de softwares prossionais que aliem caracter sticas como funcionalidade, conabilidade, usabilidade e eci encia. Quando n ao usamos engenharia de software, ou usamos modelos inadequados, temos como conseq u encia a gera ca o de c odigos in uteis, nunca utilizados e geradores de bugs. Uma palavra nal sobre modelagem: escolha um modelo que se adapta ` as suas caracter sticas pessoais. Se voc e est a acostumado a desenvolver modelos, use um modelo como TMO (veja se ca o 5.3.7) ou o apresentado na se ca o 5.4. Se voc e gosta de ir mais r apido para a etapa de programa ca o, pense em usar XP (veja se ca o 5.3.9). Uma posi ca o intermedi aria e dada por UP (veja se ca o 5.3.8). No Cap tulo 6 Etapas de para o desenvolvimento de um programa, veremos passo-a-passo as etapas para o desenvolvimento de um programa utilizando uma metodologia mista, que envolve etapas do m etodo TMO, dicas dos m etodos espiral, iterativo, de UP e de XP.
5.6
Exerc cios
1. Pesquise no dicion ario os termos engenharia e software. 2. Quais as caracter sticas comuns aos diferentes modelos de engenharia de software? 3. Por que modelos baseados em prototipagem falham? 4. Quando devemos utilizar um modelo como o espiral? 5. Qual a diculdade para aplicar o modelo UP? Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
107
6. Por que XP falha em sistemas novos? Por que XP e adequado para o desenvolvimento de varia co es de sistemas existentes? 7. Fa ca uma an alise cr tica das 12 regras de XP. Por exemplo: o que signica fazer o planejamento ao longo de todo projeto? 8. Fa ca uma an alise cr tica do modelo de engenharia de software selecionado. Dica: voc e quer fazer um churrasco no domingo mas n ao sabe se vai ter sol? A dica do professor Nivaldo e ir at e o site do CPTEC, http://tempo.cptec.inpe.br/, e, em seguir, digitar o nome de sua cidade no campo :: Previs oes Digite o nome da Cidade . O site mostra a previs ao para hoje e para os pr oximos quatro dias e inclui: temperaturas m aximas e m nimas, hora do sol nascente e do sol poente, raios UV, e cones com previs ao de sol/chuva/nublado.
108
Cap tulo 6
110
Na etapa de projeto do sistema (se ca o 6.6), veremos a deni ca o da interface de programa ca o API (se ca o 6.6.1), a sele ca o da implementa ca o de controle (se ca o 6.6.2) e das plataformas a serem suportadas (se ca o 6.6.3). Aprenderemos quando usar e como selecionar bibliotecas externas (se ca o 6.6.4) e a biblioteca gr aca a ser utilizada GDI (se ca o 6.6.5), al em da sele ca o do ambiente de desenvolvimento integrado IDE (se ca o 6.6.6). Na etapa do projeto orientado a objeto (se ca o 6.7), veremos os diagramas de componentes (se ca o 6.7.1) e de implanta ca o (execu ca o) (se ca o 6.7.2). Na etapa de implementa ca o (se ca o 6.8), veremos conceitos relacionados ao teste de software (se ca o 6.9), ao porqu e de se testar (se ca o 6.9.1), ` a equipe (se ca o 6.9.2) e ` a metodologia de teste (se ca o 6.9.3). Finalmente veremos porque a documenta ca o dos programas e t ao importante (se ca o 6.10), al em do uso de cart oes CRC (se ca o 6.32), a manuten ca o (se ca o 6.11) e o reuso do software (se ca o 6.11).
6.1
Concep c ao especica c ao
A primeira etapa do desenvolvimento de um software e a concep ca o, a deni ca o de requisitos a serem satisfeitos e a especica ca o do sistema (descri ca o do objetivo e o que se espera do sistema a ser desenvolvido, o contexto da aplica ca o). Na concep ca o ocorre a primeira reuni ao da equipe de desenvolvimento com os clientes, quando e feita a especica ca o do software. O cliente por meio das especica co es e das entrevistas, passa para o analista id eias gerais de uso do sistema. O resultado da etapa de especica ca o e um conjunto formal de documentos e requisitos organizados pelo analista do sistema com apoio dos usu arios. As especica co es denem as caracter sticas gerais do programa, aquilo que ele deve realizar e n ao a forma como ir a faz e-lo. Denem as necessidades a serem satisfeitas. Envolvem a sele ca o do tipo de interface (modo texto ou gr aca), a forma de intera ca o com o usu ario (teclado, mouse); se vai ter uma ou m ultiplas janelas; se o programa vai imprimir seus resultados, o formato dos arquivos de disco; se vai existir um helpe seu formato. Podem ser especicadas caracter sticas de desempenho. O cliente dene o que deve obrigatoriamente ser satisfeito e o que e opcional isto e, tudo o que o software deve ser. As especica co es devem ser bem feitas, porque s ao a base para a etapa de an alise orientada a objeto (veja se ca o 6.1.1). Cuidado com ambig uidades e com termos vagos nas especica co es; seja claro. Observe que os diagramas de caso de uso podem ser utilizados na etapa de especica ca o (veja se ca o 6.1.2). Fa ca o teste das especica co es (veja a se ca o 6.9, sobre teste de software). Na medida do poss vel, ap os a an alise de dom nio (veja se ca o 6.2.1), os limites do sistema e os atores externos devem estar claros. Dica: a comunica ca o com o cliente pode ser melhorada com o uso de met aforas, como, por exemplo, a met afora da lixeira. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
111
6.1.1
Segundo [Blaha and Rumbaugh, 2006], um cen ario pode ser um registro hist orico de execu ca o de um sistema real ou um experimento de execu ca o te orica de um sistema proposto. Um caso de uso descreve um ou mais cen arios de uso do software, exemplos de uso, como o sistema interage com usu arios externos (atores). Ademais, ele deve representar uma seq u encia t pica de uso do programa (a execu ca o de determinadas tarefas-padr ao). Tamb em deve representar as exce co es, casos em que o usu ario comete algum erro, em que o sistema n ao consegue realizar as tarefas solicitadas. Segundo [Pressman, 2002], o caso de uso deve produzir uma descri ca o clara e n ao amb gua de como o usu ario nal e o sistema interagem um com o outro. [Pressman, 2002] diz ainda que uma vez denidos o ator e seu caso de uso, uma hierarquia de comandos e identicada. Devem ser montados diversos diagramas de caso de uso. Por exemplo: para cada cen ario, crie diagramas de seq u encia listando os objetos e os diversos eventos que partem de um objeto para outro (veja se ca o 6.5.2). A Tabela 6.1 mostra os itens a serem inclu dos na descri ca o do caso de uso, podendo-se ainda incluira lista de atores e as pr e-condi co es para execu ca o. O item etapas e opcional, pois elas podem ser inclu das diretamente no diagrama de caso de uso (veja se ca o 6.1.2) Uma vez apresentados os conceitos relacionados aos casos de uso, cen arios, apresentaremos como modelar os cen arios com os diagramas de caso de uso da UML. Tabela 6.1: Exemplo de caso de uso. Nome do caso de uso: Resumo/descri ca o: Etapas: C alculo da integral de uma fun ca o. Determina ca o da integral de uma fun ca o em um dado intervalo. 1. Criar objeto fun ca o. 2. Criar objeto de integra ca o. 3. Denir intervalo de integra ca o e n umero de pontos. 4. Calcular area da fun ca o. 5. Gerar gr acos. 6. Analisar resultados. Um cen ario alternativo envolve uma entrada errada do usu ario (por exemplo, a fun ca o e logar tmica, e o intervalo vai de -1 a 10). O programa apresentar a um bug quando for determinar o logar tmo de -1.
6.1.2
o diagrama mais O diagrama de casos de uso e uma representa ca o visual dos casos de uso. E simples da UML, sendo utilizado para demonstrar os cen arios de uso do sistema pelos usu arios, os quais ao verem esses diagramas ter ao uma vis ao geral do sistema. O diagrama de caso de uso pode ser utilizado durante e ap os a etapa de especica ca o, adicionando ` as especica co es textuais alguns cen arios de uso do programa a ser desenvolvido. A Figura 6.1 mostra um diagrama de caso de uso. O diagrama de caso de uso pode incluir: atores, elipses, generaliza co es, associa co es, pacotes, inclus oes, extens oes, notas e restri co es. Um ator e um boneco utilizado para representar um usu ario, um sistema, um hardware, Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
112
ESPECIFICAC 6.1. CONCEPC AO AO uma entidade que interage com o sistema. O ator comunica-se com o sistema somente com associa co es. Um diagrama de caso de uso pode incluir um ou mais atores.
Dentro das elipses s ao inclu das descri co es das etapas, a co es e opera co es que ser ao executadas pelo sistema. Uma elipse tamb em pode incluir um caso de uso, que ser a detalhado em outro diagrama ou em uma tabela (veja Tabela 6.1).
Um associa c ao entre um ator e uma elipse e representada por uma seta. A associa ca o pode ligar ainda dois atores e incluir estere otipos como < <extend> > e < <include> >. O diagrama de caso de uso geral da Figura 6.1 mostra o usu ario acessando os sistemas de ajuda do software, calculando a area de uma fun ca o ou analisando resultados. No exemplo da Figura 4.9, o caso de uso de Acesso ao sistema de ajuda e detalhado. Observe que ilustramos o acesso aos diferentes tipos de manuais que o usu ario poder a acessar. Figura 6.1: Diagrama de caso de uso um caso de uso geral.
O caso de uso Calcular area fun ca o descrito na Figura 6.1 e na Tabela 6.1 e detalhado na Figura 6.2. O usu ario criar a um objeto fun ca o matem atica, um objeto para sua integra ca o; em seguida, denir a o intervalo de integra ca o, calcular a a area da fun ca o criada e, por m, analisar a os resultados (eventualmente gerar a gr acos com os resultados obtidos utilizando um sistema externo, como o programa gnuplot ). Este diagrama de caso de uso ilustra as etapas a serem executadas pelo usu ario ou sistema, a itera ca o do usu ario com o sistema. Figura 6.2: Diagrama de caso de uso calcular area fun ca o.
Especializa c ao/Generaliza c ao
d C a s o e s o u : i l lc d i d j d i C A t t c e s o a s e m a e a o s e m a m p a r o a u u u . S F r e m n u l f C a c r n o u u lis lt d n a r e s a o s u io A A t o r s r u d a s o e s o u : C l f a c a r e a n o u u l f c a r a n o u C f i l i t t e n r e r a o n e g r a o v D d h ) t t e m . ( i b j d i t t r a o e o e n g r a o f i e r a g c o s C G lo t g n p u ia b je f t r o o n oA u lis lt d n a r e s a o s u C io A t o r s r u
Andr e Duarte Bueno
Em um diagrama de caso de uso, um ator ou um caso de uso (elipse) pode ser especializado/generalizado. Uma generaliza ca o de um caso de uso mostra que este pode ser realizado de uma forma mais espec ca. Funciona da mesma forma que heran ca em classes; o caso de uso geral deve ser abstrato, e os casos de uso herdeiros, espec cos. Veja na Figura 6.3 a generaliza ca o do ator respons avel por gerar os gr acos do sistema. Neste exemplo os gr acos poder ao Programa ca o Orientada a Objeto com C++
ser gerados pelos programas externos gnuplot, octave ou scilab. Da mesma forma como ocorre em heran cas, toda a estrutura e herdada e novas caracter sticas e varia co es comportamentais podem ser adicionadas. Figura 6.3: Diagrama de caso de uso: analisar resultados (uso de generaliza ca o).
Inclus ao
Quando um caso de uso e comum, o mesmo pode ser inclu do em outro. No exemplo da Figura 6.4, An alisar v arias fun co es, o usu ario ir a analisar v arias curvas, repetindo v arias vezes o caso de uso Analisar resultado. Observe que fazemos refer encia ao caso de uso Analisar resultados ilustrado na Figura 6.3 usando uma seta tracejada e o estere otipo < <include> >. Figura 6.4: Diagrama de caso de uso Analisar v arias fun co es (uso de inclus ao).
Analisar resultados <<include>>
d a s o e s o u : C l i l d t f i l i n a r a o s e r a c o s e n r a o z A G g A g f ) i d c m c c q e s u d f i e r a o e r c o s ( g g g d h t f d e m n r o s p m . l i l d t n a s r e s a o s u l s A l t n c a e u v , g i b o c a . i l b s c a i l i t t t m r e a r o o c a e v E io g t o r s r u lo t ? n p u A
113
Analisar vrias curvas/funes Ator-usurio
Extens ao Na Tabela 6.1, inclu mos uma excess ao, um caso de uso excepcional, o mesmo pode ser representado como uma extens ao do caso de uso da Figura 6.2. Veja na Figura 6.5, como representar uma extens ao do caso de uso Calcular area fun ca o, observe o uso do estere otipo < <extend> >, a inclus ao de uma elipse que lembra que o usu ario pode entrar com dados errados. Inclu mos ainda uma anota ca o lembrando a necessidade de se criar uma rotina para controle da entrada de dados. A seta tracejada aponta para o caso de uso que utiliza o caso de uso extendido. Um caso de uso < <extend> > pode ser descrito por uma anota ca o.
6.1.3
Os casos de uso fornecem uma vis ao externa do sistema (eventos externos) [Fowler and Scott, 2000]. Cada diagrama de caso de uso deve ter um nome u nico, indicado no canto superior esquerdo, dentro de uma nota. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
114
6.2. ELABORAC AO
Figura 6.5: Diagrama de caso de uso entrada de dados errada (uso de extens ao).
Caso de uso: Exemplo de extenso do caso de uso "Calcular rea funo" Calcular rea funo
<<extend>>
Segundo [Blaha and Rumbaugh, 2006], um ator deve ter um prop osito u nico e coerente. Um caso de uso pode ser generalizado, pode ser extendido. Use o estere otipo < <extended> > para indicar que o caso de uso e uma extens ao de outro caso de uso, e o estere otipo < <include> > para indicar que um caso de uso inclui outro. Deve-se criar um dicion ario com o nome dos casos de uso e uma breve descri ca o. Nome do caso de uso: Nome do caso de uso: Descri ca o/Resumo Descri ca o/Resumo
Um diagrama de caso de uso pode ser ampliado para incluir intera co es entre objetos do sistema, sendo tranformado em diagrama de comunica ca o (veja se ca o 6.5.3). Uma mesma pessoa pode representar mais de um ator em um sistema, devendo ser representado separadamente. Exemplo: um coordenador de curso de uma universidade tamb em costuma ser um professor. Observe que sistemas complexos podem ser utilizados por diferentes tipos de usu ario. Se isto ocorrer, inclua nos casos de uso os diferentes tipos de usu ario. Exemplo: alguns programas modicam sua interface em fun ca o do tipo de usu ario: iniciante, intermedi ario ou avan cado. Na UML 2, os elementos de um caso de uso podem incluir multiplicidades. Verique se as especica co es atendem aos requisitos b asicos da engenharia de software. Teste: quando nalizar a etapa de concep ca o, fa ca o teste das especica co es (veja item 1 na se ca o 6.9).
6.2
Elabora c ao
Depois da deni ca o dos objetivos, da especica ca o do software e da montagem dos primeiros diagramas de caso de uso, a equipe de desenvolvimento passa por um processo de elabora ca o que envolve o estudo de conceitos relacionados ao software a ser desenvolvido, a an alise de dom nio e a identica ca o de pacotes. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
6.2. ELABORAC AO
115
Na elabora ca o fazemos uma an alise dos requisitos, ajustando os requisitos iniciais de forma a desenvolver um sistema u til, que atenda a `s necessidades do usu ario e, na medida do poss vel, permita seu reuso e futura extens ao. Eliminam-se os requisitos imposs veis, e ajusta-se a id eia do sistema de forma que este seja ex vel, considerando-se aspectos como custos e prazos. Veja a seguir uma lista de atividades a serem realizadas na elabora ca o (veja Figura 6.6): Realizar a an alise de dom nio (veja se ca o 6.2.1). Identicar pacotes (assuntos) (veja se ca o 6.2.2). Montar o(s) diagrama(s) de pacotes (veja se ca o 6.2.3). Revisar as especica co es/requisitos do sistema deixando-os mais precisos, sem ambig uidades e inconsist encias, [Blaha and Rumbaugh, 2006].
6.2.1
A an alise de dom nio e uma parte da elabora ca o; seu objetivo e entender o dom nio, a abrang encia do sistema a ser desenvolvido. Envolve itens como estimar o reuso do software utilizando-se da cria ca o de bibliotecas gen ericas. Neste ponto, o analista pensa no sistema de uma forma mais gen erica, identicando conceitos fundamentais que podem ser reaproveitados em outros sistemas. Por exemplo: o uso ou o desenvolvimento de padr oes de projeto s ao etapas da an alise de dom nio (Veja Figura 6.6). Estudo dos requisitos/especica co es do sistema. Deni ca o e caracteriza ca o do dom nio a ser investigado ( area dos programas e bibliotecas a serem investigadas). Uma boa maneira de identicar os assuntos relacionados ao sistema que est a sendo desenvolvido e dar uma olhada nos livros, manuais e artigos da area. Manter contato com especialistas que tenham dom nio dos conceitos envolvidos. Segundo [Fowler and Scott, 2000], estas pessoas devem ser abertas, ter bastante conhecimento pr atico e estar dispon veis para perguntas. Deve-se fazer entrevistas com os usu arios do software (para detalhamento dos diagramas de caso de uso). Identica ca o de amostras (instalar e testar programas e bibliotecas similares). Na elabora ca o deve-se analisar a possibilidade de se reaproveitar projetos antigos (bibliotecas externas, programas existentes etc). Procurar as classes em bibliotecas existentes antes de implement a-las [Pressman, 2002]. Se a equipe de desenvolvimento j a tem experi encia com algumas bibliotecas (como a STL, bibliotecas da GNU, bibliotecas GPL), isto deve ser considerado. A id eia e reaproveitar o conhecimento legado. Identica ca o e deni ca o dos objetos gen ericos (a serem reutilizados). Talvez o aspecto mais importante da elabora ca o seja o contato com o cliente. Quando o cliente/usu ario tem uma no ca o b asica de como o sistema e desenvolvido, ele passa a fazer solicita co es que ser ao mais facilmente implementadas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
116
6.2. ELABORAC AO
Etapas da elaborao
Consulta a especialistas
Anlise de domnio
Consulta Bibliotecas Especialistas Entrevistas Analista Consulta Programas existentes Identificao e Montagem dos Diagramas de pacotes
6.2.2
Um assunto e aquilo que e tratado ou abordado em uma discuss ao, em um estudo e e utilizado para orientar o leitor em um modelo amplo e complexo. Se um grupo de classes troca muitas informa co es entre si, provavelmente as classes fazem parte de um mesmo assunto. Assim, classes que se relacionam por meio de conceitos em comum fazem parte de uma mesma area, s ao reunidas e formam um assunto (pacote). Em um pacote, os nomes de classes e de associa co es devem ser semelhantes. Preste aten ca o a semelhan cas na forma de c alculo. Procedimentos semelhantes indicam polimorsmo e s ao candidatos a superclasses. Usualmente a classe mais gen erica de uma hierarquia de classes identica um assunto. Em C++ e usual um pacote ser representado como umnamespace (os namespaces ser ao descritos no Cap tulo 10 Namespace). Dica: monte um diagrama de pacotes (assuntos, m odulos) (veja se ca o 6.2.3).
6.2.3
Um diagrama de pacotes eu til para mostrar as depend encias entre as diversas partes do sistema; pode incluir: sistemas, subsistemas, hierarquias de classes, classes, interfaces, componentes, n os, colabora co es e casos de uso. O exemplo da Figura 4.2 apresenta um diagrama de pacotes para um sistema de m etodos num ericos. Observe que o diagrama de pacotes inclui um pacote bibliotecas, o qual e dividido em bibliotecas matem aticas, de estat stica e de simula ca o. A seguir o componente biblioteca de simula ca o ser a detalhado. Outro exemplo de diagrama de pacotes e apresentado na Figura 4.7. O programa grafo depende da biblioteca grafo; a biblioteca lib lmpt depende das bibliotecas confeq, stl, grafo e TReconstru ca o. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
6.2. ELABORAC AO
117
6.2.4
Pode-se agrupar casos de uso dentro de um pacote. A refer encia a um elemento de um pacote em um diagrama deve incluir o nome do pacote (exemplo: NomeDoPacote::elemento). Dentro de um pacote n ao podem existir nomes repetidos. O nome do pacote pode ser igual ao nome da -superclasse. De um modo geral uma hierarquia de classes faz parte de um u nico pacote, e a superclasse deve ser uma classes de interface (abstrata). Depois de realizar a an alise de dom nio, identicar e montar os primeiros diagramas de pacotes, podemos montar um esbo co, um prot otipo da interface do software. Note que esta etapa e opcional.
6.2.5
O prot otipo da interface do software e uma vers ao simplicada do software que vai ser desenvolvido. No prot otipo, os cones, bot oes, menus e di alogos s ao implementados visualmente em um software do tipo RAD (como o qt-designer ). Observe que n ao existe o c odigo; existe apenas a casca externa do software, de modo que, ao pressionar um bot ao, nenhuma a ca o e realizada. Veja a seguir algumas dicas para montagem do prot otipo do software: Para iniciar a montagem do prot otipo, parta da interface de programas existentes, das especica co es do software, do conhecimento dos usu arios e procure fazer um prot otipo o mais simples poss vel. Como a interface e geradora de muitos eventos, ela deve servir de base para a montagem de diversos cen arios. Talvez seja necess ario montar novos diagramas de caso de uso. Todos os eventos identicados na elabora ca o do prot otipo foram devidamente considerados? Deve-se testar o prot otipo desenvolvido (veja se ca o 6.9, sobre teste de software). Finalizado o prot otipo, ele deve ser apresentado e testado pelos clientes. Obtenha um retorno dos usu arios, sua avalia ca o do prot otipo. Responda a quest oes como: i) ele responde ` as necessidades levantadas nas especica co es? ii) est a faltando alguma coisa? iii) a interface utilizada e adequada (usabilidade)? A Figura 6.7 mostra que os eventos gerados pelos atores (eventos do teclado, do mouse e de dispositivos externos como a entrada auxiliar) s ao tratados por um controlador. O controlador organiza a la de eventos e os distribui para os diferentes objetos do sistema. S ao mostrados ainda os eventos e mensagens gerados e trocados entre os objetos que comp oem o sistema. Teste: quando terminar a montagem do prot otipo fa ca o teste da interface (veja item 2, na se ca o 6.9.3). Ap os a etapa de elabora ca o an alise de dom nio, identica ca o e montagem dos diagramas de pacotes e a cria ca o do prot otipo da interface, eles devem ser documentados, organizados e apresentados ao cliente. Deve-se denir ainda quest oes como cronogramas, prazos e custos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
118
6.2. ELABORAC AO
Objeto
Objeto Objeto
6.2.6
As quest oes de prazos, montagem da equipe de desenvolvimento, custos, contrato, medi co es e controle das atividades desenvolvidas, entre outras, n ao s ao focos deste livro. Para maiores detalhes consulte as refer encias [Pressman, 2002, Martin and McClure, 1993, Emerson Rios, 2004, Sonerviile, 1993].
119
6.3
A terceira etapa do desenvolvimento de um programa e a AOO An alise Orientada a Objeto. A AOO utiliza algumas regras para identicar os objetos de interesse, as rela co es entre os pacotes, as classes, os atributos, os m etodos, as heran cas, as associa co es, as agrega co es, as composi co es e as depend encias. O modelo de an alise deve ser conciso, simplicado e deve mostrar o que deve ser feito, n ao se preocupando como isso ser a realizado. O resultado da an alise e um conjunto de diagramas que identicam os objetos e seus relacionamentos. A AOO envolve o desenvolvimento de doismodelos: O modelo estrutural (veja se ca o 6.4). O modelo din amico (veja se ca o 6.5).
6.4
O foco do modelo estrutural e a an alise da estrutura do sistema, dos objetos e de seus relacionamentos. Este modelo e desenvolvido em camadas; veja a Figura 4.2. Em uma primeira camada s ao montados os diagramas de pacotes (se ca o 6.2.3), mostrando o relacionamento dos dos m odulos e subsistemas. Em seguida, cada pacote e detalhado, incluindo-se os diagramas de componentes; em uma terceira camada s ao montados os diagramas de classes (se ca o 6.4.4, 6.4.6, 6.4.9, 6.4.11) e os diagramas de objetos (se ca o 6.4.17). Opcionalmente, em uma quarta camada, montamos os diagramas de estrutura composta (se ca o 6.4.18). Observe que a cada nova camada o n vel de detalhamento do sistema e maior. Na maioria dos programas o modelo estrutural e o mais importante, pois representa e identica os objetos e os relacionamentos que comp oem o sistema, sendo utilizado por ferramentas CASE, como o umbrello, para montar o c odigo inicial do programa. Como o modelo estrutural e constitu do de elementos que s ao facilmente reconhecidos tanto pelos clientes como pelos desenvolvedores, este modelo permite uma maior comunica ca o no desenvolvimento do programa. Veremos a seguir como identicar as classes (objetos) e como devemos montar os diagramas de classes usando UML. Nota: o modelo estrutural equivale em parte ao modelo de objetos da OMT.
6.4.1
Identica c ao de classes
Segundo a t ecnica de [Booch, 1986], podemos iniciar nossa an alise estudando as especicac o es do programa. Para encontrar candidatas a classes, pegue as especica co es e sublinhe os substantivos. Depois fa ca uma an alise mais detalhada das poss veis classes, eliminando as desnecess arias e acrescentando alguma outra que tenha surgido. Segundo [Booch, 1986], os verbos nas especica co es costumam referenciar m etodos (veja se ca o 6.4.3). Senten cas para identicar classes Veja se seguir um conjunto de dicas de [Johnson and Foote, 1998] que nos ajudam a identicar as classes. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
120
A nova classe representa uma abstra ca o signicativa para o dom nio do problema. Modelar com classes as entidades que ocorrem naturalmente no dom nio do problema. A classe e complexa. O conjunto de m etodos da classe e freq uentemente utilizado por outras classes. Se representada como um m etodo de uma outra classe, poucos usu arios desta classe a solicitariam. Senten cas para conserva c ao das classes corretas2 Veja a seguir um conjunto de dicas de [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006] que nos ajudam a eliminar as classes desnecess arias. Se a classe n ao estiver muito clara, se n ao se encaixar bem no problema, voc e deve elimin ala, ou encaix a-la dentro de outra. Se duas classes representam a mesma informa ca o, uma delas deve ser eliminada. Em uma associa ca o, costuma-se atribuir a cada classe o seu papel. O nome a ser dado ` a classe deve representar seu conceito b asico e n ao o papel que ela exerce em uma associa ca o. Se um atributo costuma ser acessado muitas vezes isoladamente, representando um conceito, e se for independente, transforme-o em uma classe. Conceitos relacionados ` a implementa ca o das classes devem ser inclu dos apenas na etapa de projeto (veja se ca o 6.7). Dica: revise o diagrama de classes (veja se ca o 6.4.4), incluindo as classes que foram identicadas.
6.4.2
Identica c ao de atributos
Os atributos devem ter nomes signicativos, devem representar uma propriedade do objeto, do dom nio da aplica ca o ou do mundo real. Segundo [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006], os atributos podem ser identicados por substantivos seguidos por frases possessivas como a cor da cadeira ou a posi ca o do cursor. Os adjetivos muitas vezes representam valores de atributos espec cos e enumerados. Um atributo derivado e aquele que e obtido a partir de outros atributos. Por exemplo: se voc e tem o raio de um c rculo, pode obter sua area e seu per metro. Neste caso, o raio seria um atributo normal; a area e o per metro seriam atributos derivados, os quais devem ter uma nota ca o diferente, mas n ao podem ser omitidos. Na etapa de projeto eles poder ao ser especicados por meio de um m etodo (um m etodo calcular aa area e outro, o per metro). Os atributos de associa ca o devem ser claramente identicados, pois existem em fun ca o de uma associa ca o entre dois ou mais objetos (veja a se ca o 6.4.7 e a Figura 6.10). Atributos coletivos (de classes ou est aticos) podem ser substitu dos com vantagens por classes associadas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
6.4. AOO MODELO ESTRUTURAL Senten cas para conserva c ao dos atributos corretos2
121
Segundo [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006], a conserva ca o dos atributos corretos envolve: Se o atributo for pouco descritivo, poder a ser eliminado da an alise e inclu do no projeto. Elimine da etapa de an alise todo e qualquer ag (valor booleano do tipo verdadeiro/falso). Se uma propriedade depende da presen ca de uma associa ca o, ent ao aquela pode ser implementada como um atributo da associa ca o (veja a se ca o 6.4.7 e a Figura 6.10). Se a classe apresenta grupos de atributos que parecem comportar-se isoladamente, pense em dividir a classe. Dica: revise o diagrama de classes, incluindo os atributos que foram identicados.
6.4.3
Identica c ao de m etodos
Se o objeto identicado na AOO e um objeto real, e f acil identicar suas opera co es, mas existem m etodos de dif cil identica ca o. Segundo [Booch, 1986], os verbos nas especica co es costumam referenciar m etodos. Adicionalmente, denir em que classe um determinado m etodo deve ser colocado nem sempre e um processo f acil. A pergunta e: onde devo colocar este m etodo? Em geral, um m etodo deve ser colocado na classe-alvo. Se existe uma classe mais afetada por determinado m etodo, o m etodo deve ser colocado nessa classe. A inclus ao de m etodos pode ser realizada a todo instante, sendo realizada com base em um dos conceitos expostos a seguir [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006]. Na etapa de modelagem, concentre-se no que o m etodo faz, n ao em como implement a-lo. Projeteos m etodos com um u nico objetivo. De modo geral, cada evento enviado a um objeto corresponde a um m etodo no objeto (veja a se ca o 6.5.2). A co es e atividades no diagrama de m aquinas de estados podem ser m etodos (veja a se ca o 6.5.5). De modo geral, cada fun ca o do diagrama de atividade corresponde a um m etodo (veja a se ca o 6.5.7). Senten cas para conserva c ao dos m etodos corretos2 Se um m etodo manipula dados externos mais do que os da pr opria classe, considere mud alo de classe. Se os m etodos realizam trabalhos semelhantes, eles podem fazer parte de uma heran ca. Projete um novo m etodo quando se defrontar com a alternativa de ampliar um j a existente. Evite m etodos extensos (m aximo 30 linhas). Armazene como atributos de classe os atributos que s ao necess arios a mais de um m etodo ou a uma classe-base. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
122
Evite a chamada de um m etodo em fun ca o do resultado de outro m etodo. Dica: inclua no diagrama de classes os m etodos que foram encontrados (veja a se ca o 6.4.4). Verique os efeitos no diagrama de m aquina de estado (veja a se ca o 6.5.5) e no diagrama de seq u encia (eventos) (veja a se ca o 6.5.2). Dica: veja na se ca o 6.11.4 senten cas para construir m etodos robustos.
6.4.4
Diagrama de classes
Iniciaremos aqui a apresenta ca o dos diagramas de classes, os quais ser ao utilizados para a montagem da vers ao inicial do c odigo do programa pelo uso de geradores de c odigo (como o Umbrello), devendo ser bem desenvolvidos e entendidos. No diagrama de classes constam as classes (se ca o 6.4.1), seus atributos (se ca o 6.4.2), m etodos (se ca o 6.4.3) e os relacionamentos entre as diversas classes, como associa co es (se ca o 6.4.5), agrega co es (se ca o 6.4.8), heran cas (se ca o 6.4.10), restri co es (se ca o 6.4.13), realiza co es (se ca o 6.4.14), e depend encias (se ca o 6.4.15). Pode incluir ainda interfaces, colabora co es e anota co es. Observe na Figura 6.8 a representa ca o UML de uma classe. No primeiro bloco vai o nome da classe (sempre no singular); no segundo bloco, os atributos, e no terceiro,os m etodos. Uma representa ca o mais detalhada dos atributos engloba sua visibilidade (+publico, #protegido ou -privado), seu tipo e valor. Os atributos de classe aparecem sublinhados. Da mesma forma, pode-se detalhar os m etodos, incluindo os par ametros, o retorno e o tipo de acesso. Veja que os atributos e m etodos podem ou n ao ser visualizados. Da mesma forma, detalhes como tipo de retorno de um m etodo, tipo e n umero de par ametros podem ou n ao ser visualizados. Uma classe gabarito (template) representa um conceito gen erico que pode ser implementado com diferentes tipos de objetos. M etodos e classes abstratas s ao representados em it alico. Classes persistentes s ao armazenadas em disco ou em uma base de dados e s ao identicadas no diagrama de classe com o estere otipo < <persistente> >. Figura 6.8: Diagrama de classes representando classes.
Diagrama de classe simples, classe template e abstrata. Diagrama de classe persistente detalhada com atributos e mtodos.
Nome da classe
Classe
<<persistente>>
ClasseAbstrata
Nome dos atributos +atributo Nome dos mtodos +Mtodo() Assinatura
Classe
+atributoPublico: tipo = valor #atributoProtegido -atributoPrivado +atributoDeClasse +... +Metodo(P1:Tipo=valor): TipoRetorno +MetodoDeClasse()
NomeTemplate:tipo <<esteretipo>>
Classe
+atributo +Mtodo() Diagrama de classe template
123
6.4.5
As associa co es representam relacionamentos estruturais (permanentes). Segundo [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006], uma rela ca o ou conex ao entre classes e uma associa ca o. Segundo esse autor, as associa co es correspondem muitas vezes a verbos est aticos ou locu co es verbais. O que inclui a posi ca o (com, parte de, contido em), as a co es (direciona), comunica co es (fala a), a posse (tem, parte de) e rela co es diretas (como trabalha para, casado com, gerencia). Uma liga ca o e uma inst ancia de uma associa ca o. Observe que a associa ca o aparecer a no diagrama de classes, e a liga ca o, no diagrama de objetos. As associa co es podem ser implementadas de v arias maneiras, mas as decis oes de implementa ca o devem ser mantidas fora do modelo de an alise. Veja a seguir exemplos de associa co es. Um jogador de futebol e uma bola s ao dois objetos independentes, mas se desejarmos um jogo de futebol, teremos esses dois objetos se relacionando, formando uma associa ca o. Quando um gerente solicita a um funcion ario a realiza ca o de uma determinada tarefa, existe uma associa ca o entre o gerente e o funcion ario. Senten cas para associa co es2 A UML representa associa co es n- arias utilizando losangos. As associa co es podem ser tern arias ou de ordem mais elevada, mas na pr atica a maioria e bin aria. Evite associa co es tern arias. N ao amontoe os atributos de uma classe de associa ca o em uma classe-alvo. Utilize associa co es qualicadas onde for poss vel. Evite associa co es 1:1; geralmente esta e uma associa c ao 1:0 ou 1:n, signicando que o objeto associado pode ou n ao existir. Como um nome de papel pode representar um atributo do objeto, ele n ao deve ter o mesmo nome dos atributos do objeto. Geralmente as associa co es s ao implementadas com a utiliza ca o de ponteiros, mas n ao devem ser representadas no modelo de objetos com ponteiros (veja o Cap tulo 15 Ponteiros e refer encias.). Uma rela ca o de uma classe consigo mesma e chamada de associa ca o un aria. Se uma associa ca o tem um lado com muitos elementos (*), mas estes s ao ordenados, podese utilizar o estere otipo{ordered}. O estere otipo {bag} indica um conjunto de objetos com repeti co es. O estere otipo {sequence} indica um conjunto de objetos ordenados com repeti ca o (como um <multiset>). Segundo [Blaha and Rumbaugh, 2006], os estere otipos {bag} e {sequence} indicam a possibilidade de liga co es m ultiplas para um par de classes. Em uma associa ca o qualicada, o objeto do lado muitos (*) pode ser identicado pelo atributo qualicador. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
124
Senten cas para conserva c ao das associa co es corretas2 Depois de denidas as associa co es, deve-se vericar quais foram denidas incorretamente e descart a-las segundo os crit erios a seguir, [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006]: Descreva com clareza o que e a associa ca o, e n ao o porqu e de ela ocorrer. Um evento transiente n ao pode ser confundido com uma associa ca o (exemplo: uma batida entre um carro e uma moto). Na medida do poss vel, classes, atributos e associa co es devem representar informa co es diferentes. Se faltam informa co es, os m etodos n ao percorrem a associa ca o, os pap eis s ao muito/pouco abrangentes, ent ao a associa ca o e desnecess aria. Evite associa co es tern arias (entre tr es objetos). Subdivida-as. Normalmente, uma associa ca o s o aparece em um diagrama; uma classe, por sua vez, pode aparecer em mais de um diagrama, mostrando a rela ca o entre os diferentes diagramas. Dica: revise o diagrama de classes, incluindo as associa co es que foram identicadas (veja se ca o 6.4.6).
6.4.6
Veja na Figura 6.9 como representar uma associa ca o. Observe que a associa ca o recebe um nome, podendo-se ainda denir o papel de cada classe que participa da associa ca o e sua multiplicidade. Se uma associa ca o for representada com uma seta, ela s o ser a executada na dire ca o da seta (unidirecional). Figura 6.9: Diagrama de classes representando associa c oes.
NomeAssociao papel de B nb papel de A na Representao de uma associao bidirecional.
Classe A
+atributo +Mtodo()
Classe B
+atributo +Mtodo()
Class D
NomeDependncia
Class C Class E
Representao de restries: Uma restrio impe uma dada condio ao relacionamento indicado.
Multiplicidade A multiplicidade e um tipo de restri ca o utilizada para indicar as quantidades de cada objeto em uma associa ca o (aparece no diagrama de classes). J a a cardinalidade indica Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
125
por meio de n umeros as quantidades de cada objeto em uma liga ca o (aparece no diagrama de objetos). Na Figura 6.9, a multiplicidade da classe A e nA (n umero de objetos do tipo A) e, da classe B, nB (n umero de objetos do tipo B). Os valores de multiplicidade podem ser: 1 1..n 1..* 0..1 2..7 0..* * um um a n um a innito 0 ou 1 no m nimo 2 e no m aximo 7 0 a innito innito
Papel Quando uma associa ca o n ao e clara, pode-se colocar no diagrama de classes o nome da associa ca o e/ou o nome do papel exercido por cada classe. Um papel e utilizado para indicar a forma como a classe vai atuar em uma associa ca o. Deve ter um nome un voco, normalmente um substantivo, que identique com clareza o papel que a classe exerce na associa ca o. Em alguns casos um papel e uma restri ca o ao objeto. Por exemplo: uma empresa tem tr es secret arias, uma cuida da agenda do chefe, as outras duas trabalham na recep ca o. Observe que as tr es s ao secret arias, mas o papel de cada uma e diferente. Restri co es Em um modelo de objetos as restri co es estabelecem rela c oes funcionais entre objetos, classes, atributos e associa co es. Como exemplo de restri co es, podemos citar a restri ca o de que o raio de um c rculo n ao ultrapasse determinado valor, a restri ca o de s o poder desenhar dentro da area cliente de uma janela. Um modelo de objetos bem desenvolvido deve ter muitas restri co es. Veja na Figura 6.9 que as restri co es aparecem dentro de colchetes {}. A Figura ?? mostra que o aluno s o ser a aprovado se obtiver nota maior ou igual a seis. Dica: se um atributo apresenta uma multiplicidade n, como em uma seq u encia, ent ao o mesmo poder a ser implementado utilizando um container da STL, como <vector> ou <deque>.
6.4.7
Classe de associa c ao
No relacionamento de dois objetos, pode surgir uma propriedade que n ao pertence a nenhum dos objetos originais, s o existindo quando ocorre a intera ca o. Por exemplo: na intera ca o do objeto telha (matriz s olida) com o objeto uido (chuva) surge a propriedade tens ao interfacial. A tens ao interfacial e uma propriedade da associa ca o. Veja na Figura 6.10 a ilustra ca o de uma classe de associa ca o. Em alguns casos, a classe de associa ca o n ao e criada, e seus atributos e m etodos s ao movidos para classe A ou B. Isto deve ser evitado na etapa de an alise, principalmente quando a associa ca o e do tipo *..* (muitos para muitos).
6.4.8
Quando unimos v arios objetos simples para criar um objeto mais complexo, estamos utilizando uma agrega ca o, tamb em denominada estrutura todo-parte. Diz-se todo-parte em que todo representa o objeto composto e parte, uma das partes que o comp oem. Podemos dizer ainda uma parte de ou tem um. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
126
Classe B
nome: tipo = valor
Classe de associao
+atributo: tipo = valor +Metodo(): tipo
Uma agrega ca o e uma propriedade transitiva, isto e, se A e parte de B e B e parte de C, ent ao A e parte de C. Uma agrega ca o e uma propriedade anti-sim etrica, ou seja, se A e parte de B, ent ao B n ao faz parte de A. Em alguns casos, os dois objetos s o podem existir simultaneamente. Uma agrega ca o pode ser recursiva, isto signica que um objeto pode conter um objeto de seu tipo. Se houver d uvida em rela ca o a um objeto ser ou n ao uma agrega ca o de outro, deve-se usar uma associa ca o. Composi c ao Uma composi ca o e uma agrega ca o forte, no sentido de que as partes s o poder ao ser constru das a partir do todo. No exemplo da Figura 6.11, um volante s o existiria como parte de um carro. Senten cas para conserva c ao das agrega co es e composi co es corretas2 Ser a uma agrega ca o se voc e usar a express ao parte de. Ser a uma agrega ca o se as opera co es executadas sobre um se propagarem para o outro. A propaga ca o ocorre quando uma opera ca o aplicada sobre um objeto se estende para os demais. Ser a uma associa ca o se os dois objetos forem normalmente considerados separados.
6.4.9
Veja na Figura 6.11 como representar agrega co es e composi co es. Observe que uma agrega ca o e representada com um losango na classe todo e uma composi ca o e representada como um losango cheio. Observe que podemos incluir o papel e a multiplicidade de cada classe. Tamb em podemos incluir um estere otipo.
6.4.10
Vimos na se ca o 3.6 o conceito de heran ca. A abstra ca o que utiliza o conceito de heran ca e poderosa, permitindo destacar o que e comum aos diversos objetos que comp oem a heran ca, sem deixar de levar em conta as suas particularidades. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
127
Porta
+atributo +Mtodo() 2-6 <<agregao>>
Volante
+atributo +Mtodo()
Parte
+atributo +Mtodo()
Todo
+atributo +Mtodo()
Carro
+atributo +Mtodo() (b)
(a)
Neste ponto, podemos renar o diagrama de classes incluindo o conceito de heran ca. Realize primeiro a generaliza ca o e depois a especializa ca o. Generaliza c ao A generaliza ca o (bottom-up ) e realizada identicando-se atributos e opera co es semelhantes. No exemplo da Figura 6.12, um rel ogio e uma generaliza ca o de rel ogio cron ometro e rel ogio alarme. Especializa c ao Especializa ca o e a cria ca o de classes-derivadas (lhas) a partir de uma classe-base (pai). As classes-derivadas t em acesso a todos os m etodos e atributos da classe-base. A especializa ca o (top-down ) pode ser vericada por meio de frases substantivas compostas por diversos adjetivos relativos ao nome da classe (exemplo: l ampada incandescente, l ampada uorescente). Uma especializa ca o pode ter um nome como e um tipo de ou e um. No exemplo da Figura 6.12, um rel ogio cron ometro e um tipo de rel ogio que foi especializado. Na especica ca o do sistema podem ter sido denidos alguns subcasos, os quais s ao candidatos a heran ` ca. Senten cas para conserva c ao das heran cas corretas2 Se uma classe inclu da na heran ca n ao e um tipo de, ent ao ela deve ser eliminada da heran ca. Se a classe foi inserida na heran ca apenas para aproveitamento de c odigo, ela deve ser eliminada. Lembre-se que modica co es na classe-base t em impacto nas classes-derivadas e devem ser feitas com cuidado. Senten cas para solucionar problemas de heran ca m ultipla2 Veja a seguir dicas de [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006] para solucionar problemas de heran ca m ultipla: Se uma classe tem mais de um pai, isto e, heran ca m ultipla, poderemos eliminar problemas utilizando mecanismos de delega ca o (transferir responsabilidades). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
128
Nos casos em que uma das classes-base e mais importante que as demais, podemos utilizar heran ca desta e delega ca o para as demais. Se uma das classes-base e o gargalo do desempenho, esta deve ser a superclasse. Dica: revise o diagrama de classes, incluindo as heran cas identicadas (veja se ca o 6.4.11).
6.4.11
Veja na Figura 6.12 como a UML representa as heran cas. Observe que a classe-base e mais gen erica, e as classes-derivadas s ao especializa co es da classe-base. A classe-derivada e um tipo de classe-base. Discriminador Em um diagrama de classes, um discriminador costuma indicar qual propriedade de um objeto est a sendo generalizada.
Base
+atributo +Mtodo() +MetodoAbstrato() Representao de uma herana. +hora
Relogio
+Hora(): int +Hora(int:horaCerta): void
<<Discriminador>> NomeHerana
RelogioCronometro
+tempoCronometro +TempoCronometro() +ZeraCronometro()
RelogioAlarme
+horaAlarme +alarmeAtivo +HoraAlarme(): int +HoraAlarme(horaCerta:int): void
Derivada_A
+atributo +Mtodo()
Derivada_B
+atributo +Mtodo()
(a)
(b)
RelogioCronometroAlarme
6.4.12
Na Figura 3.2 da se ca o 3.2, vimos que o encapsulamento envolve a separa ca o do que e vis vel ou n ao ao usu ario de um objeto. Esta separa ca o foi chamada de encapsulamento do objeto. O analista de sistema e respons avel por esta separa ca o, a qual envolve a identica ca o e deni ca o dos m etodos da classe que o usu ario poder a acessar. Esta deni ca o deve ser gen erica e consistente, pois erros no encapsulamento s ao trabalhosos para se corrigir. Depois de separar conceitualmente o que dever a ser p ublico e o que dever a ser privado, o analista usa, nos diagramas UML, o s mbolo + para indicar que o atributo/m etodo e p ublico (vis vel) e os s mbolos # e - para indicar, respectivamente, protegido (vis vel nas classesderivadas) ou privado (invis vel). Depois de feito o encapsulamento, temos denido de forma mais clara qual ser a a interface de acesso ao objeto. Neste ponto, a modelagem orientada a objeto disponibiliza o conceito de classe de interface. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
129
Uma classe de interface e uma classe gen erica, que s o tem m etodos vis veis e costuma ser utilizada como classe-base de uma hierarquia de classes. Veja na Figura 6.13 que a vis ao do engenheiro de software e mais detalhada que a vis ao do usu ario, o qual v e apenas o que n ao foi ocultado e que est a disponibilizado na classe de interface. Lembre-se, quando voc e faz um programa, voc e utiliza bibliotecas externas, feitas por outros programadores/analistas. Neste caso, voc e e o usu ario, e n ao importa os detalhes de como a biblioteca foi montada, o que interessa e sua forma de uso, sua interface. Como exemplo de classes de interface, veremos as classes <stack> (se ca o 33.1), <queue> (se ca o 33.2) e <priority_queue> (se ca o 33.3). Dica: uma superclasse e a classe mais b asica de uma hierarquia de classes; normalmente e uma classe de interface. Figura 6.13: Classe de interface.
Representao de uma classe de interface. A interface informa o que pblico e pode ser acessado pelo usurio. Eng. Software Viso do Engenheiro de software
NomeClasse
+atributoVisvel -atributoInvisvel +MtodoVisivel() -MtodoInvisvel() MtodoImplementacao ()
NomeClasse
+MtodoVisivel()
Uma classe de interface, no tem atributos, apenas mtodos pblicos. Usurio Viso do Usurio
A linguagem C++ permite a montagem de classes de interfaces e de classes abstratas. A diferen ca e que uma classe abstrata tem pelo menos um m etodo virtual puro, um m etodo que e declarado mas n ao e implementado. Como conseq u encia, uma classe abstrata n ao pode ser utilizada para criar objetos. Senten cas para elaborar classes abstratas2 Veremos a seguir dicas de [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006] para elaborar classes abstratas: Acesse todos os atributos de uma classe somente pelo envio de mensagens. As classes car ao mais abstratas quando dependerem menos das suas representa co es de dados. Identique mensagens e m etodos comuns e migre-os para uma classe-base. Isto pode criar a necessidade de quebrar m etodos e dividi-los entre classe-base e classes-derivadas. Elimineos m etodos de uma superclasse que s ao freq uentemente sobrescritos em vez de herdados por suas classes-derivadas. Isto torna a superclasse mais abstrata e conseq uentemente mais u til. Trabalhe classes-derivadas para serem especializadas. Uma classe-derivada ser a especializada se herdar todos os m etodos da clase-base e acrescentar novos a si pr opria. Uma classe-derivada sempre representa um superconjunto da classe-base. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
130
O conceito de fatora ca o envolve a cria ca o de sub-rotinas que ser ao acessadas por um m etodo da classe-base e ser ao implementadas de forma diferente pelas classes-derivadas. Subdivida um m etodo em sub-rotinas que ser ao diferentes para as diversas classes-derivadas. Dica: revise o diagrama de classes (veja se ca o 6.4.4), incluindo as classes abstratas que foram identicadas.
6.4.13
Restri c oes
Uma restri ca o e uma condi ca o booleana aplicada a atributos, m etodos, classes, associa co es e pacotes. Por exemplo: o atributo {umAluno.nota < = 10} tem como resultado um valor 0 ou 1. A porta de uma casa pode ser aberta se n ao estiver trancada (chaveada) ou se tivermos a chave. Observe que restri co es s ao colocadas dentro de chaves {}, podendo-se ainda estar descritas dentro de notas. A linguagem de restri co es de objeto (OCL Object Contraint Language) utiliza express oes como umRelogio.Hora(horaCerta) para percorrer/navegar sobre o conjunto de classes do sistema. A OCL e utilizada para identicar falhas e inconsist encias no sistema. Veja a seguir um exemplo de uma express ao OCL extra da de [Blaha and Rumbaugh, 2006]: umaContaCart ao.Extrato.Transa co es->Select(umaDataInicial == dataTransa ca o and dataTransa ca o <= umaDataFinal).
6.4.14
Realiza c oes
Uma realiza ca o e um tipo especial de heran ca em somente os m etodos s ao herdados. Normalmente uma realiza ca o e uma classe que implementa os m etodos declarados mas n ao denidos em uma classe de interface.
6.4.15
Depend encias
Como visto, as associa co es, agrega co es e heran cas representam aspectos estruturais das rela co es entre objetos. As depend encias representam rela co es de uso. Uma depend encia e representada por uma seta tracejada que parte da classe que executa o m etodo de interesse (exemplo: MinhaJanela - - ->biblioteca Qt), assim como mostra aFigura 6.30. Observe que se a classe MinhaJanela depende da biblioteca Qt, mudan cas na biblioteca Qt podem implicar em mudan cas na classe MinhaJanela.
6.4.16
Identica c ao de objetos
um conceito, Um objeto e simplesmente algo que faz sentido no contexto de uma aplica ca o. E uma abstra ca o, algo com limites n tidos e signicativos em rela ca o ao problema. Se a exist encia independente de uma entidade for importante e n ao apenas o seu valor, ent ao ela e um objeto. Neste momento voc e pode reler as se co es 2.1, 2.2 e 2.3. Dica: monte diagramas de objetos para testar o relacionamento dos diversos objetos (veja se ca o 6.4.17). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
131
6.4.17
Diagrama de objetos
O diagrama de objetos e basicamente o diagrama de classes, mas apresenta as inst ancias dos objetos criados, isto e, descreve os valores dos atributos assumidos por determinados objetos e seus relacionamentos em um dado momento. Serve para auxiliar os diagramas de comunica ca o em uma etapa de teste. Inclui itens como objetos e liga co es, notas, restri co es e pacotes. Veja na Figura 6.14 a representa ca o de um diagrama de objetos. Observe que o objeto pode estar ativo ou inativo, pode ser uma inst ancia simples ou m ultipla, pode ou n ao ter seus atributos descritos e pode incluir estere otipos. Qualicador usada na repreUm qualicador, uma qualica ca o inter-relaciona classes de objetos. E senta ca o das inst ancias da classe.
Objeto
<<esteretipo>> Objeto inativo (borda fina) instncia simples [estado explcito] atributos
<<esteretipo>> Objeto ativo (borda grossa) instncia mltipla [estado explicito] atributos
6.4.18
um diagrama estrutural usado O diagrama de estrutura composta foi inclu do na UML 2. E para detalhar o relacionamento dos elementos internos de uma classe, componente ou m odulo do constru sistema. E do a partir da composi ca o de elementos e pode ser utilizado para descrever o relacionamento dos atributos de classes complexas. Por exempo: dentro de uma classe Pessoa, como se relacionam as propriedades: endere co, telefone, e-mail, nome, idade, sexo etc. Veja na Figura ?? um diagrama de estrutura composta da classe de simula ca o de um reservat orio de petr oleo (SimReservat orio).
6.4.19
Vimos que o diagrama de classes e um diagrama em que constam as classes, seus atributos, m etodos, e relacionamentos. O diagrama de classes e o mais importante para o desenvolvedor pois e utilizado pelos programas modeladores, como o umbrello , para montagem do c odigo inicial do programa. Veremos como montar o c odigo inicial do programa usando o umbrello na se ca o 6.8.2. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
132
O diagrama de objetos e pouco utilizado, normalmente os diagramas de caso de uso s ao transformados em diagramas de comunica ca o, mostrando a rela ca o entre o usu ario e os objetos internos. O diagrama de estrutura composta foi introduzido a partir da UML 2 e objetiva detalhar as rela co es e comunica co es entre os atributos e m etodos de uma mesma classe, bem como os elementos internos do objeto se relacionam. Ademais, deve ser utilizado para detalhar o funcionamento de objetos complexos.
6.4.20
Itera c ao
Observe na Figura 5.1 que, ap os a cada etapa realizada, deve-se realizar uma itera ca o, a qual consiste em analisar as diversas etapas anteriormente realizadas, com o objetivo de encontrar e eliminar erros, de lembrar pontos esquecidos e de vericar a coer encia do modelo. Segundo [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006], os seguintes itens devem ser vericados: Identicados classes e objetos, voc e deve criar um dicion ario, com o nome de cada classe/objeto e a descri ca o em um par agrafo do que e e representa cada um deles. Verique se os casos de uso foram detalhados e se suas necessidades foram resolvidas. Verique se h a classes desnecess arias (sem atributos e m etodos). Verique se h a atributos e m etodos deslocados. Verique se os atributos e os m etodos s ao compat veis. Verique se os m etodos t em acesso; se n ao tiverem, est ao faltando associa co es. Verique se h a associa co es repetidas. Verique a presen ca de assimetrias nas associa co es e generaliza co es. Teste os diversos caminhos do modelo obtido para vericar sua consist encia e completude. Depois de corrigido o modelo, podemos agrupar as classes e os m odulos que t em algum sentido l ogico em comum em um diagrama (diagrama de pacotes). Se nos requisitos n ao foram inclu dos dados relativos ao desempenho do sistema, este e um bom momento. Classes, atributos, m etodos e associa co es criados foram documentados?
133
6.5
O modelo din amico e utilizado na descri ca o das transforma co es dos objetos em rela ca o ao tempo, preocupando-se com o controle da execu ca o, sua seq u encia. Representa a evolu ca o da execu ca o do programa, as respostas do programa aos eventos gerados pelo usu ario. Preocupa-se com aspectos como os eventos, as mensagens e suas seq u encias, as comunica co es e colabora co es entre objetos e subsistemas, as mudan cas de estados e a realiza ca o de atividades. Todo programa que envolva intera ca o e tempo, ou ainda interface gr aca com o usu ario e controle de processos, deve ter um bom modelo din amico, o qual pode ser constru do com diagramas de seq u encia (se ca o 6.5.2), de comunica ca o (se ca o 6.5.3), diagramas de m aquina de estado (se ca o 6.5.5) e diagramas de atividade (se ca o 6.5.7). Reveja o relacionamento dos diagramas do modelo din amico na Figura 4.3. Veja a seguir como identicar os eventos e mensagens e como implementar o modelo din amico e seus diagramas.
6.5.1
Um evento pode ser um est mulo externo provocado pelo usu ario ao pressionar o mouse ou ao selecionar um item de menu. Pode ser provocado por um outro programa ou pelo sistema operacional. Um evento induz a modica ca o do estado de um ou mais objetos, representa uma a ca o que ocorre em determinado tempo e tem dura ca o zero. Os eventos incluem toda e qualquer intera ca o do usu ario com o programa (sele co es de menu, entrada de dados, pressionamento do mouse etc.), decis oes, interrup co es, transi co es, a co es de ou para usu arios de dispositivos externos. Segundo [Blaha and Rumbaugh, 2006], os eventos freq uentemente correspondem a verbos conjugados no passado ou ao come co de alguma condi ca o. Uma mensagem especica uma comunica ca o entre objetos; s ao o meio pelo qual os objetos interagem, [Pressman, 2002]. Uma mensagem pode ser enviada de um objeto para outro, transferindo informa co es (inclui o objeto destino, o m etodo a ser executado e seus par ametros). Por exemplo: quando o usu ario clica no cone impressora ele gera um evento. O sistema que controla o processamento das entradas do usu ario associa a este evento uma mensagem que efetivar a a chamada do m etodo de impress ao. Senten cas para eventos Um evento e uma ocorr encia u nica, isto e, distinta das demais. Ocorre em um determinado momento; a hora em que determinado evento ocorre e um atributo do evento. Um evento n ao retorna um valor. Os eventos simples n ao transportam par ametros, mas a maioria transporta algum tipo de par ametro. Um evento pode ser gerado por um ator e se dirigir a um objeto, a um conjunto de objetos, ou a outro ator. Tamb em pode ser gerado por um objeto e ter como destino outro objeto ou ator. Os eventos podem ser agrupados segundo propriedades comuns. Voc e deve juntar os eventos que atuam de forma semelhante sobre o uxo de controle e dar-lhes nomes semelhantes, mesmo se os valores dos par ametros diferirem. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
134
Se dois eventos n ao s ao relacionados de forma causal, eles s ao chamados concorrentes um n ao tem efeito sobre o outro, n ao existe uma rela ca o temporal entre eles (ordem de execu ca o).
Nossa an alise e que transforma um determinado evento em um evento de erro, ou seja, n os e que interpretamos o evento como sendo um erro.
Pode-se especicar a data e hora em que determinado evento ocorrer a, ou usar um timer para gerar eventos a cada intervalo de tempo. Pode-se descrever que um evento ocorrer a dentro de um determinado tempo (exemplo: ap os 10s).
Os eventos s ao mais expressivos que os m etodos, porque o efeito de um evento n ao depende somente da classe do objeto, mas tamb em de seu estado.
Dica: monte diagramas de seq u encia (veja a se ca o 6.5.2) e/ou diagramas de comunica ca o (se ca o 6.5.3).
6.5.2
O diagrama de seq u encia enfatiza a troca de eventos e mensagens e sua ordem temporal. Cont em informa co es sobre o uxo de controle do programa. Costuma ser montado a partir de um diagrama de caso de uso e estabelece o relacionamento dos atores (usu arios e sistemas externos) com alguns objetos do sistema. Veja o prot otipo de um diagrama de seq u encia na Figura 6.15, no qual incluimos um ator, sua linha de vida (linha vertical pontilhada), uma mensagem, um objeto que receber a a mensagem. Observe que a linha de vida do objeto ca cheia quando ele est a realizando algum processamento (ativo). Veja que uma mensagem pode incluir sua ordem de execu ca o, o evento que a gerou, condi co es (ou restri co es), itera co es (representadas pelo s mbolo *) e o retorno.
Em um diagrama de seq u encia as mensagens de retorno s ao optativas e s ao representadas com linha tracejada. Aconselha-se a inclus ao da u ltima mensagen de retorno, de forma a deixar claro a naliza ca o da tarefa. Se existir processamento paralelo, as instru co es de retorno devem ser inclu das. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
135
Objeto O ator clica em um item de menu enviando uma mensagem para o objeto.
Linha de vida
Ator evento: {condio} Mensagem: Mtodo() Linha tracejada indica objeto inativo
Veja na Figura 6.16 um exemplo de diagrama de seq u encia. Observe que um evento gerado pelo ator, o professor, provoca o envio de uma mensagem para o objeto prova. Neste exemplo, o professor est a montando uma prova: primeiro separa uma folha de papel (cria a prova), a seguir cria mentalmente as quest oes e depois as adiciona ` a prova. Quando a prova est a pronta, o professor a entrega para o aluno. O aluno faz a prova, devolve-a para o professor e ent ao aguarda o resultado. O professor corrige a prova e ent ao mostra-a para o aluno (veja diagrama de m aquina de estado do aluno na Figura 6.20). Observe que uma mensagem pode ser enviada para o pr oprio objeto (autochamada). O aluno emite para si mesmo a mensagem, prestar aten ca o. Observe que temos uma prova, v arias quest oes e v arios alunos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
136
Aluno Ator Professor Mensagem <<create>> <<create>> Objeto Questo fazendo prova Prova
adiciona <<create>>
Na Figura 6.17 mostramos a seq u encia para c alculo da area de uma fun ca o. Depois de criar o objeto do tipo Simulador, com nome SimAreaFuncao, executamos a fun ca o pol tica Run(), respons avel pelo gerenciamento do c alculo da area da fun ca o. O simulador cria um objeto fun ca o, um objeto de integra ca o e em seguida chama o m etodo Area() do objeto de integra ca o passando como par ametro a fun ca o. A area e determinada. Por m, podemos solicitar ao programa externo Gnuplot a plotagem de gr acos da fun ca o.
Figura 6.17: Diagrama de seq u encia seq u encia para c alculo da area de uma fun ca o.
funo : Funcao : Ator-usurio : SimAreaFuncao() : Run() integral : Integral : SimAreaFuncao gnuplot : Gnuplot
: Funcao()
: Gnuplot()
: Plot()
137
6.5.3
No diagrama de comunica ca o o foco e a intera ca o e a troca de mensagens e dados entre os objetos. Veja na Figura 6.18 uma representa ca o do diagrama de comunica ca o equivalente ao diagrama de seq u encia da Figura 6.16. Observe que a seq u encia de execu ca o e dada por n umeros. O diagrama de comunica ca o pode ser utilizado em uma etapa de testes l ogicos ou conceituais dos modelos desenvolvidos. Observe que o diagrama de comunica ca o pode ser desenvolvido como uma extens ao do diagrama de caso de uso, detalhando o caso de uso por meio da inclus ao dos objetos, mensagens e par ametros trocados entre os objetos. O diagrama de comunica ca o inclui atores, objetos, mensagens e componentes do sistema. Objetos podem ser conectados por rela co es de associa ca o ou depend encia. As depend encias entre os n os representam rela co es de comunica ca o (podendo ser unidirecionais ou bidirecionais). Um diagrama de comunica ca o pode ser detalhado usando-se uma numera ca o como em 1; 1.1; 1.2; e assim por diante. Algumas ferramentas CASE podem gerar o diagrama de comunica ca o a partir do diagrama de eventos e vice-versa. [Fowler and Scott, 2000] consideram que o estudo de alternativas, isto e, varia co es nos diagramas de comunica ca o e seq u encia podem ser exploradas com o uso de cart oes CRC (veja se ca o 6.10.2).
Veja na Figura 6.19 uma representa ca o de um diagrama de comunica ca o equivalente ao diagrama de seq u encia da Figura 6.17. O diagrama de comunica ca o ilustrado na Figura 6.19 mostra a seq u encia para c alculo da area de uma fun ca o. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
138
Figura 6.19: Diagrama de comunica ca o seq u encia para c alculo da area de uma fun ca o.
6.5.4
Os valores assumidos pelos atributos de um objeto ao longo do tempo, a realiza ca o de uma atividade, ou a espera de um evento representam o estado do objeto. Segundo [Blaha and Rumbaugh, 2006], o estado e uma abstra ca o dos valores e liga co es de um objeto, normalmente correspondem a verbos no ger undio (esperando, discando). Um estado pode representar tanto caracter sticas ativas como passivas. Considere apenas atributos relevantes ao denir um estado. D e a cada estado um nome signicativo. O nome pode n ao ser necess ario se o estado for diretamente identicado.
i d i a g r m a e c o m n c a o u D : l I t n e g r a l d f c o r a e m n u u : . C F n c a o u : l ( ) I t n e g r a : 2 b i d ( ) d b l * A F F s e r q e a s e q n c a a p o r v u u t r e a p r n c a o n c a o o e u u u O : : : : ( ) F 3 n c a o u i j f t a o o n o : 1 . C i t g r l ) G t n p o u : l 4 G t p l c u . i l d s m a r l ( P r g n p : f P t o a r c o s 5
6.5. AOO MODELO DINAMICO
Para ajudar na identica ca o dos estado, fa ca uma an alise de cada atributo do objeto. Por exemplo: o atributo temperatura da agua indica se a agua est a no estado s olido, l quido ou gasoso. Um estado pode sofrer altera co es qualitativas (transi ca o de estado) e quantitativas (transi co es internas). Uma altera ca o quantitativa representa qualquer altera ca o em um dos atributos do objeto, por exemplo, a altera ca o da temperatura da agua de 55 C para 54 C. J a uma altera ca o qualitativa representa uma altera ca o conceitual do objeto, como a altera ca o da temperatura da agua de 55 C (l quida) para -5 C (s olida). O estado depende de uma condi ca o (a temperatura da agua). Uma transi ca o de estado pode estar associada a um evento/mensagem ou a uma atividade que altere um atributo (por exemplo, uma atividade que altere a temperatura da agua). A transi ca o de estado e representada por uma seta. Transi co es internas s ao ocorr encias que podem alterar o valor de um atributo, mas n ao mudam o estado do objeto. Depois de considerar os eventos normais (default ), considere as exce co es (casos de erro). Se a seq u encia puder ser repetida indenidamente, ela formar a um la co. Sempre que poss vel, substitua seq u encias nitas por la cos. Um estado depende dos eventos anteriores, mas de modo geral os eventos anteriores s ao ocultados pelos posteriores. Lembre-se de que uma instru ca o fa ca: Xem um objeto pode ser um evento para outro objeto, ou seja, verique as instru co es, fa ca nos diversos objetos e verique se esta n ao representa um evento para outro objeto; caso represente, desenhe no outro objeto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
139
Prepare um diagrama de m aquina de estado para cada classe de objetos com comportamento din amico importante (n ao trivial), mostrando os eventos que o objeto recebe e envia. Isto e, s o construa diagramas de m aquina de estados para classes de objetos com comportamento din amico signicativo (veja a se ca o 6.5.5 e a Figura 6.20).
6.5.5
Um diagrama de m aquina de estado representa os diversos estados que o objeto assume e os eventos que ocorrem ao longo de sua vida ou mesmo ao longo de um processo (hist orico do objeto). E usado para modelar aspectos din amicos do objeto. Elementos presentes em um diagrama de m aquina de estado s ao: Estado indica de forma abreviada o estado do objeto. Um exemplo de estado e a realizac a o de uma atividade demorada. Por exemplo: realizando entrada de dados, processando integra ca o, processando montagem dos gr acos (veja a Figura 6.21). Veja na Figura 6.20 (a) o prot otipo de representa ca o de um estado, o qual inclui: o nome do estado, a a ca o de entrada(entry), a atividade a ser realizada(do) e a a ca o de sa da(exit). Nome indica o nome do estado/atividade e deve ser u nico. entry a ca o de entrada, a ser executada quando entra no estado. do/atividade indica uma atividade em andamento. exit a ca o de sa da a ser executada quando sai do estado. Evento causa a transi ca o de estado (provoca execu ca o da a ca o que muda o estado do objeto). Condi c ao de guarda (guard condition) uma condi ca o de guarda imp oe algum tipo uma restri de restri ca o ` a transi ca o de estado. E ca o booleana, se verdadeira a a ca o que provoca a transi ca o de estado e executada. Uma condi ca o e representada entre colchetes {}. Por exemplo: um aluno s o ser a considerado aprovado se tiver obtido m edia nal maior que 6 (veja a Figura 6.20). A c ao todo m etodo que e executado quase instantaneamente e que est a associado a um evento e denominado a ca o (action ). As a co es podem representar opera co es internas de controle. A co es internas n ao mudam o estado do objeto. Quando as transi co es de um estado executam a mesma a ca o, pode-se vincular o estado ` a a ca o. A co es est ao associadas a transi co es. Veja na Figura 6.20 (b) um exemplo de diagrama de m aquina de estado para um aluno. Observe que este e formado por n os que representam os estados e setas que representam as transi co es entre os estados; observe tamb em como s ao representados o estado inicial e nal. Inicie a constru ca o do diagrama de m aquina de estado a partir dos diagramas de seq u encia; use os eventos oriundos dos casos de uso. Todo caso de uso corresponde a um caminho a ser seguido no diagrama de m aquina de estado, ou seja, deve-se comparar os diversos casos de uso e vericar os pontos em que eles divergem (e que precisam ser codicados no diagrama de m aquina de estados). Lembre-se de que dois caminhos em um diagrama de m aquina de estado ser ao os mesmos se o objeto esquecer os valores passados. Veja na Figura ?? os estados de uma thread e na Figura ?? os estados de um processo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
140
incio
estado
{matricula ok}
Assistindo aula
Pode-se representar mais detalhadamente um estado, usando-se diagramas de estados compostos. Cada estado composto representa um subestado, semelhante a sub-rotinas. Compare as Figuras 6.21 e 6.22, observe que o estado processando integra ca o pode ser detalhado em sub-estados. No caso, inclu mos os sub-estados iniciando dados, calculando area e retornando resultados. Figura 6.22: Diagrama de m aquina de estado: Estados compostos do objeto simulador.
141
Podemos representar concorr encias e sincroniza ca o no interior de um objeto utilizando diagramas de m aquinas de estado. Uma concorr encia dentro de um estado subdivide o estado. Observe na Figura 6.23 que o processo de c alculo da area foi subdividido em dois processos concorrentes, podendo ser utilizado processamento paralelo. Veremos uma introdu ca o ao uso de cluster e a programa ca o paralela usando m ultiplas threads ou m ultiplos processos a partir do Cap tulo ?? Introdu ca o ` a Utiliza ca o de Clusters de Computadores. Figura 6.23: Diagrama de m aquina de estado estados concorrentes do objeto simulador.
Veja a seguir dicas de [Rumbaugh et al., 1994] para a constru ca o de um diagrama de m aquinas de estados. Um cen ario pode ajud a-lo a encontrar novos estados.
d l d t p e r s a o c a a n o r e a u u : S i d i d d t a g r m a e m q n a e s a o u : d l d t s a o c a a n o r e a u : D , E l d t e p o s a o s c o r n e s x d d t t r e p e n o c m s o E l P I P t o c n e r s s v ( ) p s c o n r . . b d s s a o u i d d I n c a n o a o s D d l P I I t r o c e a n o e r s m p a r e s v d l d t t e o r n a o r e s a o u R l i d E t e a n o r z R i> f / o c n c a o u b d s a oP u D d e g rs d f i t r o c e s a n o m n a g e m g r c o s lo lo ( ) / P t > o g p u D
Andr e Duarte Bueno
O diagrama de m aquina de estado da classe-base deve ser separado do diagrama de m aquina de estado da classe-derivada, o qual deve descrever os seus atributos. Verique a consist encia dos diversos diagramas de m aquina de estado e verique se os eventos compartilhados est ao coerentes. As liga co es entre os diversos diagramas de m aquina de estado s ao realizadas pelas mensagens e eventos compartilhados. Um diagrama de m aquina de estado pode representar ciclos de vida. No caso em que um objeto e criado, realiza determinados procedimentos e e eliminado. Pode representar la cos cont nuos quando o objeto e persistente (n ao e destru do). Um estado complexo pode ser dividido em diagramas de n vel inferior, denominados estados compostos ou subestados. Algumas simula co es de engenharia podem demorar v arios dias. Como os computadores falham (ocorrem quedas de energia), e importante criar mecanismos que permitam o rein cio da simula ca o do ponto em que parou. Para facilitar a cria ca o destes pontos, os diagramas de m aquina de estado acrescentaram o conceito de estado de hist oria, representado pela letra H. As informa co es do sistema s ao armazenadas de tal forma que permitam o rein cio da simula ca o a partir deste ponto. Releia a se ca o 1.3.3. O controle da interface do usu ario pode ser descrito em um diagrama de m aquina de estado. Programa ca o Orientada a Objeto com C++
142
Observe nas guras apresentadas que os gr acos de estado costumam ser descritos no ger undio (exemplo: mostrando, calculando, gerando). Concorr encias e sincroniza co es, conceitos utilizados em processamento paralelo, podem ser representados em diagramas de m aquina de estado (veja a Figura 6.23). Teste verique a consist encia do diagrama de m aquina de estado. Compare eventos entre objetos para vericar se o diagrama est a completo. Verique os erros de sincroniza ca o, por exemplo, quando uma entrada ocorre em um momento inadequado.
143
6.5.6
Identica c ao de atividades
Como vimos nos diagramas de m aquinas de estado (se ca o 6.5.5), uma atividade e uma opera ca o que demora um determinado tempo, como, por exemplo, a solu ca o de um sistema de equa co es, o processamento de transa co es em um grande banco de dados, a simula ca o de um reservat orio de petr oleo, o processamento de sinais etc. Como uma atividade pode ser complexa, precisamos detalhar por meio de um uxograma como esta atividade vai ser realizada. Normalmente uma atividade e implementada por um m etodo de um determinado objeto, e detalhar o funcionamento da atividade corresponde a detalhar o funcionamento de determinada m etodo/fun ca o. Um m etodo deve ter precondi co es para seus dados de entrada e de sa da. Comece vericando os par ametros de entrada (tipo, valor-padr ao, valores m aximos e m nimos). Em seguida, verique se o retorno e adequado. Verique a l ogica de c alculo/processamento utilizada. Verique as estruturas de controle utilizadas (if, for, switch, case, do, while) (veja o Ap endice D). Verique as restri co es entre objetos. Uma restri ca o e uma depend encia funcional entre objetos. Dica: o detalhamento das atividades pode ser descrito com o uso dos diagramas de atividades (veja a se ca o 6.5.7).
6.5.7
Diagrama de atividades
O diagrama de atividades tamb em se preocupa com quest oes din amicas, mas em um n vel mais detalhado, sendo utilizado para descri ca o dos diversos m etodos das classes. Segundo [Blaha and Rumbaugh, 2006], um diagrama de atividades mostra a seq u encia de etapas que comp oem um processo complexo, como um algoritmo ou uxo de trabalho; seu enfoque s ao os m etodos e n ao os objetos. Isto e, o objetivo do diagrama de atividades e descrever algoritmos e funcionalidades complexas, detalhando um estado de atividade do diagrama de m aquina de estados. O diagrama de atividades se preocupa com os valores de entrada e sa da dos m etodos, como os atributos s ao alterados, as depend encias entre os m etodos. Em um diagrama de atividades os n os representam a co es ou atividades, e as linhas representam transi co es (uma transi ca o pode ocorrer quando a a ca o/atividade anterior foi completada). Os diagramas de atividades s ao especialmente importantes em areas como engenharia. O diagrama de atividades e baseado em redes de petri; e semelhante a um uxograma, a diferen ca e que ele permite que atividades sejam executadas paralelamente. Os elementos presentes em um diagrama de atividades s ao: Estado de a c ao descreve a atividade que est a sendo executada. Transi co es s ao setas que indicam que a atividade anterior terminou e que a nova atividade vai ser executada. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
144
Barra de sincroniza c ao (bifurca c ao/separa c ao) quando o m etodo admite processamento paralelo, utilizamos barras de sincroniza ca o para indicar uma separa ca o dos processos. Barra de sincroniza c ao (aglutina c ao/jun c ao) a barra de sincroniza ca o e utilizada ainda para representar a aglutina ca o de uma atividade. Losangos losangos s ao utilizados para indicar tomadas de decis ao, uso de estruturas de controle, como um if, um switch. Uma breve descri ca o sobre a decis ao pode ser inclu da utilizando-se anota co es.
A Figura 6.24 mostra em (a) o prot otipo de um diagrama de atividades. Observe que est ao presentes os indicadores de in cio e m da atividade (os mesmos do diagrama de m aquinas de estado), losangos para tomada de decis ao, bifurca co es e aglutina co es (utilizadas para indicar processamento concorrente) e as atividades. A Figura 6.24 (b) mostra o diagrama de atividades de um m etodo de binariza ca o (transforma uma imagem em tons de cinza ou colorida em imagem preto/branco). Observe que se a imagem j a estiver binarizada o m etodo n ao faz nada. Se a imagem e em tons de cinza, chama o m etodo que binariza imagens em tons de cinza e, se for imagem colorida, chama o m etodo que binariza imagens coloridas. Observe que e um m etodo pol tico e envolve apenas tomadas de decis oes. O processamento ser a feito em m etodos auxiliares.
Figura 6.24: Em (a) o prot otipo de um diagrama de atividades. Em (b) o diagrama de atividades de um m etodo de binariza ca o.
O diagrama de atividades se preocupa com os detalhes de implementao dos mtodos. O que ocorre dentro de cada mtodo importante. incio Atividade No exemplo um mtodo de binarizao.
separao bifurcao [ Imagem Binarizada ] Tomada de deciso Atividade [ Imagem Cinza ] [false] [true] [ Iterativo ] Atividade Atividade Executa mtodo iterativo Executa mtodo direto [ Direto ] Executa binarizao de imagem Cinza [ Imagem Colorida ]
A Figura 6.25 mostra o diagrama de atividades para o m etodo do Trap ezio. O mesmo e utilizado para calcular a area de uma fun ca o. Observe que toda seq u encia de c alculo e detalhada. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
145
Figura 6.25: Diagrama de atividades m etodo do Trap ezio para c alculo da area.
Diagrama de Atividades: Classe: IntTrapezio Mtodo: Area() Mtodo de clculo Recebe intervalo integrao e funo f,xmax,xmin,numeroIntervalos dx=(xmax-xmin)/numeroIntervalos
x = x + dx
y=f(x)
Diagrama de atividades com raias de nata c ao O diagrama de atividades pode apresentar linhas verticais (raias de nata ca o) separando os diferentes objetos. O uso de raias de nata ca o permitem a visualiza ca o da execu ca o de seq u encias de troca de mensagens e dados entre objetos. Como pode incluir barras de bifurca ca o e aglutina ca o, pode ser utilizado para representar processamentos paralelos. Veja o exemplo na Figura 6.26. Nele, o usu ario externo cria um objeto simulador e em seguida roda a simula ca o. O objeto simulador cria um objeto fun ca o e um objeto integrador, dene seus atributos e logo ap os inicia o c alculo da area da fun ca o. O simulador identica a presen ca de dois n os (de um cluster) e separa o calculo da area em dois intervalos, i e j. Depois de calculada a area, o simulador envia para o programa externo gnuplot o comando para gerar e plotar os gr acos. O resultado nal e analisado pelo usu ario. Figura 6.26: Diagrama de atividades uso de raios de nata ca o.
i l t 2 1 g n p o s r o u u U N N i l d S l i l d m a o r u a c a p r m e r o a c a s e g n o u u u C C i i t t n e r o n e r o v v i l d S r a m a o r u C d i i b j f o t r a o e o n o u R C i e g r a f i l t t e n r e r a o n o v D l F a c e u u C l i I t l j I r e a n e r a o t v r e a n e r a o v A A l f i f i t o a r g c o s e r a g r c o s P G lis lt d t n a r e s a o s o s u A R M
Andr e Duarte Bueno
146
Diagrama de atividades e envio de sinal para dispositivos externos O diagrama de atividades pode incluir ainda ret angulos com pontas triangulares, os quais s ao utilizados para indicar o envio/recebimento de sinais de/para sistemas externos. Veja na Figura 4.5 os elementos utilizados pela UML para representar o envio/recebimento de sinais.
6.5.8
Diagrama de tempo
Mostra mudan cas no estado ou papel de uma classe ao longo do tempo; e util para descrever processos temporais.
6.5.9
um diagrama que mistura elementos do diagrama de m E aquinas de estado, de seq u encia, de comunica ca o e de pacotes, objetivando detalhar toda intera ca o de um determinado cen ario de uso do programa.
6.5.10
Observe que com os diagramas din amicos temos representadas todas as caracter sticas din amicas do sistema e dos objetos. Os diagramas de seq u encia e de comunica ca o se preocupam com a troca de dados entre objetos e atores do sistema, a intera ca o dos objetos em um n vel mais macro. O diagrama de m aquinas de estado e focado nos estados assumidos pelo objeto e suas transi co es (valores dos atributos), os poss veis comportamentos do objeto. O diagrama de atividades se preocupa com o que ocorre dentro de cada m etodo da classe, detalhando seu funcionamento (a microdin amica do sistema, os algoritmos). O diagrama de tempo mostra varia co es de um objeto ao longo do tempo. J a o diagrama de intera ca o geral e uma mescla de v arios diagramas, sendo usado para detalhar um determinado cen ario.
6.5.11
Itera c ao
Observe na Figura 5.1 que, ap os cada etapa realizada, deve-se realizar uma itera ca o. Os seguintes itens devem ser vericados: Revise os diagramas de seq u encia e de comunica ca o. Voc e incluiu diagramas de m aquinas de estados para as classes complexas? Algoritmos complexos foram montados utilizando os diagramas de atividades? A estrutura de um modelo din amico e estreitamente relacionada com o modelo estrutural. Os eventos podem ser representados como m etodos no modelo estrutural. A hierarquia de estados de um objeto e equivalente a um conjunto de restri co es do modelo estrutural. Voc e vericou o efeito da modelagem din amica nos diagramas estruturais? Conra as rela co es entre os diagramas din amicos e os m etodos nas classes. Voc e incluiu nos diagramas os casos excepcionais? As entradas erradas? Falhas no sistema? Problemas com hardware? Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
147
Teste terminado o modelo din amico, fa ca o teste l ogico (veja o item 3, na se ca o 6.9). Dica: otimiza ca o o modelo din amico deve incluir a identica ca o dos pontos do programa que merecem ser otimizados. Isto pode ser feito baseando-se na an alise dos diagramas de atividade (veja a se ca o 6.5.7) e na an alise dos algoritmos que precisam ser implementados. Identique pontos concorrentes e que podem ser executados em paralelo. Comece fazendo uma pesquisa na internet por bibliotecas similares; veja como os outros resolveram a quest ao da otimiza ca o de determinado algoritmo. Na etapa de implementa ca o, voc e pode utilizar um proler (veja o Cap tulo ?? Auditoria e Otimiza ca o de Programas) para identicar os gargalos de desempenho.
148
6.6
Projeto do sistema
Depois da an alise orientada a objeto desenvolve-se o projeto do sistema, qual envolve etapas como a deni ca o dos protocolos, da interface API, o uso de recursos, a subdivis ao do sistema em subsistemas, a aloca ca o dos subsistemas ao hardware e a sele ca o das estruturas de controle, a sele ca o das plataformas do sistema, das biblitoecas externas, dos padr oes de projeto, al em da tomada de decis oes conceituais e pol ticas que formam a infraestrutura do projeto. Deve-se denir padr oes de documenta ca o, padr oes para o nome das classes, padr oes de retorno e de par ametros em m etodos, caracter sticas da interface do usu ario e caracter sticas de desempenho. Segundo [Rumbaugh et al., 1994, Blaha and Rumbaugh, 2006], o projeto do sistema e a estrat egia de alto n vel para resolver o problema e elaborar uma solu ca o. Voc e deve se preocupar com itens como: 1. Protocolos Deni ca o dos protocolos de comunica ca o entre os diversos elementos externos (como dispositivos). Por exemplo: se o sistema envolve o uso dos n os de um cluster, devem ser considerados aspectos como o protocolo de comunica ca o entre os n os do cluster. Deni ca o dos protocolos de comunica ca o entre os diversos elementos internos (como objetos). Deni ca o da interface API de suas bibliotecas e sistemas (veja a se ca o 6.6.1). Deni ca o do formato dos arquivos gerados pelo programa. Por exemplo: prera formatos abertos, como arquivos txt e xml. 2. Recursos Identica ca o e aloca ca o dos recursos globais, como os recursos do sistema ser ao alocados, utilizados, compartilhados e liberados. Implicam modica co es no diagrama de componentes (veja a se ca o 6.7.1). Identica ca o da necessidade do uso de banco de dados. Implicam em modica co es nos diagramas de atividades e de componentes. Identica ca o da necessidade de sistemas de armazenamento de massa. Por exemplo: um storage em um sistema de cluster ou sistemas de backup. 3. Controle Identica ca o e sele ca o da implementa ca o de controle, seq uencial ou concorrente, baseado em procedimentos ou eventos (veja a se ca o 6.6.2). Implicam modica co es no diagrama de execu ca o (veja a se ca o 6.7.2). Identica ca o das condi co es extremas e de prioridades. Identica ca o da necessidade de otimiza ca o. Por exemplo: prera sistemas com grande capacidade de mem oria; prera v arios hds pequenos a um grande. Identica ca o e deni ca o de loops de controle e das escalas de tempo. Identica ca o de concorr encias quais algoritmos podem ser implementados usando processamento paralelo (veja a se ca o ??). 4. Plataformas Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
149
Identica ca o das estruturas arquitet onicas comuns. Identica ca o de subsistemas relacionados ` a plataforma selecionada. Podem implicar em modica co es no diagrama de pacotes (veja a se ca o 6.2.3) e no diagrama de componentes (veja a se ca o 6.7.1). Identica ca o e deni ca o das plataformas a serem suportadas: hardware, sistema operacional e linguagem de programa ca o (veja a se ca o 6.6.3). Sele ca o das bibliotecas externas a serem utilizadas (veja a se ca o 6.6.4). Sele ca o da biblioteca utilizada para montar a interface gr aca do programa GDI (veja a se ca o 6.6.5). Sele ca o do ambiente de desenvolvimento para montar a interface de desenvolvimento IDE (veja a se ca o 6.6.6). 5. Padr oes de projeto Normalmente os padr oes de projeto s ao identicados e passam a fazer parte de uma biblioteca de padr oes da empresa. Mas isto s o ocorre ap os a realiza ca o de diversos projetos. Nota: uma das maiores preocupa co es de simula co es de engenharia e o desempenho. A necessidade de se aliar desempenho, interface gr aca amig avel e reuso de bibliotecas limita o n umero de linguagens a serem utilizadas, de modo que C++ tem sido a mais indicada (veremos a otimiza ca o de programas no Cap tulo ?? Auditoria e Otimiza ca o de Programas, e t ecnicas de processamento paralelo a partir do Cap tulo ?? Introdu ca o ` a Utiliza ca o de Clusters de Computadores).
6.6.1
Quando estamos desenvolvendo uma classe, um m odulo ou um sistema, precisamos denir sua interface de acesso. Uma API Application Programming Interface ou interface de programa ca o de aplica ca o e um conjunto de instru co es e informa co es sobre a forma como a biblioteca deve ser acessada. A API separa o que e p ublico (acess vel) do que e protegido ou privado (inacess vel). Na se ca o 3.2 e por meio da Figura 3.2, mostramos que a vis ao do que e publico e do que e privado depende da audi encia, isto e, de quem vai utilizar a classe/m odulo/sistema. Na pr atica isto signica que, quando formos denir as interfaces de nossos sistemas, precisamos denir claramente quem s ao seus usu arios (a audi encia). Por exemplo: a API de bibliotecas como Qt, GTK, MFC, VCL s ao desenvolvidas para programadores medianos. O protocolo e o conjunto de m etodos que podem ser acessados pelo usu ario, o conjunto de mensagens a que o objeto responde; ou seja, o protocolo e o conjunto de m etodos p ublicos da classe. Veja a seguir dicas de [Winblad et al., 1993] para melhorar os protocolos. Senten cas para melhorar os protocolos D e nomes similares ou id enticos a mensagens e m etodos quando uma classe se comunica com outras classes para realizar opera co es similares. Desenhe classes onde uma mensagem possa ser enviada diretamente para um objeto e manipulada corretamente pelos m etodos nele contidos. Finalmente, e importante montar a interface API de seu programa de modo que ela seja extens vel, reaproveit avel e que considere requisitos futuros. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
150
6.6.2
O sistema ou subsistema de controle da execu ca o do software pode ser implementado de diferentes formas. Veja a seguir alguns exemplos: Se o sistema realiza seq u encias predenidas como em arquivos de lote (por exemplo, autoexec.bat, init.d), ou c alculos seq u enciais, ent ao o controle pode ser feito por arquivos ASCII, os quais determinam a seq u encia a ser realizada. Sistemas de reinicializa ca o do sistema podem ser inclu dos (veja a se ca o 1.3.1 e 1.3.2). Este tipo de sistema utiliza uma estrutura de controle chamada de transforma ca o em lote, bastante utilizada em procedimentos de engenharia, no processamento de transa co es banc arias (cheques) e transa co es agendadas. Um sistema com controle do tipo transforma ca o cont nua permite a realiza ca o de etapas de simula co es. Para cada bloco de tarefas executadas, o usu ario analisa os resultados obtidos e toma decis oes a respeito da seq u encia de execu ca o do sistema, ou seja, o usu ario pode alterar o uxo de execu ca o do programa. Veja a se ca o 1.3.3. Em uma interface interativa os usu arios interagem o tempo todo com o sistema (geralmente utilizando uma interface gr aca). De maneira geral, este tipo de controle e baseado em eventos e permite a execu ca o concorrente (pelo uso de m ultiplas threads e/ou processos). O acesso compartilhado aos recursos pode ser controlado por bloqueadores de acesso (mutex). Sistemas de software modernos com controle do tipo interface interativa utilizam listas e podem ter macros para execu ca o de atividades repetitivas (veja a se ca o 1.3.4). Sistemas cient cos e simula co es de engenharia (como processamento de dados, sinais e imagens, simula co es qu micas e ambientais) podem utilizar um dos tipos de controle acima denidos. Se a simula ca o e fechada (dados de entrada e sa da previamente denidos), pode-se utilizar tranforma ca o em lote. Se existem poucas necessidades de intera ca o com o usu ario use transforma ca o cont nua. Sistemas modernos de engenharia utilizam interface interativa, possibilitando um controle mais renado das simula co es a serem realizadas.
6.6.3
Uma plataforma de programa ca o envolve o hardware, o sistema operacional e a linguagem de programa ca o. Veja a seguir alguns exemplos: Computador do tipo Macintosh sistema operacional Mac Os X linguagem C. Computador do tipo PC/Intel sistema operacional Windows linguagem C++. Computador do tipo Workstation/AMD - Opteron sistema operacional GNU/Linux linguagem C++. Um programa em ANSI C++ pode ser compilado em diversas plataformas. O procedimento e simples; basta copiar o c odigo-fonte para a plataforma-alvo e, em seguida, compilar os programas usando um compilador padr ao Ansi C++. Para facilitar a compila ca o de um programa em m ultiplas plataformas, as equipes de desenvolvimento da GNU desenvolveram os programas autoconf, automake e libtool (os quais ser ao descritos no Cap tulo ?? Introdu ca o ` a Programa ca o Multiplataforma com Software Livre). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
151
6.6.4
No projeto do sistema e necess ario denir quais bibliotecas externas ser ao utilizadas. A dica e utilizar bibliotecas reconhecidas e bem-documentadas, como as bibliotecas da GNU. Segundo [Korson and Macgregor, 92], uma biblioteca orientada a objeto deve: ter protocolos uniformes (nomes e assinaturas), focar um tema completo (fechado), mas considerando generalidades (aliando, na medida do poss vel, uniformidade, completude e generalidade). Tamb em deve permitir sua extens ao e ser eciente. Veremos na se ca o ?? as vantagens e as desvantagens do uso de bibliotecas externas. Veja a seguir alguns exemplos de bibliotecas externas. Exemplos de bibliotecas externas Bibliotecas da GNU, veja http://www.gnu.org. Bibliotecas disponibilizadas no site Scientic Applications on Linux (SAL), veja http://sal.linet.gr.jp/index.shtml. Bibliotecas disponibilizadas no site The Object-Oriented Numerics Page, veja http://www.oonumerics.org/oon/. Biblioteca magick++, apresentada na se ca o ??, veja http://www.simplesystems.org/Magick++/ . Biblioteca commom C++, apresentada na se ca o ??, veja http://www.gnu.org/directory/GNU/commoncpp.html . Biblioteca boost, apresentada na se ca o ??, veja http://www.boost.org/. Biblioteca de m etodos num ericos, veja http://users.physik.tu-muenchen.de/gammel/matpack/. Depois de selecionar as bibliotecas externas que utilizar a, e necess ario fazer o download/instala ca o da biblitoteca, ler os manuais do usu ario e a documenta ca o API, al em de estudar os exemplos que acompanham a biblioteca. A apresenta ca o das bibliotecas, seus conceitos, vantagens e desvantagens, como montar e como usar nossas pr oprias bibliotecas e como usar bibliotecas conhecidas ser ao vistas nos cap tulos e se co es abaixo: A se ca o 6.6.5 mostra a sele ca o da biblioteca gr aca a ser utilizada GDI. Na se ca o 6.11.5 apresentaremos algumas senten cas para montagem de bibliotecas. Na se ca o 6.11.6 veremos senten cas para montagem de frameworks. No Cap tulo ?? Bibliotecas, veremos como implementar nossas pr oprias bibliotecas. No Cap tulo ?? O Programa Libtool, veremos como implementar nossas pr oprias bibliotecas em sistemas multiplataforma. Veremos a partir do Cap tulo ?? Bibliotecas Uteis, exemplos de bibliotecas externas. Para desenvolver programas em um ambiente de janelas como o Windows, o Mac OS X, o GNOME ou o KDE, voc e ter a que escolher uma biblioteca gr aca. Veja na se ca o 6.6.5 uma discuss ao sobre a sele ca o de bibliotecas gr acas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
152
6.6.5
H a alguns anos desenvolvia-se um programa em computadores PC XT/AT, utilizando-se um ambiente em modo texto, pois n ao existiam janelas e cones. Mais recentemente, praticamente todos os programas utilizam janelas, cones, menus etc. e s ao desenvolvidos para plataformas computacionais como o PC/Windows Vista, esta co es de trabalho rodando Unix, GNU/Linux com interface gr aca padr ao MOTIF, GNOME, KDE, ou mesmo Macintosh rodando MAC OS System X. Desenvolver um programa For Windows, assim que se lan cou o Windows 3.0, era uma verdadeira calamidade, pois a API do Windows s o fornecia algumas fun co es b asicas, e o programador tinha que escrever praticamente tudo o que ia utilizar. Situa ca o semelhante ocorria com os demais ambientes de janelas. Desenvolver um programa para um ambiente de janelas tornou-se mais f acil, gra cas a bibliotecas de interfaces gr acas orientadas a objeto (GDI), como a Qt, a GTK, a VCL, a MFC, entre outras. Essas interfaces fornecem toda uma hierarquia de classes que podem ser imediatamente herdadas pelo seu programa. Voc e pode criar janelas, menus, bot oes, barras de ferramentas, entre outros objetos, com muita facilidade. Entretanto, para que se possa desenvolver um programa para um ambiente gr aco, e preciso aprender programa ca o orientada a objeto. Voc e s o conseguir a herdar e utilizar os objetos fornecidos pelas bibliotecas gr acas se compreender a programa ca o orientada a objeto e a sintaxe de C++ (veremos a sintaxe de C++ em detalhes a partir do Cap tulo 7 Introdu ca o ao C++.). Em 2007, as bibliotecas gr acas mais utilizadas no ambiente Windows s ao a VCL, do Builder, Delphi e a MFC, do Microsoft Visual C++. No ambiente GNU/Linux, as mais utilizadas s ao as bibliotecas Qt (da TrollTech/KDE) e a biblioteca GTK (da GNU/GNOME). Dica: d e prefer encia a bibliotecas que sejam livres e multiplataforma. Veremos no Cap tulo ?? A biblioteca Qt 4, exemplos de uso da biblioteca Qt.
6.6.6
Uma IDE e uma interface integrada para o desenvolvimento de programas e softwares avanc ados. Ela facilita a vida do programador, pois as diversas ferramentas a serem utilizadas compilador, editor de texto, linker, debuger, sistema de controle de vers oes, entre outros est ao integrados em uma u nica ferramenta. A seguir ser ao descritos alguns ambientes de desenvolvimento integrados utilizados nas plataformas Windows, Mac OS X, Unix e GNU/Linux. Windows Em se tratando de ambientes de desenvolvimento, pode-se dizer que o Borland C++, o Builder C++ e o Microsoft Visual C++ s ao programas bastante seguros e completos. Contam com geradores autom aticos de c odigo e visualizadores de classes. Um programa GPL (software livre) simples e bom e o Dev C++. Mac OS System X O Mac OS System X e um sistema operacional compat vel com os sistemas Unix e GNU/Linux, de forma que programas feitos utilizando bibliotecas multiplataforma, como a Qt ou GTK, rodar ao no seu Mac OS X. Um ambiente de desenvolvimento bastante conhecido pelo pessoal que usa Mac e o Code Warrior Metroworks. GNU/Linux (Unix) Nos u ltimos anos os ambientes de desenvolvimento do GNU/Linux sofreram diversos Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
153
aperfei coamentos. Distribui co es do GNU/Linux incluem diversos pacotes para aux lio ao desenvolvimento de software em C++, podendo-se citar: controle de vers oes (cvs, subversion, cervisia ), auditoria de software (gprof, callgrind, oreport, valgrind, kcachegrind, chainsaw ), debugagem (gdb, ddd ), interfaces integradas de desenvolvimento (kdevelop, Eclipse, glade, QtDesigner), e utilit arios (Kbabel, emacs, kbugbuster ). A programa ca o para software livre e GNU/Linux ser a discutida na parte IV do livro. Dica: veja na Revista Linux, edi ca o 29, uma lista auxiliar de ambientes de desenvolvimento para GNU/Linux. Procure o endere co: http://www.revistadolinux.com.br/ed/029/assinantes/desenvolvimento.php3. A Linux Magazine, n umero 12, apresenta a reportagem Ferramentas de Desenvolvimento An alise. Ambientes de desenvolvimento A seguir ser a apresentada uma lista de ambientes de desenvolvimento. Abra o site indicado e verique quais s ao as plataformas suportadas. Microsoft Visual C++ .NET 2003 uma IDE completa que usa a biblioteca de classes MFC (Microsoft Foundation Classes). E Veja a seguir as principais caracter sticas do Visual C++, as quais foram extra das do site da Microsoft. Conformidade do C++ com as normas ISO; otimiza co es atualizadas do compilador; verica co es aperfei coadas de seguran ca do buer; Windows Forms Designer; melhor diagn ostico do compilador; depura ca o aperfei coada no C++; documenta ca o expandida e amostras; e bibliotecas revisadas para maior seguran ca . Para maiores detalhes consulte o site http://msdn.microsoft.com/visualc/. Borland Enterprise Studio C++ uma IDE completa que usa a biblioteca de classes VCL (Visual Class Library). E Para maiores detalhes consulte o site http://www.borland.com.br/estudiocpp/. Borland C++ Builder Ambiente completo, do tipo RAD, que utiliza a biblioteca VCL Visual Class Library. Tem suporte ` a UML 1.5 ou 2.0, e, com o LiveSource, pode-se alternar entre o desenvolvimento da modelagem UML ou da implementa ca o. Tamb em permite a cria ca o de novos padr oes. Veja o que diz o site da Borland: Para o desenvolvedor C++ prossional, que exige aplica co es con aveis e de alta-performance. Enm o IDE que voc e esperava! O C++Builder R 2006 atualiza e rena o popular IDE do C++Builder R com as mais recentes fun co es RAD e ALM para o desenvolvimento C e C++ cr tico ` a miss ao. Desenvolva robustas aplica co es GUI, de base de dados e Web em tempo recorde, com desenvolvimento de aplica co es Web WYSIWYG, poderosos novos provedores de dados, as mais recentes fun co es de produtividade IDE, e uma profunda integra ca o de IDE com controle de vers ao, acompanhamento de bugs e colabora ca o de equipe. Alavanque uma grande variedade de componentes de terceiros com o mais recente VCL (Visual Component Library). Parte do Borland Developer Studio, o C++Builder 2006 tamb em inclui suporte completo ao desenvolvimento Web, de base de dados e GUI utilizando C, C++, C#, Delphi Win32 e Delphi .NET. Para maiores detalhes consulte o site http://www.borland.com/us/products/cbuilder/. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
154
6.6. PROJETO DO SISTEMA Nota: o kylix foi uma tentativa frustada da borland de desenvolver um ambiente para plataforma GNU/Linux.
Dev C++ Ambiente visual pequeno, simples de usar e que utiliza as ferramentas da GNU. Veja na Figura 6.27 a tela do programa Dev C++. Para maiores detalhes, como instala ca o, siga as instru co es do site http://www.bloodshed. net/dev/.
Code Warrior Metroworks Ambiente completo com uso da biblioteca Code Warrior. Muito utilizada no Mac Os System X. Para maiores detalhes consulte o site http://www.metrowerks.com. Kdevelop O kdevelop tornou-se um ambiente multilinguagem, podendo ser utilizado para desenvolver programas em Ada, C, C++ (biblioteca GDI Qt ou GTK), banco de dados, Fortran, Haskell, Java, Pascal, Perl, PHP, Python, Ruby e Shell. Ou seja, voc e aprende a usar um ambiente de desenvolvimento e faz programas utilizando diferentes linguagens. Adaptou o Qt-designer para funcionamento integrado, tem interface integrada para acesso a debuger e a diferentes sistemas de controle de vers oes. Permite visualizar os arquivos e as classes de diferentes formas. Muito bem documentado. Veja na Figura 6.28 a tela do kdevelop. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
6.6. PROJETO DO SISTEMA Para maiores detalhes consulte o site http://www.kdevelop.org. Figura 6.28: A tela do programa kdevelop.
155
Qt-designer Ambiente do tipo RAD, completo e de uso simplicado. Veja uma pequena reportagem sobre o Qt-designer na Revista Linux, edi ca o 31, dispon vel em http://www. revistadolinux.com.br/ed/031/assinantes/programacao.php3. Exemplos de uso da biblioteca Qt, utilizada pelo Qt-designer, est ao dispon veis na se ca o ??. Para maiores detalhes consulte o site http://www.trolltech.com. Glade o Ambiente completo que utiliza o toolkit do gtk++ (veja http://www.gtk.org/). E ambiente ideal para o desenvolvimento de programas para o GNOME. Para maiores detalhes consulte o site http://glade.gnome.org/. Eclipse um o eclipse e uma plataforma completa para constru ca o e integra ca o de software. E software livre desenvolvido pela IBM, escrito em Java, mas que tem suporte para C e C++. Veja o que diz o site http://www.eclipse.org/: O Eclipse e um projeto da comunidade de software aberto focado na construc a o de uma plataforma de desenvolvimento composta de bibliotecas extens veis e ferramentas para desenvolvimento, constru ca o e gerenciamento, em tempo de execu ca o, de softwares ao longo de seu ciclo de vida. Uma grande e entusiasmada equipe, formada pelos maiores vendedores de tecnologias e iniciativas inovadoras, como universidades, institui co es de pesquisa e indiv duos, tem extendido, complementado e dado suporte a plataforma do Eclipse Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
156
Anjuta Outro ambiente de desenvolvimento para o GTK/GNOME. Para maiores detalhes consulte o site http://anjuta.sourceforge.net. Source navigator Dispon vel em algumas distribui co es Redhat. Para maiores detalhes consulte o site http://sources.redhat.com/sourcenav/. Sistema GNU Pode-se desenvolver os programas com editores de texto simples (emacs, vi ), compilar os programas com o gcc/g++, linkar com o ld, e usar o make para compila ca o automatizada. Tem o cvs para controle de vers oes. O programa doxygem e utilizado para gerar documenta ca o embutida. O sistema da GNU tem ainda os pacotes automake, autoconf e libtool que permitem o desenvolvimento de sistemas multiplataforma. Todos esses sistemas ser ao vistos em detalhes a partir do Cap tulo ?? Introdu ca o ` a Programa ca o Multiplataforma com Software Livre. Para maiores detalhes consulte o site http://www.gnu.org. Observe que o sistema GNU garante maior portabilidade e uniformidade no desenvolvimento de seus programas, pois esse sistema est a presente em praticamente todas as plataformas. As bibliotecas gr acas mais interessantes s ao a Qt e a GTK pois s ao livres e multiplataforma. Os sistemas GNU ser ao discutidos na Parte?? Programa ca o Multiplataforma com Software Livre. Nota: se o sistema que vai ser desenvolvido e grande, ent ao a etapa de projeto pode ser feita em paralelo ` a an alise e deve considerar as experi encias da equipe de desenvolvimento. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
157
6.7
O projeto orientado a objeto e a etapa posterior ao projeto do sistema (veja a Figura 5.1). Baseia-se na an alise, mas considera as decis oes do projeto do sistema. Acrescenta a an alise desenvolvida e as caracter sticas da plataforma escolhida (hardware, sistema operacional e linguagem de programa ca o). Passa pelo maior detalhamento do funcionamento do programa, acrescentando atributos e m etodos que envolvem a solu ca o de problemas espec cos n ao identicados durante a an alise. Envolve a otimiza ca o da estrutura de dados e dos algoritmos, a minimiza ca o do tempo de execu ca o, de mem oria e de custos. Existe um desvio de enfase para os conceitos da plataforma selecionada. Exemplo: na an alise voc e dene que existe um m etodo para salvar um arquivo em disco, dene um atributo nomeDoArquivo, mas n ao se preocupa com detalhes espec cos da linguagem. J a no projeto, voc e inclui as bibliotecas necess arias para acesso ao disco, cria um objeto espec co para acessar o disco, podendo, portanto, acrescentar novas classes ` aquelas desenvolvidas na an alise. Efeitos do projeto no modelo estrutural Adicionar nos diagramas de pacotes as bibliotecas e subsistemas selecionados no projeto do sistema (exemplo: a biblioteca gr aca selecionada). Novas classes e associa co es oriundas das bibliotecas selecionadas e da linguagem escolhida devem ser acrescentadas ao modelo. Estabelecer as depend encias e restri co es associadas ` a plataforma escolhida. Efeitos do projeto no modelo din amico Revisar os diagramas de seq u encia e de comunica ca o considerando a plataforma escolhida. Vericar a necessidade de se revisar, ampliar e adicionar novos diagramas de m aquinas de estado e de atividades. Efeitos do projeto nos atributos Atributos novos podem ser adicionados a uma classe, como, por exemplo, atributos espec cos de uma determinada linguagem de programa ca o (acesso a disco, ponteiros, constantes e informa co es correlacionadas). Estruturas de dados avan cadas podem ser montadas utilizando-se os containers e algoritmos gen ericos de C++ (a STL ser a discutida a partir do Cap tulo 31 Introdu ca o ` a Biblioteca Padr ao de Gabaritos de C++ STL ). Efeitos do projeto nos m etodos Em fun ca o da plataforma escolhida, verique as poss veis altera co es nos m etodos. O projeto do sistema costuma afetar os m etodos de acesso aos diversos dispositivos (exemplo: hd, rede). De maneira geral os m etodos devem ser divididos em dois tipos: i) tomada de decis oes, m etodos pol ticos ou de controle; devem ser claros, leg veis, ex veis e usam polimorsmo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
158
6.7. PROJETO ORIENTADO A OBJETO POO ii) realiza ca o de processamentos, podem ser otimizados e em alguns casos o polimorsmo deve ser evitado.
Algoritmos complexos podem ser subdivididos. Verique quais m etodos podem ser otimizados. Pense em utilizar algoritmos prontos como os da STL (algoritmos gen ericos). Responda a pergunta: os m etodos da classes est ao dando resposta ` as responsabilidades da classe? Revise os diagramas de classes, de seq u encia e de m aquina de estado. Efeitos do projeto nas heran cas Reorganiza ca o das classes e dos m etodos (criar m etodos gen ericos com par ametros que nem sempre s ao necess arios e englobam m etodos existentes). Abstra ca o do comportamento comum (duas classes podem ter uma superclasse em comum). Utiliza ca o de delega ca o para compartilhar a implementa ca o (quando voc e cria uma heran ca irreal para reaproveitar c odigo). Usar com cuidado. Revise as heran cas no diagrama de classes. Efeitos do projeto nas associa co es Deve-se denir na fase de projeto como as associa co es ser ao implementadas, se obedecer ao um determinado padr ao ou n ao. Se existe uma rela ca o de muitos, pode-se implementar a associa ca o com a utiliza ca o de um dicion ario, que e um mapa das associa co es entre objetos. Assim, o objeto A acessa o dicion ario fornecendo uma chave (um nome para o objeto que deseja acessar) e o dicion ario retorna um valor (um ponteiro) para o objeto correto. Veja o Cap tulo 29 Implementando Associa co es em C++. Evite percorrer v arias associa co es para acessar dados de classes distantes. Pense em adicionar associa co es diretas. Efeitos do projeto nas otimiza co es Fa ca uma an alise de aspectos relativos ` a otimiza ca o do sistema. Lembrando que a otimiza ca o deve ser desenvolvida por analistas/desenvolvedores experientes. Identique pontos a serem otimizados em que podem ser utilizados processos concorrentes. Pense em incluir bibliotecas otimizadas. Se o acesso a determinados objetos (atributos/m etodos) requer um caminho longo (exemplo: A->B->C->D.atributo), pense em incluir associa co es extras (exemplo: A-D.atributo). Atributos auxiliares podem ser inclu dos. A ordem de execu ca o pode ser alterada. Revise as associa co es nos diagramas de classes. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
159
Depois de revisados os diagramas da an alise voc e pode montar dois diagramas relacionados ` a infraestrutura do sistema. As depend encias dos arquivos e bibliotecas podem ser descritos pelo diagrama de componentes (veja a se ca o 6.7.1), e as rela c oes e depend encias entre o software e o hardware podem ser ilustradas com o diagrama de implanta ca o (veja a se ca o 6.7.1).
6.7.1
Diagrama de componentes
O diagrama de componentes mostra a forma como os componentes do programa se relacionam, suas depend encias. Inclui itens como: componentes, subsistemas, execut aveis, n os, associa co es, depend encias, generaliza co es, restri co es e notas. Exemplos de componentes s ao bibliotecas est aticas, bibliotecas din amicas, dlls, componentes Java, execut aveis, arquivos de disco, c odigo-fonte. Veja na Figura 6.30 um exemplo de diagrama de componentes. Observe que este inclui muitas depend encias, ilustrando as rela co es entre os arquivos. Por exemplo: o subsistema biblioteca inclui os arquivos das classes A e B, e a gera ca o dos objetos A.obj e B.obj depende dos arquivos A.h, A.cpp, B.h e B.cpp. A gera ca o da biblioteca depende dos arquivos A.obj e B.obj. O subsistema biblioteca Qt, um subsistema exerno, inclui os arquivos de c odigo da biblioteca Qt e a biblioteca em si. O subsistema banco de dados representa o banco de dados utilizado pelo sistema e tem uma interface de acesso que e utilizada pelo programa para acesso aos dados armazenados no banco de dados. O programa execut avel a ser gerado depende da biblioteca gerada, dos arquivos da biblioteca Qt, do m odulo de arquivos MinhaJanela e do banco de dados. Algumas observa co es u teis para o diagrama de componentes: De posse do diagrama de componentes, temos a lista de todos os arquivos necess arios para compilar e rodar o programa. Observe que um assunto/pacote pode se transformar em uma biblioteca e ser a inclu do no diagrama de componentes. A liga ca o entre componentes pode incluir um estere otipo indicando o tipo de relacionamento ou algum protocolo utilizado.
<<biblioteca>> MtodosNumricos
<<arquivo>> A.obj
160
6.7.2
O diagrama de implanta ca o e um diagrama de alto n vel que inclui rela co es entre o software e o hardware e que se preocupa com os aspectos da arquitetura computacional escolhida. Seu enfoque e o hardware, a congura ca o dos n os em tempo de execu ca o. O diagrama de implanta ca o deve incluir os elementos necess arios para que o sistema seja colocado em funcionamento: computador, perif ericos, processadores, dispositivos, n os, relacionamentos de depend encia, associa ca o, componentes, subsistemas, restri co es e notas. Veja na Figura 6.31 um exemplo de diagrama de implanta ca o de um cluster. Observe a presen ca de um servidor conectado a um switch. Os n os do cluster (ou clientes) tamb em est ao conectados ao switch. Os resultados das simula co es s ao armazenados em um servidor de arquivos (storage ). Pode-se utilizar uma anota ca o de localiza ca o para identicar onde determinado componente est a residente, por exemplo {localiza ca o: sala 3}. Figura 6.31: Diagrama de implanta ca o.
Diagrama de implantao, inclui aspectos de hardware, conexes, drives. Mostra o hardware e as ligaes necessrias para rodar o programa.
<<Servidor>>
<<Processador1>> <<Processador1>> Servidor Lgico OpenMosix HD <<Processador2>> <<Core_1>> <<Core_2>> <<Core_3>> <<Core_4>> Demais clientes repetem configurao do cluster-01. Programa simulao
<<Processador2>>
6.8. IMPLEMENTAC AO
161
6.8
Implementa c ao
Nesta se ca o veremos como nos preparar para a implementa ca o, algumas dicas para implementa ca o da interface gr aca do programa, e como montar o c odigo inicial do programa com o umbrello.
6.8.1
Dica de UP fa ca um planejamento da implementa ca o (monte um plano). ` medida que se modelam as diversas classes e m A etodos, deve-se testar cada classe e cada m etodo desenvolvido (teste l ogico). A dica e criar classes de teste para testar as classes e subsistemas criados (veja o item 4 da se ca o 6.9). Antes de iniciar a implementa ca o de um m etodo complexo, voc e deve concluir o seu diagrama de atividades. Mantenha contato constante com os usu arios do sistema e esteja atento a custos e prazos.
6.8.2
Softwares modeladores como o umbrello, o dia e o Visual-Paradigm podem ser utilizados para montagem do c odigo inicial do programa. De modo geral, o c odigo e gerado a partir do diagrama de classes, e a maioria dos modeladores implementa uma casca inicial do programa que inclui as classes, seus atributos, m etodos, associa co es e documenta co es. Vimos na se ca o 4.4.2 o programa umbrello, o qual pode ser utilizado para gerar o c odigo inicial do programa. Uma das vantagens do umbrello e que ele e software livre e tem a capacidade de gerar os c odigos para diversas linguagens. C++, Actionscript, Ada, IDL, Java, JavaScript, Pascal, Perl, PHP, Python, Ruby, SQL, TCL, XMLschema. Nota: se voc e ainda n ao tem o programa umbrello instalado, veja na se ca o 4.4.2 como obter o umbrello. Leia o manual de instala ca o e instale o programa. Em seguida leia o manual do usu ario do umbrello para se familiarizar com o programa. Aprenda em detalhes como criar os diagramas de classe. Veja a seguir um roteiro para montar o c odigo inicial do programa com o umbrello. 1. Abra o programa umbrello. 2. Monte os diagramas de classes para seu sistema. Inclua todos os atributos, m etodos e associa co es necess arias. Como exemplo, voc e pode reproduzir o exemplo da Figura 4.8. 3. Revise o diagrama de classe. A id eia e s o gerar o c odigo depois que o diagrama de classe esteja correto. 4. Inclua as considera co es do projeto e revise novamente o diagrama. 5. Selecione o item de menu C odigo->Linguagem Ativa e logo ap os selecione C++. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
162
6. Selecione o item de menu C odigo->Assistente de Gera ca o de C odigo. No di alogo Assistente de Gera ca o de C odigo, selecione as classes que devem ter seu c odigo gerado e em seguida pressione o bot ao Pr oximo. 7. No di alogo Op co es de Gera ca o de C odigo temos 3 abas: (a) Geral voc e dene a linguagem a ser utilizada, al em da pasta onde o programa vai ser armazenado e a pol tica de substitui ca o de arquivos. (b) Formata ca o dene caracter sticas dos coment arios, tipo e quantidade de indenta ca o. (c) Op co es de linguagem dene caracter sticas espec cas da linguagem selecionada. Depois de fazer suas op co es pressione o bot ao Pr oximo. 8. Conra as classes selecionadas e ent ao pressione Gerar. O c odigo gerado estar a disponibilizado no diret orio informado. 9. Use o editor ou IDE de sua prefer encia para editar os c odigos gerados. Com o c odigo inicial do programa gerado por uma ferramenta CASE (como o umbrello ou o Visual-Paradigm ), parte-se para a implementa ca o do programa. Nesta etapa s ao essenciais n ao s o os conhecimentos da modelagem orientada a objeto, mas da linguagem de programa ca o, ou seja, as regras de sintaxe e a forma como a linguagem implementa a programa ca o orientada a objeto.
6.8.3
Para implementar a interface gr aca do programa, o engenheiro de software deve considerar aspectos como: Padroniza ca o (consist encia; opera co es semelhantes t em interfaces semelhantes). Na medida do poss vel, a interface deve ser orientada a objeto, isto e, os elementos visuais da interface devem representar objetos internos. Use threads (processamento paralelo). Por exemplo: e interessante ter uma thread separada respons avel pela atualiza ca o da interface gr aca do sistema, enquanto outras threads est ao realizando as atividades solicitadas. Di alogos devem lembrar as u ltimas op co es selecionadas. Voc e pode incluir um bot ao default. Veja um conjunto de instru co es para construir interfaces gr acas amig aveis no documento http://developer.gnome.org/projects/gup/hig/.
6.9
Teste de software
Apresenta-se nesta se ca o o teste de software: o que e, porque devemos testar nossos softwares, a equipe de teste e uma metodologia simplicada para o teste de software. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
163
6.9.1
O teste se preocupa com o funcionamento l ogico do programa, se o software cumpre com seus objetivos, se os requisitos de qualidade, usabilidade e performance foram atendidos, com o controle dos bugs. Segundo [Pressman, 2002], o objetivo do teste e encontrar o maior n umero poss vel de erros, com um m nimo de esfor co aplicado, durante um intervalo de tempo real stico. O objetivo prim ario do teste de software e diminuir as falhas de um software, tendo como conseq u encia uma redu ca o no custo e no tempo de desenvolvimento do software. Entre as vantagens de um software bem testado est ao o aumento da qualidade, da funcionalidade e a redu ca o das falhas. Outras conseq u encias de um software bem testado ea redu ca o na necessidade de suporte. Incluir no cronograma de desenvolvimento do sistema as atividades de teste. Controle o processo de teste. Voc e precisa denir o rigor, o n vel de detalhamento dos testes a serem realizados. Por exemplo: um programa para controle de v oo requer um sistema de testes extremamente rigoroso. Use procedimentos automatizados para execu ca o do teste (como check-list e programas de teste). Use uma metodologia de teste adaptada ` a sua equipe. Dica de XP: o planejamento e execu ca o do teste deve ser integrado ao projeto de desenvolvimento do sistema. Isto e, os testes do software devem ser realizados ao longo de todas as etapas de desenvolvimento.
6.9.2
Equipe de teste
O tamanho da equipe de teste depende do tamanho da equipe envolvida no projeto. Em alguns casos a equipe de teste e uma equipe separada. A seguir, ser ao brevemente apresentadas as responsabilidades de cada membro da equipe: Gerente respons avel pela infraestrutura do sistema de teste, pela montagem da equipe e pela sele ca o das ferramentas a serem utilizadas. Analista respons avel pelo planejamento do teste, estrutura l ogica do teste, cria ca o de check-list e an alise dos resultados obtidos. Testador realiza os testes e emite relat orios. Dica de XP: a metodologia eXtreme Programming indica a montagem de duas equipes, uma implementa as classes e a outra, o sistema de testes.
6.9.3
Metodologia de teste
Segundo [Sonerviile, 1993], o processo de teste evolue: teste de unidade, teste de m odulos, teste de subsistemas, teste do sistema e teste de aceita ca o. Existem diferentes metodologias de teste. Veja a seguir uma poss vel metodologia para o teste de seu software: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
O teste come ca na an alise dos requisitos, das especica co es O sistema especicado est a fechado (completo)? Teste dos casos de uso Eles fazem sentido? Est ao completos? Teste da interface (prot otipo) amig A interface satisfaz as necessidades do cliente? E avel? Montar uma equipe com dois a tr es usu arios que far ao testes com o prot otipo gerado, dando uma resposta a quesitos como funcionalidade, facilidade de uso, e sugest oes para melhoria da interface do sistema. 2. Teste da estrutura do sistema: Os assuntos/pacotes foram identicados? Eles fazem sentido? Os diagramas de classes est ao completos? 3. Teste da din amica do sistema (teste l ogico): Todos os diagramas de caso de uso foram considerados? Foram utilizados para montagem dos diagramas de comunica ca o? O teste l ogico e realizado sem nenhum c odigo; para tanto, partimos dos diagramas de casos de uso e criamos os diagramas de comunica ca o. No teste l ogico e vericada a integra ca o entre pacotes, componentes e classes. Quando necess ario os diagramas de m aquina de estado foram montados? Voc e montou os diagramas de atividade para os m etodos complexos? 4. Teste do projeto: A arquitetura e a plataforma escolhidas s ao adequadas? S ao multiplataforma? S ao extens veis? O sistema suportar a m ultiplos processos? O sistema permite o uso de processamento paralelo? 5. Teste de unidade (classes, atributos, m etodos e subsistemas): Utilizado para vericar se cada unidade (classe, subsistema) est a consistente. Deve ser realizado antes e depois da implementa ca o de cada classe. Classes: A classe tem sentido l ogico? Ela representa uma abstra ca o signicativa do problema? Testar a classe utilizando diagramas de comunica ca o. O programador implementa as diferentes classes e, para cada classe importante, cria uma classe de teste. A classe de teste deve testar toda interface da classe-alvo (m etodos p ublicos). Atributos: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
6.9. TESTE DE SOFTWARE O tipo e a precis ao s ao adequados? O atributo foi inicializado? O intervalo de valores e respeitado? M etodos:
165
Vericar as entradas, tipo dos par ametros, limites, precis ao. L ogica do m etodo/algoritmo (montar diagrama de atividade). Vericar aloca ca o/desaloca ca o de mem oria, uso de ponteiros. Vericar tipo de retorno, valores retornados. Cada m etodo deve ser testado com um conjunto de dados que inclua dadospadr ao e dados de exce co es (valores inv alidos). Primeiro, deve-se testar os casos simples, mais usuais; depois, os casos complexos, com os m etodos assumindo valores pr oximos aos extremos admitidos.
Pacotes: Pode-se criar pequenos programas para teste das classes de um pacote. 6. Teste de integra ca o: Consiste em testar a integra ca o entre as diversas partes do sistema (classes <-> subsistemas, subsistema<->subsistema). Testar a integra ca o entre as classes que fazem parte de um pacote/assunto ou hierarquia. Acesso, comunica ca o, funcionalidade (usar diagramas de comunica ca o, de atividades, de componentes). Testar integra ca o dentro de uma hierarquia. Testar as rela co es e integra co es entre pacotes/subsistemas: 7. Teste de compila ca o: Mensagens de warning. Verique todas essas mensagens, pois elas precisam ser eliminadas. Como os compiladores t em evolu do rapidamente, e normal aparecerem erros diferentes quando se compila o software com compiladores diferentes. A dica e compilar o programa em diferentes plataformas com diferentes compiladores. 8. Teste de sistema (usu ario <-> sistema): Teste de opera ca o normal com alguns usu arios (teste do sistema como um todo). Um cliente ou usu ario experiente pode ajudar um membro da equipe de desenvolvimento a montar uma estrutura de dados que ser a utilizada nos testes. Coloque usu arios para testar o sistema, avaliar sua qualidade, sua usabilidade (facilidade de uso do software). Deve-se usar a mesma equipe utilizada no teste da interface, mas agora testando o sistema em funcionamento. Os usu arios devem avaliar novamente a interface, o tempo de resposta do programa. Verique os seguintes aspectos: o programa produz os resultados esperados? Os dados incorretos s ao corretamente tratados? O programa e f acil de usar? A performance e satisfat oria? Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
Consiste em testar os limites do sistema (opera co es extremas). Os atributos e par ametros assumem valores extremos. Testar o desempenho do sistema, sua performance. Veja como aumentar a performance de seus programas e testar o desempenho de cada m etodo/fun ca o usando prolers no Cap tulo ?? Auditoria e Otimiza ca o de Programas. Teste de compatibilidade (multiplataforma) Teste de interoperabilidade. Verique se o sistema pode ser compilado e linkado em outras m aquinas, com outros sistemas e compiladores. A id eia e vericar se o sistema respeita o conceito multiplataforma. Testar/vericar o formato dos arquivos gerados. Vericar se o arquivo gerado em uma plataforma pode ser aberto em outra (a dica e usar padr oes abertos). Teste de seguran ca O sistema tem prote ca o contra ataques externos? Teste de aceita ca o Teste de instala ca o. O programa de instala ca o funciona? Teste dos manuais, tutoriais. Os manuais foram feitos? Foram revisados? Os links est ao corretos? Teste de vers oes Consiste em distribuir o sistema e receber o retorno dos usu arios (vers ao alfa e beta ). 9. Teste de regress ao: Toda vez que alteramos uma parte do sistema que estava funcionando, podemos adicionar novos bugs. O teste de regress ao e realizado para vericar se o programa continua funcionando. Para reduzir o n umero de testes de regress ao procure deixar suas classes completas. Deve ser realizado sempre que uma classe e alterada. Quando temos certeza de que programa est a correto, usamos o programa de teste para gerar uma sa da-padr ao, que e armazenada no disco (exemplo: NomeClasse.padrao.out). A cada nova execu ca o do teste, uma nova sa da e gerada (exemplo: NomeClasse.regressao.out). As duas vers oes s ao ent ao comparadas com o programa di. Se existirem diferen cas, ent ao o programa n ao passou no teste, e o c odigo precisa ser corrigido.
2
Dica: podemos incluir dentro dos arquivos Makele as instru co es para rodar o programa de teste e vericar se as sa das est ao iguais.
6.9.4
Manter uma lista enumerada com os bugs encontrados no arquivo bugs. Marcar os solucionados e os n ao-solucionados. Descrever o bug e as condi co es em que ocorre, al em de sua localiza ca o. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
167
O programa checker da GNU, obtido no endere co http://www.gnu.org/software/checker/, pode ser utilizado para vericar o acesso ` a mem oria realizado pelo seu programa. Segundo o site da GNU, o checker e uma ferramenta que procura erros de mem oria em tempo de execu ca o. Sua fun ca o prim aria e emitir mensagens de warning quando o programa realiza acesso a vari aveis n ao inicializadas, ou quando o programa acessa mem oria n ao alocada. Quando uma classe e enviada para o reposit orio, o sistema de controle das vers oes pode executar um programa auxiliar, este programa auxiliar pode ser o programa de teste (veja se ca o ??). Para realizar o teste de unidade, procure no google por Objetct Oriented Software and test. D e uma olhada no programa da GNU cppUnit, dispon vel em http://cppunit. sourceforge.net. Veja as refer encias: [Pressman, 2002, Emerson Rios, 2004, Winblad et al., 1993, Martin and McClure, 1993].
168
6.10
Documenta c ao do programa
A documenta ca o de um programa e essencial pelos seguintes motivos: Compreens ao do funcionamento do programa e de seu planejamento. Acompanhamento da execu ca o das atividades de implementa ca o, testes e depura ca o. Compreens ao e controle das atividades desenvolvidas. Prepara ca o dos manuais e da ajuda [help ]do programa. Permite a manuten ca o e a altera ca o do programa por terceiros. A Figura 5.1 ilustra as diversas etapas de desenvolvimento de um programa e os documentos que devem ser gerados. Observe que a documenta ca o e gerada ao longo do desenvolvimento do programa e deve servir de base para a elabora ca o dos manuais (estes devem ser desenvolvidos somente ap os a conclus ao do programa). Deve-se criar um diret orio onde ser ao armazenados os arquivos do programa a ser desenvolvido. Neste diret orio ser ao inclu das todas as informa co es relativas ao programa, ou seja, a documenta ca o da an alise orientada a objeto, do projeto do sistema, do projeto orientado a objeto, das bibliotecas desenvolvidas, dos testes realizados, o arquivo de help do programa (tutoriais e manuais). No diret orio-raiz crie um arquivo README/LEIAME, com informa co es b asicas sobre o sistema, um arquivo com instru co es para instala ca o do programa (INSTALL), um arquivo com a lista das modica co es (ChangeLog), um arquivo com as novidades da vers ao (NEWS), um arquivo com os bugs identicados/solucionados (BUGS), um arquivo com instruc o es sobre a licen ca do programa (COPYING), um arquivo com a lista de autores (AUTHORS) e um arquivo com questionamentos sobre poss veis mudan cas, tarefas (TODO). No arquivo INSTALL voc e precisa incluir a lista de bibliotecas externas (de terceiros) que ser ao utilizadas, informando tamb em como estas bibliotecas podem ser obtidas e instaladas (pr e-requisitos). Nota: para o desenvolvedor existe um efeito secund ario associado ` a documenta ca o do sistema, que e o estudo, a compreens ao e a descri ca o do pr oprio c odigo.
6.10.1
Veremos a seguir um conjunto de itens que devem estar presentes na documenta ca o de um software. Dentro de [] colocamos os itens opcionais. Esta lista de itens tem como base o sistema ao descritos na de documenta ca o JAVA DOC (o sistema JAVA DOC e o programa doxygen s se ca o ??) e o programa umbrello (veja a Figura 4.7). Podemos dividir a documenta ca o em duas partes, uma relacionada aos aspectos estruturais e outra, aos aspectos din amicos. Observe que dentro do sistema temos subsistemas e dentro dos subsistemas temos pacotes. Em alguns casos, temos componentes externos (como programas externos) e artefatos externos (como arquivos e tabelas). Veremos no cap tulo de programa ca o multiplataforma que podemos organizar nosso programa em pastas/subdiret orios, por isso, existe um item pasta. A seguir temos a documenta ca o das classes normais e classes de interface, al em de suas poss veis associa co es, atributos e m etodos. Podemos documentar ainda as enumera co es. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
DO PROGRAMA 6.10. DOCUMENTAC AO Documenta c ao do sistema Nome do sistema: [Subsistemas:] [Formas de acesso:] [Bibliotecas externas utilizadas:] Descri ca o: breve descri ca o do sistema (inclui suas responsabilidades). Documenta c ao dos subsistemas Nome do subsistema: [Nome do estere otipo:] [Visibilidade: p ublico, protegido, privado, de implementa ca o.] Descri ca o: breve descri ca o do subsistema, o que representa. Documenta c ao dos assuntos/pacotes Nome do assunto/pacote: [Nome do estere otipo:] [Visibilidade: p ublico, protegido, privado, de implementa ca o.] [Bibliotecas relacionadas:] [Classes relacionadas:] Descri ca o: breve descri ca o do pacote, o que representa. Documenta c ao dos componentes externos Nome do componente: [Nome do estere otipo:] [Execut avel: S/N.] [Visibilidade: p ublico, protegido, privado, de implementa ca o.] Descri ca o: breve descri ca o do componente, o que representa. Documenta c ao dos artefatos externos Nome do artefato: [Nome do estere otipo:] Desenhar como: padr ao, arquivo, biblioteca, tabela. [Visibilidade: p ublico, protegido, privado, de implementa ca o.] Descri ca o: breve descri ca o do artefato. Programa ca o Orientada a Objeto com C++
169
170 Documenta c ao das pastas (diret orios) Nome da pasta: [Nome do estere otipo:]
[Visibilidade: p ublico, protegido, privado, de implementa ca o.] Descri ca o: breve descri ca o da pasta. Documenta c ao das classes Nome da classe: [Nome do arquivo:] Autor: Data: Copyright: Licen ca: [Nome do estere otipo:] [Nome do pacote: assunto a que est a relacionada.] [Abstrata?] [Visibilidade: p ublico, protegido, privado, de implementa ca o.] [Superclasse:] [Concorr encia:] [Bugs identicados:] [See ou veja tamb em: link para informa co es externas.] Descri ca o: inclui descri ca o do objetivo da classe (tarefas, responsabilidades, colaboradores): Documenta c ao das classes de interface Nome da classe de interface: Autor: Data: Copyright: Licen ca: [Nome do estere otipo:] [Nome do pacote: assunto a que est a relacionada.] [Visibilidade: p ublico, protegido, privado, de implementa ca o.] Descri ca o: inclui descri ca o do objetivo da classe, sua forma geral de uso. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
DO PROGRAMA 6.10. DOCUMENTAC AO Documenta c ao das associa co es Nome da associa ca o: Tipo: [Multiplicidades:] [Atributo(s) de associa ca o:] Descri ca o: breve descri ca o da associa ca o. Documenta c ao dos atributos Nome: Tipo: [Valor inicial: valor m nimo: valor m aximo:] [Visibilidade]: p ublico, protegido, privado, de implementa ca o. [Restri co es:] [Derivado (S/N):] [Linguagem/escopo]: friend, const, static. [Nome do estere otipo:] Descri ca o: breve descri ca o do atributo. Documenta c ao dos m etodos Nome: Acesso: p ublico, protegido, privado. Retorno: Tipo Par ametros: Tipo [Nome do estere otipo:] [Precondi co es:] Tipo: virtual, est atico, normal, const. [Exce co es:] [Concorr encia:] Descri ca o: breve descri ca o da forma de uso. Programa ca o Orientada a Objeto com C++
171
[Visibilidade]: p ublico, protegido, privado, de implementa ca o. Descri ca o: breve descri ca o da enumera ca o. Relacionados aos aspectos din amicos temos a documenta c ao dos casos de uso, dos atores, das associa co es entre atores e casos de uso. Documenta c ao dos casos de uso Nome do caso de uso: [Nome do estere otipo:] [Abstrato?] [Visibilidade: p ublico, protegido, privado, de implementa ca o.] Documenta ca o: breve descri ca o do caso de uso. Documenta c ao dos atores Nome do atores: [Nome do estere otipo:] [Visibilidade]: p ublico, protegido, privado, de implementa ca o. Documenta ca o: breve descri ca o do ator. Dica: para documenta ca o embutida, utilize o formato JAVA DOC (veja a se ca o ??), e, para montar os manuais do usu ario, o sistema DOCBOOK (sgml/xml, usando o programa LYX).
6.10.2
Alguns desenvolvedores utilizam cart oes CRC (Classe/Responsabilidade/Colabora ca o). Um cart ao CRC e dividido em tr es se co es: no topo, o nome da classe; na coluna da esquerda, as responsabilidades; e na coluna da direita, os colaboradores. Veja a Tabela 6.32. Figura 6.32: Cart oes CRC: cClasse, responsabilidade, colabora ca o. Nome da classe: Responsabilidades Colaboradores
6.10.3
usual a cria E ca o de um arquivo de texto ou planilha em que constam os nomes das classes criadas e uma breve descri ca o. Funciona como um dicion ario das classes criadas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
173
6.11
A manuten ca o do programa envolve a corre ca o dos bugs remanescentes e a necessidade de se extender o programa. A quest ao da manuten ca o envolve ainda aspectos como custo da manuten ca o, custo para desenvolvimento de novas vers oes, al em de como manter a equipe de desenvolvimento. A reutiliza ca o consiste em elaborar um programa com a preocupa ca o de este ser posteriormente reaproveitado. A id eia por tr as do reuso do software e simples: construir m odulos, bibliotecas e classes que possam ser reaproveitados por voc e, sua equipe de desenvolvimento e por terceiros. Para conseguir o reuso devemos melhorar os protocolos e aumentar o empacotamento, viabilizando a constru ca o de bibliotecas e frameworks. Benef cios do reuso de software Redu ca o de custo. Software mais testado e debugado. Economia de tempo. Veja a seguir um conjunto de dicas, algumas extra das de [Winblad et al., 1993] e [Rumbaugh et al., 1994], para aumentar a reusabilidade.
6.11.1
Senten cas diversas: Documente e teste todos os sistemas desenvolvidos (veja a se ca o 6.9 e 6.10). Coloque os c odigos em reposit orios (veja o Cap tulo 6.11.1 Controle de Vers oes o cvs ). Sempre que poss vel use delega ca o. Como outras pessoas podem ter interesse em partes de seu c odigo, monte-o utilizando sistemas multiplataforma, mesmo que voc e sempre trabalhe com a mesma plataforma.
6.11.2
O conceito de empacotamento envolve a necessidade de se unir dois ou mais programas desenvolvidos por pessoas diferentes. Pode ocorrer que dois programadores desenvolvam classes com o mesmo nome e voc e ter a a necessidade de alterar o nome de uma delas. Uma linguagem que permite um bom empacotamento eliminar a esta necessidade. Felizmente C++ fornece o conceito de namespace (veja Cap tulo 10 Namespace), facilitando um bom empacotamento.
6.11.3
Na elabora ca o use abstra ca o; procure deixar o sistema gen erico. Deixe a interface de acesso ` a classe simples de usar (use oculta ca o). Elimine interfaces duplicadas. Existe a necessidade de se deixar o programa mais gen erico. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
174
A interface de acesso deve ser testada por outros usu arios ( e simples? faz sentido? obedece a um mesmo padr ao?). Se a estrutura das classes e id entica e pouco mut avel, use templates. Se a estrutura das classes e din amica, polim orca, use heran ca. O objeto se comporta como um objeto padr ao de C++? Os operadores foram sobrecarregados?
6.11.4
Construa m etodos reutiliz aveis. Deixe o m etodo o mais gen erico poss vel. Mantenha os m etodos pequenos, com menos de 30 linhas de c odigo. Mantenha os m etodos coerentes, por exemplo, executar uma u nica tarefa ou tarefas estreitamente relacionadas. Mantenha os m etodos consistentes, por exemplo, m etodos semelhantes devem ter nomes e formatos semelhantes. Separe m etodos pol ticos, aqueles que envolvem a tomada de decis oes, dos de implementa ca o, aqueles que realizam um procedimento espec co. Os par ametros dos m etodos devem ser passados de forma uniforme. Elimine par ametros n ao utilizados. N ao acesse informa co es globais em um m etodo. Evite m etodos que mudam seu comportamento drasticamente em fun ca o de altera co es no estado dos objetos ou que tenham inu encia do hist orico da execu ca o do sistema. C odigos legados (antigos) feitos por terceiros poder ao ser reaproveitados. Mas neste caso, voc e vai ter de fazer uma reengenharia neste c odigo. Comece encapsulando o c odigo de forma a deixar o acesso transparente, com os mesmos protocolos utilizados em seus sistemas. Abuse dos m etodos privados e evite m etodos p ublicos. Se parte de um algoritmo e repetida em dois m etodos diferentes (fA, fB), pense em criar um m etodo auxiliar, no qual o c odigo duplicado vai ser colocado. Se for uma heran ca, este m etodo auxiliar deve ser colocado na classe-base. Senten cas para construir m etodos robustos Um m etodo e robusto se ele n ao falha, mesmo quando recebe par ametros errados. Somente otimize o programa depois de este funcionar e ter sido testado. Valide argumentos de m etodos acessados pelo usu ario. N ao inclua atributos que n ao podem ser validados. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
E REUSO DE SOFTWARE 6.11. MANUTENC AO Evite limites predenidos. D e prefer encia ` a aloca ca o din amica de mem oria.
175
Reduza o n umero de par ametros, dividindo uma mensagem em v arias (n umero de argumentos <= 6). Reduza o tamanho dos m etodos para at e 30 linhas.
6.11.5
A montagem de bibliotecas ser a vista no Cap tulo ?? Bibliotecas e no Cap tulo ?? O Programa Libtool. Construa sua biblioteca utilizando a STL (descrita a partir do Cap tulo 31 Introdu ca o a Biblioteca Padr ` ao de Gabaritos de C++ STL). N ao coloque numa mesma biblioteca tens n ao correlacionados, ou seja, crie tantas bibliotecas quantas forem necess arias. Se for necess ario usar bibliotecas/vari aveis que n ao s ao multiplataforma, crie uma classe gen erica, multiplataforma, e crie classes herdeiras com c odigos espec cos para determinada plataforma. Veja a seguir dicas de [Winblad et al., 1993] para montagem de bibliotecas. muito importante que um objeto seja completo, para que possa ser utilizado como uma E biblioteca expans vel. Uma biblioteca de classes e algo gen erico, com a classe-base (superclasse), as classesderivadas, os atributos e os m etodos b asicos, al em da estrutura de liga ca o das classes. Uma biblioteca de classes precisa ser desenvolvida, planejada, pois n ao surge espontaneamente. Para facilitar o uso de uma biblioteca, podemos criar mais de uma interface de acesso, isto e, uma nova interface pode ser desenvolvida para atender um determinado tipo de uso. Depois de montar a vers ao 1.0 de sua biblioteca, preocupe-se em eliminar bugs, em sua otimiza ca o, antes de incluir novas funcionalidades.
6.11.6
Uma framework e uma biblioteca de classes que foi aprimorada, aperfei coada para solucionar os problemas espec cos de uma determinada area. As frameworks s ao o objetivo fundamental do projeto orientado a objeto, uma vez que representam o n vel mais alto de abstra ca o.Veja a seguir dicas de [Winblad et al., 1993] para montagem de frameworks. Identique classes-derivadas que implementem o mesmo m etodo de diferentes maneiras. Se um m etodo e sempre redenido, reconsidere onde estes m etodos poderiam estar mais bem localizados. Envie mensagens para outras classes em vez de para a pr opria classe. Substitua frameworks baseadas em hereditariedade por frameworks baseadas em componentes, sobrepondo m etodos com mensagens enviadas para os componentes. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
176
Identique conjuntos de m etodos combinados em uma classe somente para acessar um atributo de inst ancia comum. Considere a migra ca o de um ou mais m etodos para outras classes; mude os m etodos para passar par ametros expl citos. Isto facilitar a a divis ao de classes. Segundo Kent Beck (autor do modelo XP) [Teles, 2006], frameworks s ao arriscadas quando s ao desenvolvidas cedo demais, pois nesse caso ser ao dif ceis de usar. Se voc e estiver usando XP, primeiro voc e constr oi duas ou mais aplica co es e ent ao abstrai aquilo que e comum, fazendo com que aplica co es semelhantes sejam constru das mais facilmente no futuro. Note que esta dica e valida para qualquer metodologia, e n ao apenas XP.
6.11.7
` medida que o tempo passa, novas exig A encias (especica c oes) s ao realizadas pelos usu arios, e o analista/programador deve modicar o programa com o objetivo de dar resposta ` as novas necessidades do usu ario [Winblad et al., 1993]. Encapsular classes. Ocultar estruturas de dados. Evite percorrer muitas associa co es para executar determinada tarefa. Evite instru co es case sobre o tipo de objeto. Distinga m etodos p ublicos dos privados.
6.11.8
Veja a seguir um conjunto de senten cas para o desenvolvimento de programas em grande escala [Winblad et al., 1993, Rumbaugh et al., 1994]. N ao inicie o programa prematuramente. Mantenha os m etodos compreens veis. Fa ca m etodos leg veis. Utilize os mesmos nomes do modelo de objetos. Escolha os nomes cuidadosamente. Utilize diretrizes (regras) de programa ca o. Procure criar m odulos empacotando as classes. Documente as especica co es, classes, m etodos, atributos e as associa co es. Deixe o usu ario ter acesso a essas informa co es. Fa ca um documento de uso do programa pelo usu ario. Embora o texto apresentado nesta parte do livro seja introdut orio, considero-o suciente para a maioria dos sistemas a serem desenvolvidos por engenheiros ou novatos da area de Ci encias da Computa ca o, Inform atica ou Sistemas de Informa ca o. Para maiores informa co es sobre engenharia de software veja as refer encias: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
177
[Blaha and Rumbaugh, 2006, Teles, 2004, Guedes, 2004, Kruchten, 2003, Pressman, 2002, Fowler and Scott, 2000, Booch et al., 2000, Martin and McClure, 1993, Winblad et al., 1993, Booch, 1986, Coad and Yourdon, 1993].
6.12
Neste cap tulo aprendemos as diversas etapas para o desenvolvimento de um software. Desde a especica ca o at e a documenta ca o e a manuten ca o. Vimos que a especica ca o do programa deve ser feita textualmente e pode incluir cen arios de uso do programa, exemplos de uso. Os cen arios s ao visualizados com ajuda dos diagramas de caso de uso, os diagramas mais simples da UML. Em seguida, aprendemos que precisamos fazer uma elabora c ao do problema, um estudo do problema, envolvendo a an alise de dom nio, a identica ca o de pacotes e seus diagramas. Na etapa de an alise orientada a objeto, vimos que o modelo estrutural se preocupa com a identica ca o de classes, dos atributos, dos m etodos e com a montagem do diagrama de classe. Vimos como identicar as associa co es, agrega co es, composi co es, heran cas, restri co es, realiza co es e depend encias e como descrev e-las gracamente com os diagramas de classes. Pelo modelo din amico descrevemos a din amica do sistema, tanto do ponto de vista do usu ario (diagramas de caso de uso) quanto do ponto de vista do sistema. O macrosistema e representado pelos diagramas de sequ encia e de comunica ca o (eventos e mensagens). O comportamento das classes e descrito pelos diagramas de m aquinas de estado. J a a microdin amica, que ocorre dentro dos m etodos, e descrita pelos diagramas de atividade. Na etapa de projeto do sistema denimos conceitos como os protocolos API, a aloca ca o de recursos, a deni ca o do tipo de controle e a especica ca o das plataformas. Inclui ainda a sele ca o de bibliotecas e de ambiente de desenvolvimento. De posse do diagrama de implanta ca o identicamos todos os equipamentos necess arios para colocar o sistema em funcionamento. No projeto orientado a objeto aprendemos a montar os diagramas de componentes e de implanta ca o (execu ca o). Na implementa ca o aprendemos que podemos usar o umbrello para montagem do c odigo inicial utilizando os diagramas de classe. Aprendemos a import ancia do teste de software. Vimos que a documenta ca o e uma etapa fundamental para o desenvolvimento de programas com qualidade. Finalmente, a manuten ca o envolve tanto a adapta ca o do programa ` as novas solicita co es dos usu arios quanto a montagem de bibliotecas reutiliz aveis. Uma maneira de prever o futuro e estar sempre atualizado, ler revistas de programa ca o, inscrever-se em sites de discuss ao das APIs que for utilizar e inscrever-se em sites de desenvolvimento de software. Nota: deve-se ressaltar que os seus primeiros programas utilizando POO consumir ao o mesmo tempo que os desenvolvidos utilizando t ecnicas estruturadas. As vantagens do reaproveitamento aparecem ` a medida que os programas v ao sendo desenvolvidos, ou quando voc e j a disp oe de uma biblioteca OO e pode desenvolver o programa com ela.
6.13
Exerc cios
// Vari aveis float x,y,z, a,b,c;
178 float media,desvioPadrao; double area, perimetro, volume; double limiteInferior, limiteSuperior; float vetorDados [100]; // Fun c~ oes // Calcula area de uma figura double Area(..); double Perimetro(..); double Volume(..); // Calcula area de uma fun c~ ao double IntegralSimpson(..); double IntegralTrapezio(..); // Fun c~ ao de uma vari avel float Fy(float x); // Fun c~ ao de duas vari aveis float Fz(float x, float y); float FormulaBasca(..); // Calcula m edia de um grupo de dados, de um vetor float Media(..); float DesvioPadrao(..);
Monte o diagrama UML de um programa equivalente em C++ (diagrama de classes com atributos, m etodos e associa co es). Dica: voc e deve agrupar atributos e m etodos que se relacionam dentro de classes. 2. Para o diagrama de classes a seguir, acrescente alguns atributos e m etodos (e eventualmente classes) e estabele ca as rela co es entre as classes (associa co es, agrega co es e heran cas). Exemplos de atributos: nome, n umero, capacidade, valor, data, dimens oes, sexo, idade, extens ao, entre outros. Exemplos de m etodos: Contratar(), Despedir(), Abastecer(), Limpar(), PrepararPouso(), ConferirPassagem(), Manuten ca o(), ApertarCinto(), MoverFlaps(), CheckIn(), entre outros. Monte um diagrama de eventos para o piloto. Monte um diagrama de comunica ca o para o passageiro. 3. Descreva, de forma resumida, as etapas para o desenvolvimento de um programa. Diga quais s ao as quatro etapas mais importantes e justique. 4. Fa ca as especica co es de um programa que calcula o ajuste de um conjunto de pares ordenados x,y a uma fun ca o polinomial. Isto e, como determinar uma curva (polinomial, 1D = reta, 2D = par abola) usando m etodos como m nimos quadrados? (a) Monte um diagrama de caso de uso ilustrando cen arios de intera ca o do usu ario com o programa. (b) Monte os diagramas de classe incluindo os conceitos de associa ca o, agrega ca o e heran ca (generaliza ca o/especializa ca o). Justique suas decis oes. (c) Monte diagramas de m aquina de estado para alguma classe. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
179
(d) Monte diagramas de atividade para algum m etodo. Dica: crie classes de fun co es 1D, 2D, de estat stica, de ajuste de curvas, de um simulador.
180
Parte II
181
Cap tulo 7
Introdu c ao ao C++
Neste cap tulo veremos um pouco da hist oria de C++ (se ca o 7.1), exemplos de aplica co es em C+ (se ca o 7.2), o que e o ANSI C++ (se ca o 7.3) e quais as novidades de C++ (se ca o 7.4). Ademais, veremos quais s ao os tipos de programas em C++ (se ca o 7.5), as diferen cas de nomenclatura entre POO e C++ (se ca o 7.6), os conceitos de pr e-processamento, compila ca o, linkagem, debugagem e otimiza ca o (se ca o 7.7). Por m, veremos como e o layout de um programa em C++ com m ultiplos arquivos (se ca o 7.8).
7.1
C
A linguagem C foi desenvolvida por Denis Richard, em 1972, e teve origem na linguagem B, desenvolvida por Ken Thompson, em 1970. O ano de 1978 foi hist orico para a linguagem C, uma vez que naquele foi editado o livro The C Programming Language, o qual teve grande vendagem e foi o respons avel pela divulga ca o de C [Kernighan and Ritchie, 1988]. Veja a seguir algumas caracter sticas de C: O sucesso da linguagem C se deve ao fato de C ser independente de hardware. C tem sido utilizada em programas estruturados. A linguagem C e o sistema operacional Unix foram desenvolvidos conjuntamente. Isto signica que C/C++ e ambientes operacionais como Unix, GNU/Linux e Mac OS X t em uma intera ca o muito ntima. C++ Em 1980, Bjarne Stroustrup desenvolveu a linguagem de programa ca o C++, um superconjunto de C inicialmente chamado C com classes. Observe que o operador ++ e o operador de incremento; assim, C++ e o C incrementado. Isto signica que C++ apresenta uma s erie de vantagens em rela ca o ao C e tem se mostrado extremamente eciente nos mais variados campos de programa ca o, e por isso quase todas as grandes empresas que desenvolvem softwares utilizam C++. Mas, anal de contas, devo aprender C e depois C++, ou ir direto para C++? O criador do C++, Bjarne Stroustrup, arma: Estou rmemente convencido de que e melhor ir direto para C++ [Bjarne, 1999]. 183
184
Veja a seguir algumas caracter sticas de C++: E classicada como uma linguagem moderna, de quinta gera ca o. de alto n E vel, orientada a objeto. fortemente tipada. E linguagem de prop E osito geral, ou seja, pode ser utilizada para desenvolver praticamente utilizada nos mais variados tipos de computadores, sistemas todo tipo de programa. E operacionais, aplica co es e em todos os pa ses do mundo [Stroustrup, 2005]. a mais utilizada para montagem de sistemas complexos e grandes, como os sistemas E operacionais Windows, GNU/Linux, e programas como o Oce e o OpenOce. Nota: segundo o IDC International Data Corporation( http://www.idc.com/), a linguagem C++ tem mais de tr es milh oes de programadores; e esse n umero est a crescendo.
7.2
C++ e uma linguagem de programa ca o de m ultiplos prop ositos, podendo ser utilizada para cria ca o de v arios tipos de aplica co es. Veja a lista de exemplos de aplica co es em C++ no endere co http://www.research.att.com/~bs/applications.html. Desenvolvimento de sistema operacional (kernel, ferramentas, device drivers, rede etc) Microsoft Windows Vista, XP, NT, 98; BeOS (sistema operacional) Internet Internet Explorer; Mozilla, Firefox, Thunderbird Aplica co es com interface gr aca elaborada Microsoft Oce, FrontPage, Money, Project, Exchange, AppleWorks Sistemas gr acos, ambientes de janela, jogos Adobe Photoshop, Illustrator, Acrobat, CDE desktop. KDE. Banco de dados MySQL Sistemas CAD/CAM Autocad Ambientes de desenvolvimento, bibliotecas, linguagens derivadas Qt-designer, kdevelop; CORBA, MICO; C#, Java. Programa ca o cient ca Imago, Sail Veja a seguir alguns exemplos de empresas que usam C++: Amazon, Ericsson, Bloomberg, Google, IBM, Intel, Microsoft, Metrowerks, SGI, Autodesk. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
185
7.3
O ANSI C++ American National Standards Institute e um comit e que estabelece os conceitos b asicos da linguagem C++, principalmente os referentes ` a sintaxe. Se voc e desenvolver um programa compat vel com o ANSI C++, pode ter certeza de que ele poder a ser compilado por diferentes compiladores de C++ para diferentes plataformas. Note que o compilador tamb em deve estar dentro dos padr oes de C++. Em 1990 foi publicado o ANSI/ISO/IEC:9899:1990, que e o ANSI C ou [C90]. Em 1998 foi aprovado o ANSI/ISO/IEC:14882:1998[E], que e o ANSI C++ ou [C++98]. Em 1999 foi aprovado o ANSI/ISO/IEC:9899:1999[E], que e o ANSI C revisado ou [C99]. Em 2003 foi aprovado o ANSI/ISO/IEC:14882:2003[E], que e o ANSI C++ revisado inclu ndo o TR1 Technical Corrigendum 1, tamb em conhecido como [C++03]. Para 2009 est a prevista a aprova ca o do ANSI/ISO/IEC:14882:2009, que e o ANSI C++ com as inova co es do C++0x. Este livro cobre as deni co es estabelecidas pelo comit e ANSI C++. Nota: voc e encontra maiores informa co es do ANSI C++ no site http://www.open-std.org/ jtc1/sc22/wg21/. As inova co es do C++0x ser ao apresentadas no Cap tulo ?? C++0x O que vem por a ?
7.4
A linguagem C++ e uma das melhores linguagens de programa ca o existentes, porque agrupa formula co es altamente abstratas como classes (que permitem um trabalho de alto n vel) e formula co es de baixo n vel (como o uso de ponteiros, aloca ca o din amica de mem oria e at e a utiliza ca o de chamadas de interrup co es que realizam tarefas altamente espec cas). Com C++ um u nico programador consegue gerenciar uma quantidade maior de c odigo. Veja a seguir algumas novidades e vantagens de C++. Como novidades de C++ em rela c ao ao C podemos citar a utiliza ca o de classes, fun co es inline, convers ao de tipo, verica ca o de par ametros de fun ca o, operadores para gerenciamento de mem oria (new/delete), refer encias, constantes, sobrecarga de operador, sobrecarga de fun co es, polimorsmo, templates (gabaritos), tratamento de exce co es e namespaces. Destes novos conceitos, os que mais se destacam s ao o uso de classes, do polimorsmo e os templates. Como vantagens de C++ em rela c ao ao C podemos citar aumento da produtividade, maior reaproveitamento de c odigo, maior qualidade geral do projeto, facilidade de extens ao e manuten ca o. Maior compreens ao geral por toda a equipe de desenvolvimento. importante notar que essas vantagens s E ao compreendidas na medida em que se usa C++. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
186
7.5
Como dito, C++ e um superconjunto de C que foi desenvolvido para dar suporte ` a programa ca o orientada a objeto. A implica ca o dessa heran ca de C em C++ e que voc e ir a se deparar com programas nos seguintes formatos: Programa estruturado escrito em C utiliza os conceitos b asicos de C, dados e fun co es separados. Programa estruturado escrito em C++ utiliza alguns conceitos de C++, como cin/cout, switch, fun co es inline, const e refer encias, ou seja, utiliza algumas novidades de C++ (exemplos nos ap endices). Programa baseado em objeto escrito em C++ utiliza os conceitos de classes e heran cas. Inclui controle de acesso (public, protected e private), fun co es friend e o conceito fundamental de classes (exemplos a partir do Cap tulo 11 Classe). Programa orientado a objeto escrito em C++ inclui o conceito de polimorsmo e pode incluir a utiliza ca o de conceitos da STL, como containers e iteradores (exemplos a partir do Cap tulo 19 Polimorsmo). Programa gen erico escrito em C++ inclui os conceitos de programa ca o gen erica. Inclui a utiliza ca o de algoritmos gen ericos da STL, uso intensivo de containers e iteradores (exemplos na Parte III: Introdu ca o a STL). Este livro tem enfoque na programa ca o orientada a objeto em C++ e na programa ca o gen erica.
7.6
A Tabela 7.1 mostra as diferen cas entre a nomenclatura da programa ca o orientada a objeto (Parte I Filosoa e modelagem orientada a objeto) e a nomenclatura de C++. Neste livro procurei usar sempre os nomes objeto, atributo e m etodo. Chamarei de fun ca o apenas as fun co es globais e fun co es de C, e chamarei de m etodo as fun co es que s ao implementadas como parte de uma classe. O objetivo e aproximar os conceitos da POO aos de programa ca o em C++. Tabela 7.1: Diferen cas na nomenclatura da POO e de C++. Nomenclatura POO Nomenclatura C++ Objeto Objeto Classe Classe M etodo M etodo/Fun ca o Atributo Atributo, vari avel Mensagem Chamada de fun ca o Subclasse Classe-derivada Superclasse Classe-base Hereditariedade Hereditariedade, deriva ca o
187
7.7
S ao descritos a seguir alguns conceitos gerais e a seq u encia usual para montagem de um programa. Etapa de edi c ao Um programa em C++ e composto por um ou mais arquivos de texto com as extens oes .h (declara ca o de classes) e .cpp (deni ca o de m etodos da classe). Um arquivo do programa e formado por um conjunto de instru co es de programa ca o que s ao organizadas logicamente para realizar determinadas tarefas. Veja na Figura 7.1 os arquivos de texto Class1.h, Class1.cpp, Class2.h, Class2.cpp e Prog.cpp. Etapa de pr e-processamento a primeira fase da compila E ca o de um programa. Nela o compilador verica as instru co es passadas com o sinal #. Primeiro s ao inclu dos os arquivos externos, depois s ao processadas as macros. Na fase de pr e-processamento, cada letra do arquivo de disco e mapeada para o padr ao Unicode (ISO/IEC 10646) e posteriormente para o conjunto de caracteres de execu ca o. O resultado da fase de pr e-processamento e uma seq u encia de s mbolos que chamamos de unidade de tradu ca o. A unidade de tradu ca o e independente de outros arquivos (veja Figura 7.1). Note ainda que cada arquivo do programa e compilado separadamente. No exemplo a seguir a unidade de tradu ca o vai incluir o arquivo <iostream>. Exemplo: // Arquivo Prog.cpp #include <iostream> int main() { std::cout < < "Oi tudo bem!";
return 0; }
Para gerar o arquivo de pr e-processamento digite: g++ -E Prog.cpp > Prog.ii . Note que o arquivo gerado e muito grande. Etapa de compila c ao o compilador O compilador e o programa respons avel pela convers ao do programa (texto) escrito usando uma linguagem de programa ca o, em c odigo bin ario (linguagem de m aquina); ou seja, o compilador realiza a tradu ca o do c odigo em linguagem de m aquina. Adicionalmente, o compilador encontra os erros de sintaxe do programa e, depois de compilado, o programa passa a ter um arquivo objeto *.obj (*.o no Unix, GNU/Linux). Observe na Figura 7.1 que cada classe tem dois arquivos (Class1.h e Class1.cpp) e que, ap os a compila ca o do Class1.cpp, e gerado o arquivo Class1.o. Etapa de liga c ao o linker O linker e o programa que agrupa um ou mais arquivos objeto *.obj (*.o) em um arquivo execut avel, resolvendo as depend encias (entre os arquivos) e fazendo as liga co es necess arias. Os erros de liga ca o s ao detectados pelo linker. Os arquivos que ser ao agrupados s ao relacionados em um arquivo de projeto ou em um arquivo Makele. Depois de linkado um programa tem um arquivo execut avel (*.exe no Windows, a.out no GNU/Linux). Na Figura 7.1, o linker e utilizado para gerar o programa nal. Veja na Tabela 7.2 as extens oes dos arquivos gerados nas Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
188
compilador
[opcional]
Class1.o
lib Biblioteca
Class2.o
Prog
diferentes plataformas. Observe que diversos arquivos objeto .o podem ser agrupados em uma biblioteca. Etapa de debugagem o debuger O debuger e um programa que ajuda o programador a encontrar os erros de programa ca o os famosos bugs. Com um debuger podemos analisar a execu ca o do programa passo a passo (ou linha a linha), e a cada passo podemos vericar o que est a acontecendo. Etapa de otimiza c ao o proler O proler e um programa que ajuda o programador a identicar os pontos do programa que consomem mais tempo (ou seja, onde o programa est a lento). De posse dessa informa ca o podese melhorar a qualidade do programa e a sua velocidade;. para isso, apenas rode o programa de dentro do proler e analise os resultados de tempo de execu ca o de cada fun c ao. Tabela 7.2: Extens oes usuais dos arquivos nas diferentes plataformas. Situa ca o DOS/Windows Unix, GNU/Linux Mac antes de compilar nome.h/nome.cpp nome.h/nome.cpp nome.h/nome.cpp depois de pr e-processar nome.ii nome.ii nome.ii depois de compilar nome.obj nome.o nome.o depois de linkar nome.exe a.out ou nome a.out ou nome Veremos as diretrizes de pr e-processador no Ap endice A Diretrizes de pr e-processador. Veremos em detalhes o compilador da GNU, o g++, no Cap tulo ?? Compilando com gcc e g++. Veremos a debugagem de programas no Cap tulo ?? Uma introdu ca o aos bugs e a debugagem de programas e no Cap tulo ?? Os programas gdb, ddd e o bugzilla. Por m, veremos o uso de prolers no Cap tulo ?? Auditoria e otimiza ca o de programas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
189
7.8
Veremos nesta se ca o o layout e uma estrutura-padr ao para os arquivos de um programa orientado a objeto em C++; j a no pr oximo cap tulo, veremos nossos primeiros exemplos. A implementa ca o de um programa inicia com a deni ca o do arquivo de projeto. Ele lista todos os arquivos que fazem parte do projeto (veja se ca o 7.8.1). Depois de criado o arquivo de projeto, s ao criados os arquivos de cabe calho (*.h) com a deni ca o da classe, e os arquivos de implementa ca o (*.cpp) com a deni ca o dos m etodos da classe. Note na Figura 7.1 que, para cada classe criada, s ao gerados dois arquivos, CNomeClasse.h e CNomeClasse.cpp. O programa principal, aquele que tem a fun ca o main(), deve estar em um arquivo separado, com a extens ao .cpp (exemplo: Programa.cpp). Nas se co es que seguem apresentaremos o prot otipo e a em seguida um exemplo de cada tipo de arquivo. O arquivo de cabe calho da classe (*.h) e apresentado na se ca o 7.8.2, e um exemplo, a declara ca o da classe CAplicacao, e apresentado na listagem 7.1. O arquivo de implementa ca o da classe (*.cpp) e apresentado na se ca o 7.8.3, e um exemplo, a implementa ca o dos m etodos da classe CAplicacao, e apresentado na listagem 7.2. O arquivo de implementa ca o da fun ca o main() e apresentado na se ca o 7.8.4, e um exemplo e apresentado na listagem 7.3.
7.8.1
Arquivo de projeto
A organiza ca o dos programas separando o c odigo em diversos arquivos facilita sua manutenc a o e possibilita um maior entendimento da estrutura dos programas; conseq uentemente, todo o processo de compila ca o/recompila ca o ca mais r apido. O arquivo de projeto dene quais arquivos fazem parte do programa e em que seq u encia devem ser compilados. Ademais, ele cont em uma lista com os nomes dos arquivos de cabe calho (*.h) e de implementa ca o (*.cpp) e a forma como os mesmos ser ao compilados e linkados. Vimos na se ca o 6.6.6 os diferentes compiladores e ambientes de desenvolvimento de C++. Cada ambiente de desenvolvimento gera um arquivo de projeto pr oprio. Por exemplo: um arquivo de projeto do Borland C++ tem a extens ao *.ide ou *.prj; um arquivo do Microsoft Visual C++, por sua vez, tem a extens ao *.mfc. No kdevelop a extens ao e *.kdevelop, e no Dev C++, *.dev. No Unix e no GNU/Linux, o arquivo de projeto costuma ser um arquivo Makele. Nota: veremos, no Cap tulo ?? Make, como montar arquivos de projeto Makele e, no Cap tulo ?? Montagem de um programa multiplataforma com ferramentas da GNU, como montar arquivos de projeto independente de plataforma. Veja exemplo de arquivo Makele na se ca o ??.
7.8.2
A deni ca o da classe e armazenada em arquivos de cabe calho com a extens ao *.h. Observe no prot otipo a seguir que inclu mos a documenta ca o. No primeiro bloco de coment arios inclu mos informa co es gerais sobre o programa, o nome do arquivo e dos autores. Depois inclu mos as bibliotecas padr oes de C++ que ser ao utilizadas e iniciamos a deni ca o da classe com um breve coment ario sobre o que a classe e e representa. Em seguida denimos a forma de acesso a cada atributo/m etodo. Por m, declaramos os atributos e m etodos da classe colocando um breve coment ario sobre o que cada atributo/m etodo representa. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
190
Prot otipo: /** Cabe calho do programa Documenta ca o geral do programa, do sistema como um todo. @autor nome do(s) autor(es) @le CNomeClasse.h */ /// Inclus ao das bibliotecas padr oes de C++ #include <iostream> /// Documenta ca o da classe CNomeClasse /// O que a classe e e representa... class CNomeClasse { /// Especica ca o do controle de acesso public: /// Declara ca o de atributo Tipo nomeAtributo; /// Declara ca o de m etodo TipoRetorno NomeM etodo(Par ametros); }; Apresenta-se na listagem 7.1 o arquivo de cabe calho da classe. Al em da declara ca o e deni ca o da classe, inclu mos uma breve documenta ca o da classe e uma descri ca o do m etodo Run(). Procurou-se incluir a maioria dos itens presentes em um programa real. Listing 7.1: Exemplo b asico: Arquivo de cabe calho da classe.
// Este p r o g r a m a e x e m p l i f i c a a e s t r u t u r a / layout de um // p r o g r a m a t pico em C ++ /* * D e c l a r a uma classe minimalista , a classe C A p l i c a c a o A mesma inclui apenas um m e todo , o m e todo Run () . * */ class CAplicacao { public : // / M e todo de e x e c u c~ a o da a p l i c a c~ ao. void Run () ; };
Nota: vimos informa co es b asicas sobre documenta ca o de programas na se ca o 6.10. Veremos, ent ao, como implementar a documenta ca o em C++ no Cap tulo ?? Documenta ca o de programas.
7.8.3
As deni co es dos m etodos da classe s ao armazenadas em arquivos de implementa ca o com a extens ao (*.cpp). Observe, no prot otipo a seguir, que sempre incluiremos o arquivo com o nome da classe #include "CNomeClasse.h". Prot otipo: /** Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
7.8. LAYOUT DE UM PROGRAMA ORIENTADO A OBJETO EM C++2 Cabe calho do programa Documenta ca o geral do programa, do sistema como um todo. Implementa os m etodos da classe CNomeClasse,... @autor nome do(s) autor(es) @le CNomeClasse.cpp */ /// Inclus ao das bibliotecas .padr ao de C++ #include <iostream> /// Inclus ao das bibliotecas do grupo de programadores #include CNomeClasse.h /// Deni ca o dos m etodos da classe TipoRetorno CNomeClasse::NomeM etodo(Par ametros) { ..Conjunto de tarefas a serem realizadas..; }
191
Apresenta-se na listagem 7.2 o arquivo de implementa ca o da classe CAplicacao. Observe que depois de incluir o arquivo CAplicacao.h, implementamos o c odigo do m etodo Run(). Listing 7.2: Exemplo b asico: Arquivo de implementa ca o da classe.
Este p r o g r a m a e x e m p l i f i c a a e s t r u t u r a / layout de um p r o g r a m a t pico em C ++ */ # include < iostream > // / Inclui a d e c l a r a c~ a o da classe # include " CAplicacao . h " // / I m p l e m e n t a os m e t o d o s da classe // / O m e todo Run () e s c r e v e uma m e n s a g e m na tela void CAplicacao :: Run () { // std :: cout e s c r e v e na tela o texto " Bem - vindo ao C ++!" std :: cout << " Bem - vindo ao C ++! " << std :: endl ; } /* *
Nota: em Java todo c odigo da classe ca em um u nico arquivo. Prero o formato usado por C++; a separa ca o da implementa ca o em um arquivo *.cpp deixa o arquivo de cabe calho mais enxuto e mais claro.
7.8.4
Al em do arquivo de deni ca o *.h e do arquivo de implementa ca o *.cpp, voc e vai precisar de um arquivo com a deni ca o da fun ca o main(), a qual e chamada quando o programa e executado. O arquivo programa.cpp usa as classes denidas pelo programador. Veja o prot otipo a seguir: Prot otipo: /** Cabe calho do programa Documenta ca o geral do programa, do sistema como um todo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
192 @autor nome do(s) autor(es) @le programa.cpp */ /// Inclui as classes que ser ao utilizadas #include CNomeClasse.h /// Implementa a fun ca o principal, main() int main() { TipoPar ametro par ametro; // Cria par ametro CNomeClasse objeto; // Cria objeto objeto.NomeM etodo(par ametro); // Usa m etodo do objeto criado return 0; }
7.9. SENTENCAS
Veja na listagem 7.3 a implementa ca o da fun ca o main(). O programa inicia com a fun ca o main(), na qual um objeto do tipo CAplicacao com nome ap e criado. O objeto ap executa o m etodo Run() que envia para a tela a mensagem "Bem-vindo ao C++". Ap os a execu ca o do m etodo Run(), o controle volta para a fun ca o main() e termina ao nal desta fun ca o com um return 0;. Para compilar o programa no GNU/Linux g++ Programa.cpp CAplicacao.cpp Para executar o programa no GNU/Linux /a.out Listing 7.3: Exemplo b asico: Arquivo de implementa ca o da fun ca o main().
/* * Este p r o g r a m a e x e m p l i f i c a a e s t r u t u r a / layout de um p r o g r a m a t pico em C ++ */ // Inclui o a r q u i v o " C A p l i c a c a o . h " que tem a d e c l a r a c~ a o da classe C A p l i c a c a o # include " CAplicacao . h " // A fun c~ a o main () , r e t o r n a um inteiro , se chama main () e // n~ a o tem nenhum p a r ^ ametro int main () { CAplicacao ap ; // Cria objeto do tipo C A p l i c a c a o com nome ap ap . Run () ; return 0; } Bem vindo ao C ++! // E x e c u t a o m e todo Run () do objeto ap // A fun c~ a o main () deve r e t o r n a r um i n t e i r o // o zero indica que o p r o g r a m a t e r m i n o u bem .
7.9
Senten cas
Observe que, de modo geral, arquivos de programa ca o em C t em a extens ao .c, e arquivos de programa ca o em C++ t em a extens ao .cpp (de C plus plus ou C mais mais). C++ e extensivamente utilizado em aplica co es cient cas, em programas com interface gr aca e em programas com muita intera ca o com o usu ario. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
193
Programas de engenharia, f sicos e matem aticos s ao bem representados em C++, pois as diferentes areas da matem atica s ao facilmente modeladas como classes em C++. Isto e, faz-se uma associa ca o clara entre conceitos matem aticos e classes de C++. Se voc e utilizou uma ferrramenta UML como o umbrello (veja se ca o 4.4.2), pode gerar automaticamente a estrutura inicial dos arquivos *.h e *.cpp. Assim, para cada classe criada, o umbrello gera os respectivos arquivos .h e .cpp.
7.10
Neste cap tulo aprendemos um pouco sobre a hist oria da linguagem C++, a qual tem origem na linguagem C, que, por sua vez, e derivada da linguagem B. Ser a que existiu uma linguagem A? Vimos que a linguagem C++ e derivada da linguagem C e que, em fun ca o das transforma co es ocorridas nos u ltimos anos, podemos ter programas C++ em diferentes formatos: estruturado, baseado em objeto, orientado a objeto, ou, ainda, utilizando programa ca o gen erica. Aprendemos que o ANSI C++ e o comit e respons avel pela padroniza ca o de C++ e que, ao fazermos um programa usando ANSI C++, esse deve compilar e rodar em centenas de plataformas. Vimos as diferen cas na nomenclatura de POO e C++. Aprendemos os conceitos b asicos de compila ca o, gera c ao do c odigo objeto, e a linkagem montagem do programa execut avel. Vimos que os debugers s ao utilizados para localiza ca o dos bugs do programa e que os prolers s ao utilizados para melhorar a performance do programa. Por m, vimos o layout de um programa em C++. Dica: ao nal de cada cap tulo dedique cerca de 5-10 minutos para fazer uma r apida revis ao dos conceitos apresentados.
7.11
Exerc cios
1. Fa ca uma pesquisa na internet sobre a hist oria de C++. 2. Quais as vantagens da padroniza ca o do Ansi C++? 3. V a at e o site do Ansi C++ (procure por Ansi C++) e veja quais novidades est ao previstas para os pr oximos anos. 4. Procure na biblioteca por livros de C/C++. Coloque-os em ordem de data de publica ca o e, em seguida, compare os c odigos. Veja que a forma como os programas s ao desenvolvidos tem modicado constantemente (veja se ca o 7.5). 5. Quais s ao as tarefas do compilador? 6. Quais s ao as tarefas do pr e-processador? 7. Quais s ao as tarefas do linker? 8. O que s ao e para que servem os debugers e os prolers? 9. Quantos arquivos t em um programa OO m nimo em C++. Qual e sua extens ao e conte udo?
194
Cap tulo 8
8.1
Veremos a seguir alguns conceitos b asicos da sintaxe de C++. Esses conceitos ser ao mais bem compreendidos posteriormente, com as listagens de programas que ser ao apresentadas. Arquivo e um texto que cont em c odigo-fonte em C++ e diretrizes para o pr e-processador. Coment arios s ao utilizados para descrever/detalhar o funcionamento de determinadas partes do c odigo. Um coment ario em C utiliza os caracteres /* para iniciar o coment ario e */ para encerrar o coment ario. Um coment ario em C++ utiliza duas barras //; tudo o que estiver ap os as duas barras e coment ario. Note que o arquivo e composto por linhas de texto e que o coment ario de C++ e v alido apenas para linha em que foi inclu do. Exemplo: /* Aqui e coment ario */ Aqui e programa ; // Aqui e coment ario. S mbolos existem cinco tipos de s mbolos em um programa C++: palavras-chave, identicadores, operadores, literais e separadores. Esses tipos de s mbolos s ao brevemente descritos a seguir. Palavras-chaves s ao de uso interno do C++, t em signicado para a linguagem, para o processo de compila ca o, e n ao podem ser utilizados para nomear objetos. Veja se ca o 8.2. Identicadores um identicador e uma seq u encia de letras usadas pelo programador para dar nome aos objetos, atributos e m etodos. Um nome denota um objeto, uma 195
196
8.1. SOBRE A SINTAXE DE C++ fun ca o, um enumerador, um tipo, um membro de classe, um modelo, um valor ou um label (veja se ca o 8.3). Al em disso, pode estar denido em uma biblioteca externa. No exemplo a seguir criamos tr es n umeros inteiros com os nomes x, y, z. Exemplo: int x,y,z; char nomeDaPessoa[50]; // x,y e z s~ ao identificadores // nomeDaPessoa e um identificador
Operadores o s mbolo + e o operador soma, sendo utilizado para somar dois objetos. J a o operador ++ e utilizado para incrementar o valor de uma vari avel, ou seja, operadores s ao s mbolos cuja utilidade j a e denida pelo C++. Os operadores de C++ est ao listados na Tabela C.1. Veremos os operadores em detalhes no Ap endice C Operadores. No exemplo a seguir temos tr es exemplos de operadores: operador soma (+), que e bin ario (atua sobre dois objetos); operador incremento (++), que e un ario (atua sobre um u nico objeto); e o operador de compara ca o maior que (>) . Neste exemplo, se x for maior do que y retornar a verdadeiro. Exemplo: + e o operador de soma ( e um operador bin ario). ++ e o operador de incremento ( e um operador un ario). x > y; o s mbolo > e o operador maior que. Literais tipos de vari aveis previamente denidas pela linguagem C++ para representar objetos de uso corrente. Como exemplo podemos citar: um booleano, um caracter, um n umero inteiro, um n umero em ponto utuante, uma string constante. Exemplo: int x = 5; char c = a; float y = 5.3; char* nome = "Vinicios"; // // // // O n umero 5 e um literal A letra a e um literal O n umero 5.3 e um literal Vinicios e um literal
Declara c ao diz que existe um objeto com nome fulano de tal, mas n ao cria o objeto. Uma declara ca o pode ser repetida (veja se ca o 8.4). A partir de sua declara ca o um objeto pode ser utilizado. Exemplo: extern int a; extern const int c; int f(); struct S; class C; // // // // // Declara Declara Declara Declara Declara um inteiro a inteiro constante C que existe uma fun c~ ao f() que existe uma estrutura S que existe uma classe C
Deni c ao uma deni ca o cria um ou mais objetos e reserva mem oria. Uma deni ca o n ao pode ser repetida (veja se ca o 8.5). Veremos o uso de extern na se ca o B.2.1. Exemplo: int b; extern const int c = 1; int f(){ return 5; }; // Cria/define um n umero inteiro b // Atribue valor para c // Define a fun c~ ao f()
Atribui c ao quando se armazena algum valor no objeto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
197
Classes de armazenamento denem o tempo de vida de um objeto, podendo ser est atico (existe durante toda execu ca o do programa) ou din amico (existe por um determinado per odo de tempo). Veja nas se co es B.1 e B.3 informa co es sobre classes de armazenamento e modicadores de acesso. Escopo dene onde um objeto e vis vel. O escopo pode ser local {bloco}, de fun ca o, de arquivo, de classe ou global (veja se co es 8.12 e B.4). Blocos um bloco se inicia com { e termina com }. Objetos criados dentro do bloco est ao no escopo do bloco e n ao podem ser acessados externamente. Objetos criados dentro do bloco s ao objetos autom aticos, e estes s ao automaticamente destru dos quando o bloco e encerrado. Exemplo: { ... } // Inicio do bloco // Fim do bloco
Tipos predenidos tipos de objetos previamente denidos pela linguagem C++ (veja Cap tulo 9 Tipos). Exemplo: int x; long int r; unsigned int s; float y; double z; // // // // // N umero N umero N umero N umero N umero inteiro, com nome x inteiro longo com sinal, com nome r inteiro sem sinal, com nome s flutuante, com nome y com dupla precis~ ao, com nome z
Tipos derivados tipos denidos pelo programador, como estruturas, enumera co es e uni oes (veja Cap tulo 9 Tipos). No exemplo a seguir denimos a classe CPessoa, com os atributos nome e idade. Exemplo: class CPessoa { public: string nome; int idade; }; // CPessoa e um tipo do usu ario
Especicador e uma palavra-chave da linguagem que e utilizada para denir o tipo do objeto ou modicar determinado tipo. Por exemplo: um especicador inline e utilizado para modicar a forma com que a fun ca o/m etodo ser a compilada. Um especicador de tipo informa o tipo do objeto. Um especicador typedef e usado para criar um apelido para um tipo conhecido (veja Cap tulo 9 Tipos). Exemplo: int x; inline void f() { cout < < "saida" < < typedef float racional; // int e o especificador // inline e o especificador endl; } // typedef e float s~ ao o especificador Andr e Duarte Bueno
198
Lvalues um objeto e uma regi ao de armazenamento de mem oria. Um lvalue e uma express ao que se refere a um objeto ou fun ca o (o retorno e algo ativo). Pode aparecer ` a esquerda do sinal igual (=), podendo ser alterado. Objetos especicados como const n ao s ao lvalues. Exemplo: int x = 3; const int y = 3; // x e um lvalue. // y N~ AO e um lvalue.
Diretrizes de pr e-processador s ao informa co es/instru co es que s ao passadas para o compilador com o s mbolo #. Veremos o uso das diretrizes de pr e-processador no Ap endice A Diretrizes de pr e-processador.
8.2
Palavras-chave do C++
Uma linguagem de programa ca o faz uso extensivo de determinadas palavras, denominadas palavras-chave. Essas palavras foram denidas para a linguagem C++ e s ao utilizadas pelo programador com algum objetivo espec co. Como essas palavras j a t em um signicado predenido para a linguagem, voc e n ao pode declarar um objeto com o mesmo nome de uma palavra-chave, pois o compilador faria uma confus ao e acusaria erro. Com o objetivo de economizar palavras, algumas palavras-chave t em mais de uma utilidade, por exemplo, a palavra-chave virtual, que pode especicar um m etodo virtual ou uma heran ca virtual. Outro exemplo e void, que, para ponteiros, e um ponteiro para qualquer coisa e, para m etodos, signica aus encia de par ametros ou aus encia de retorno. Veja as palavraschave do ANSI C++ na Tabela 8.1. As palavras-chave est ao classicadas de acordo com seu uso. Tabela 8.1: Palavras chaves do ANSI C++. Tipos Modicadores de tipos Controle L ogicos Mem oria Controle de acesso Convers oes Exce co es Diversos bool, char, wchar_t, short, int, long, float, double, long double, void auto, const, extern, mutable, register, signed, static, typedef, unsigned, volatile break, case, continue, default, do, else, for, goto, if, return, switch, while and, and_eq, bitand, bitor, compl, false, not, not_eq, or, or_eq, true, xor, xor_eq delete, new private, protected, public const_cast, dynamic_cast, reinterpret_cast, static_cast try, throw, catch asm, class, enum, explicit, export, friend, inline, namespace, operator, sizeof, struct, template, this, typeid, typename, union, using, virtual
Dica: a linguagem C/C++ reservou alguns identicadores para uso futuro voc e deve evitar o seu uso. S ao eles: is (exemplo: isblank), mem, str (exemplo: strtof), to, wcs. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
199
8.3
O nome de um objeto deve come car com uma letra (a-z, A-Z) ou sublinhado ( ). A linguagem C++ difere mai usculas e min usculas, ou seja, AA e diferente de aa. A especica ca o-padr ao de C++ tamb em permite o uso de caracteres especiais como . Embora possa ser utilizado no in cio de um nome, ele deve ser evitado. O uso de dois underscores, como em nome objeto, e reservado, devendo ser evitado. Caracteres v alidos a-z A-Z 0-9 + - * / = , . : ; ? \ | ! # $ & ( ) [ ] { } Caracteres inv alidos ++ = *= /= ?: :: /** == && // << >> >= <= += -
8.3.1
Para facilitar a leitura do programa, e usual a ado ca o de uma conven ca o para nomear os objetos. Veja na Tabela 8.2 um exemplo. Veremos a seguir como declarar e denir objetos em C++. Tabela 8.2: Conven ca o para nomes de objetos. Tipo de Objeto Vari aveis #dene Nome de classes Nome de estruturas Nome de uni oes Nome de enumera co es Nome de m etodos/fun co es Atributos Atributos est aticos Formato do Nome #dene MAIUSCULA; CNomeClasse; SNomeEstrutura UNome ENome InicialMai uscula(); inicialMin uscula min usculas Exemplos #dene SIZE 100 class CNormal{...}; struct SData{}; union UPressao{}; enum ESemana{}; int MediaPonderada(); int mediaPonderada; static int contador;
8.4
Declara c oes
Uma declara ca o introduz um ou mais nomes em um programa e especica como esses nomes devem ser interpretados. Uma declara ca o n ao reserva mem oria para o objeto, apenas diz que ele existe. Al em disso, declara ca o pode ser uma fun ca o, um tipo, um objeto (constante ou vari avel), um namespace, um template ou uma entidade relacionada, [Lischner, 2003]. Veja no prot otipo a seguir que uma declara ca o tem tr es componentes: os qualicadores, os especicadores e os declaradores. Prot otipo Qualicadores Especicadores Declarador; Qualicador especica o tipo de linkagem, est atica ( static ), externa ( extern ), ou export (veja se ca o B.2), ou modica o tipo de acesso com const , volatile e mutable (veja se ca o B.3). A ordem dos qualicadores n ao importa, isto signica que extern const volatile int x; e o mesmo que const extern volatile int x;. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
200
8.5. DEFINIC OES Especicador indica o tipo fundamental, a classe de armazenamento ou outras propriedades dos objetos declarados. Declarador especica o nome dos objetos e opcionalmente modica o tipo com um * . Um declarador pode especicar um valor inicial para o identicador que est a sendo declarado ( = ). Exemplo: static int x1; int x2; class CPonto; typedef int I; int * ptr; int& ref = &x1;
// // // // // //
um objeto int est atico, com nome x1 um objeto do tipo int com nome x2 um nome de classe um sin^ onimo para int (um apelido) um objeto ponteiro para int uma refer^ encia para x1.
Ao longo do livro veremos como declarar e usar tipos mais elaborados, como vetores, arrays, tipos do usu ario e tipos denidos em bibliotecas externas.
8.4.1
Veja na Tabela 8.3 exemplos de declara co es e deni co es de objetos. Inclu mos declara co es de matrizes, fun co es e ponteiros. Tabela 8.3: Exemplos de declara co es e deni co es. Sintaxe da declara ca o Tipo nome[]; Tipo nome[3]; Tipo* nome; Tipo* nome[]; Tipo* (nome[]); Tipo (*nome)[]; Tipo& nome; Tipo nome[nx][ny]; Tipo nome[nx][ny][nz]; Tipo nome(); Tipo*nome(); Tipo*( nome()); Tipo (*nome)(); Tipo efetivo Vetor do Tipo Vetor do tipo com tr es elementos Ponteiro para tipo Vetor de ponteiros para tipo Vetor de ponteiros para tipo Ponteiro para vetor do tipo Refer encia para o tipo Matriz 2D com nx por ny elementos Matriz 3D com nx por ny por nz elementos Fun ca o que retorna o tipo Fun ca o que retorna ponteiro tipo* Fun ca o que retorna ponteiro Tipo* Ponteiro para fun ca o que retorna o Tipo Exemplo int cont[]; int cont[3]; //0,1,2 int* ptr; int* cont[]; int* (cont[]); int (*cont)[]; int& cont; int m[5][6]; int m[5][6][4]; int cont(); int* cont(); int*(cont()); int (*cont)()
8.5
Deni c oes
Uma deni ca o dene o tipo de armazenamento, o valor, o corpo e o conte udo de uma declara ca o. Enquanto uma declara ca o informa que algo existe (interface), uma deni ca o a implementa e especica como aquela funciona. A deni ca o de uma fun ca o, por exemplo, inclui o corpo da fun ca o [Lischner, 2003]. Al em disso, uma deni ca o faz com que seja reservada a quantidade adequada de mem oria para o objeto e seja feita qualquer inicializa ca o apropriada. Uma declara ca o de uma deni ca o, por sua vez, a menos que contenha um extern e n ao tenha um inicializador. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
A ` FUNC MAIN() 8.6. INTRODUC AO AO Exemplo: extern int x; // Declara c~ ao: informa que existe um int x int y; // Defini c~ ao: reserva espa co de mem oria para y Deni c ao simples consiste em declarar um objeto de cada vez. Exemplo: int x;
201
Deni c ao m ultipla consiste em declarar v arios objetos de uma u nica vez. A deni ca o m ultipla deve ser evitada, pois o ideal e declarar um objeto por linha e incluir um coment ario sobre o objeto. Exemplo: float r,s,t;
Deni c ao com inicializa c ao consiste em declarar um objeto e, ao mesmo tempo, atribuir um valor a esse objeto. Exemplo: int x = 7; float y = 5.2; int r(30); int s[4];
// // // //
O mesmo que int x(7); Inicializa y com o valor 5.2 Inicializa r com o valor 30 Cria array com 4 elementos, valores = 0
8.6
Quando voc e roda um programa, o sistema operacional carrega-o na mem oria e em seguida inicia na fun ca o principal, que inicia a execu ca o do programa. Em programas em C e C++, a fun ca o inicial de um programa e chamada main(). Veremos a seguir dois prot otipos para fun ca o main(), e nas listagens 8.1 e 8.3, veremos exemplos de uso. Prot otipo int main() {..... return 0;} A fun ca o retorna um n umero inteiro e n ao recebe nenhum par ametro. int main(int argc, const char *argv[]) {...... return 0;} A fun ca o retorna um n umero inteiro e recebe dois par ametros. O par ametro argc e o n umero de elementos digitados na linha de comando e argv[] o vetor para as strings digitadas na linha de comando. Nota: veremos detalhes e exemplos de uso da fun ca o main() na se ca o E.1.
8.7
Apresenta-se nesta se ca o uma breve introdu ca o ` a entrada e sa da de dados em C++ usando os objetos cin e cout. Isto e suciente para os nossos primeiros exemplos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
202
8.7.1
Usando cout
Veja na listagem 8.1 nosso primeiro exemplo de programa em C++, o qual mostra como enviar textos para tela. O programa inicia-se incluindo um coment ario na linha // Arquivo listagens/Cap-08/novaLinha-tab-beep.cpp Em seguida, inclui um arquivo da biblioteca-padr ao de C++, a <iostream>, na linha #include <iostream> A <iostream> e uma biblioteca utilizada para entrada e sa da de dados. Ela fornece o objeto std::cout, utilizado para enviar uma mensagem para a tela (cout = C out ). Esse exemplo inclui ainda a fun ca o inicial de um programa em C++. int main() { Dentro da fun ca o main(), o objeto std::cout envia para a tela a mensagem Bem std::cout < < "Bem" < < \t < < "Vindo!\n"; O caractere \t e utilizado para colocar uma tabula ca o entre a palavra "Bem" e a palavra "Vindo". Em seguida, o programa envia para a tela a mensagem "Bem Vindo ao C++!", std::cout < < "B\ne\nm\n\nVindo ao C++!\a" < < std::endl; incluindo, entre cada caractere da palavra "Bem", uma nova linha \n. O caractere \n e utilizado para colocar uma quebra de linha. O caractere \a e usado para emitir um beep. O trecho std::endl e usado para incluir uma linha nova e enviar o texto imediatamente para tela. O manipulador std::endl; e fornecido pelo arquivo <iostream>. Au ltima linha da fun ca o main() ea return 0; } utilizada para nalizar a fun ca o main() e o programa, retornando para o sistema operacional o valor 0. O retorno do valor 0 indica para o sistema operacional que o programa terminou com sucesso sua execu ca o. Observe ap os a listagem como cou a sa da. Listing 8.1: Usando sa da para tela, nova linha, tabula ca o e beep.
// A r q u i v o l i s t a g e n s/ Cap -08/ novaLinha - tab - beep . cpp # include < iostream > int main () { std :: cout << " Bem " << \ t << " Vindo !\ n " ; std :: cout << " B \ ne \ nm \ n \ nVindo ao C ++!\ a " << std :: endl ; return 0; }
Vindo!
203
Os caracteres \n(nova linha), \a (beep) e \t (tabula c~ ao) s ao conhecidos como caracteres de escape. Um caracter de escape e composto de uma barra invertida e uma letra que indica a a ca o a ser executada. Veja na Tabela 22.3 os caracteres de escape de C/C++. Nota: veremos no Ap endice K Arquivos de cabe calho, uma lista com o nome dos diversos arquivos de cabe calho da biblioteca-padr ao de C e C++.
8.7.2
Usando cin
Veja na listagem 8.2 um exemplo com declara ca o de objetos, entrada e sa da de dados. A Figura 8.2 ilustra a execu ca o do programa. Figura 8.1: Diagrama mostrando entrada e sa da de dados em C++.
soma 5
temporria 5
<<objeto>> std::cout
a 2
b 3
cin >> a;
<<objeto>> std::cin
cin >> b;
2 enter 3 enter
Novamente, o programa inicia-se com um coment ario e, em seguida, inclui a bibliotecapadr ao de C++ para entrada e sa da de dados, a <iostream>, a qual, como dito anteriormente, fornece o objeto std::cout, que e utilizado para escrever na tela usando o operador de inser ca o < <. Na linha 7 int a; criamos um n umero inteiro com nome a, e, em seguida, enviamos para a tela uma mensagem solicitando o valor de a. std::cout < < "Entre com o valor de a: "; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
204 Na linha 13
std::cin > > a; o valor digitado pelo usu ario e armazenado no objeto a. O arquivo de cabe calho <iostream> fornece o objeto std::cin, utilizado para entrada de dados. O operador de extra ca o > > extrai um objeto do teclado e move-o para o objeto ` a direita do sinal > >, no caso o n umero a. Na linha 16 std::cin.get(); o objeto std::cin e usado para pegar do teclado o enter digitado pelo usu ario e, em seguida, desconsider a-lo. O mesmo procedimento e repetido para a var avel b. Posteriormente, criamos na linha int soma; a vari avel soma, que ser a utilizada para armazenar o resultado da soma de a e b. . Na linha 29 soma = a + b; os valores de a e b s ao somados e o resultado e armazenado em soma. A linha 32 std::cout < < "Soma = " < < soma; e usada para enviar para a tela o resultado da soma. std::cout < < std::endl; e usada para enviar para a tela um caracter de nova linha, evitando-se que a u ltima mensagem enviada pelo programa que sem quebra de linha. Outros coment arios est ao embutidos no texto. A sa da e ilustrada na Figura 8.2. Listing 8.2: Declara ca o de objetos e uso de cin e cout.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // A r q u i v o: ../ l i s t a g e n s / Cap -08/ cout - cin . cpp # include < iostream > int main () { // Um int e um tipo pr e - definido , serve para a r m a z e n a r n umeros inteiros // Na linha a seguir o tipo do objeto e int e seu nome a int a ; // E s c r e v e na tela " Entre com o valor de a :" std :: cout << " Entre com o valor de a : " ; // A r m a z e n a o valor d i g i t a d o no objeto a std :: cin >> a ; // Pega o enter e d e s c o n s i d e r a std :: cin . get () ; int b ; std :: cout << " Entre com o valor de b : " ; std :: cin >> b ;
205
Os programas foram compilados e executados em um PC utilizando GNU/Linux e em um PC usando Windows, ambos com software livre. O compilador utilizado e o g++, da GNU. Por default, o compilador da GNU gera um execut avel com nome a.out. Para compilar o programa, abra um terminal, v a para o diret orio onde o programa est a localizado e digite g++ cout-cin.cpp . Para executar o programa, digite ./a.out (no GNU/Linux) e cout-cin.exe (no Windows). Veja a Figura 8.2. Para compilar e executar o programa no ambiente Windows consulte os manuais de seu ambiente de desenvolvimento. Figura 8.2: Compilando e executando programas no shell.
8.8
Vimos, na se ca o 7.7, conceitos b asicos de pr e-processamento, compila ca o, linkagem, debugagem e otimiza ca o. Nesta se ca o veremos uma breve introdu ca o ` as diretrizes de pr e-processador de C++ e um pequeno exemplo (listagem 8.3).
8.8.1
Usando #ifdef..#endif
Agora que j a vimos como escrever na tela usando cout e como ler o conte udo de uma vari avel usando cin, podemos apresentar um programa que utiliza diretrizes de pr e-processamento. Como visto na se ca o 7.7, a primeira fase da compila ca o e denominada pr e-processador. Nela o compilador verica as instru co es de compila ca o passadas com o sinal #. No exemplo da listagem 8.3 inclu mos tr es diretrizes de pr e-processador: a primeira inclui o arquivo <iostream>, na linha #include <iostream>; a segunda diretriz de pr e-processador Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
206
dene um bloco #ifdef..#endif, ou seja, se a vari avel DEBUG j a foi denida, o programa inclui a parte de c odigo que envia a mensagem "Vers~ ao com vari avel debug ativada" para a tela; do contr ario, a linha com a mensagem e desconsiderada (n ao e compilada). A terceira diretriz e o #endif que naliza o bloco. O exemplo da listagem 8.3 deve ser compilado usando g++ UsandoDiretrizesDePreProcessador-ifdef.cpp e, em seguida, testado ./a.out . Por m, compile usando g++ DDEBUG UsandoDiretrizesDePre-Processador-ifdef.cpp e teste novamente. Veja as diferen cas na sa da. Listing 8.3: Usando diretrizes de pr e-processador: #ifdef.
# include < iostream > int main () { # ifdef DEBUG std :: cout << " Vers~ a o com vari a vel debug ativada " << std :: endl ; # endif return 0; } [ b u e n o @ s u p o r t e 3 ] $ g ++ UsandoDire t r iz e sD e P re - Processador - ifdef . cpp [ b u e n o @ s u p o r t e 3 ] $ ./ a . out [ b u e n o @ s u p o r t e 3 ] $ g ++ - DDEBUG UsandoDire tr i z es D eP r e - Processador - ifdef . cpp [ b u e n o @ s u p o r t e 3 ] $ ./ a . out Vers~ a o com vari a vel debug ativada
Nota: veremos maiores detalhes sobre diretrizes de pr e-processador no Ap endice A Diretrizes de pr e-Processador.
8.9
8.9.1
Usando for
O for e uma estrutura de controle de repeti ca o utilizado para a realiza ca o de la cos (loopings ). O prot otipo a seguir ilustra a forma de uso do for. O primeiro item e a inicializa ca o da vari avel de controle do la co; o segundo, e a condi ca o utilizada para continuar no la co se esta for falsa o la co e encerrado; o terceiro item, a c~ ao1, e utilizado, geralmente, para modicar a vari avel de controle. A a ca o2 e executada repetidas vezes, at e que a condi ca o seja falsa. Prot otipo: for(inicializa ca o; condi ca o; a ca o1) a ca o2; As listagens 8.4 e 8.5 mostram o uso de for. Na listagem 8.4 usamos um bloco for para enviar para tela o valor da vari avel i, criada dentro do for. Dentro do for a vari avel i e inicializada com o valor 1 (int i = 1;). Em seguida, cada la co do for envia para a tela o valor i (std::cout < < i < < " ";). Observe na sa da os valores de i: 1 2 3 4 5 6 7 8 9 10. Ap os cada la co, o valor de i e incrementado, i++, e comparado com o valor 10, i <= 10;. Quando i for igual a 11 a condi ca o se torna falsa, e o for e encerrado. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
207
Na listagem 8.5, usamos um for encadeado, um for dentro de outro para enviar para tela y linhas e x vezes o caracter .. Listing 8.5: Usando for encadeado.
# include < iostream > int main () { int x , y ; std :: cout << " Entre com dois n u meros inteiros positivos ( x espa c o y enter ) : " ; std :: cin >> x >> y ; std :: cin . get () ; for ( int i = 1; i <= y ; i ++) { for ( int j = 1; j <= x ; j = j + 1) std :: cout << . ; std :: cout << std :: endl ; } return 0; } [ b u e n o @ l d s c 0 5 ] $ ./ a . out Entre com dois n u meros inteiros positivos ( x espa c o y enter ) : 4 2 .... .... [ b u e n o @ l d s c 0 5 ] $ ./ a . out Entre com dois n u meros inteiros positivos ( x espa c o y enter ) : 6 3 ...... ...... ......
8.9.2
O prot otipo a seguir mostra uma estrutura de controle do tipo while. O funcionamento de um bloco while e simples, enquanto a condi ca o for verdadeira a a ca o vai ser executada. Desta forma, em algum momento o bloco que cont em a a ca o a ser executada deve tornar a condi ca o falsa. Note que se a condi ca o nunca for falsa, o bloco com a a ca o nunca vai ser encerrado, ocorrendo um la co innito (sem sa da). Prot otipo: while (condi ca o) {a ca o;}; Veja agora o exemplo da listagem 8.6. Neste exemplo o objetivo e calcular o valor da pot encia dada por potencia = baseexpoente , o usu ario deve entrar com a base e o expoente. A seguir, dentro do bloco while, a pot encia e calculada. Observe que o valor de i inicia em 1 e e Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
208
incrementado dentro do while, quando i > y o la co e encerrado. O comando cin.get(); e utilizado para retirar do teclado o enter. Observe que o mesmo resultado pode ser obtido usando-se diretamente a fun ca o pow(x,y); da biblioteca padr ao de C. Para usar arquivos da biblioteca matem atica padr ao de C inclu mos o arquivo <cmath>. Listing 8.6: Usando while: Calculando a pot encia.
# include < iostream > // B i b l i o t e c a de e n t r a d a e sa da # include < cmath > // B i b l i o t e c a m a t e m a t i c a de C / C ++ int main () { int x , y ; std :: cout << " Entre com a base ( inteiro ) : " ; std :: cin >> x ; std :: cout << " Entre com o expoente ( inteiro ) : " ; std :: cin >> y ; std :: cin . get () ; int i = 1; double potencia = 1; while ( i <= y ) { potencia = potencia * x ; // O mesmo que p o t e n c i a *= x ; ++ i ; // O mesmo que i = i + 1; } std :: cout << " pot^ e ncia = " << potencia << std :: endl ; // C a l c u l a p o t ^ e n c i a usando fun c~ a o pow (x , y ) std :: cout << " pow (x , y ) = " << pow (x , y ) << std :: endl ; return 0; } [ a n d r e @ m e r c u r i o Cap2 - Sintaxe ] $ ./ a . out Entre com a base ( inteiro ) : 3 Entre com o expoente ( inteiro ) : 4 81
Voc e encontra uma descri ca o detalhada das diversas estruturas de controle de C++ no Ap endice D Estruturas de controle.
8.10
8.10.1
Neste ponto podemos apresentar um programa que utiliza operadores de C++. Se voc e ainda n ao conhece os operadores de C/C++, ap os a leitura desta se ca o, aconselha-se a leitura do Ap endice C Operadores. Veja a seguir o prot otipo de uso dos operadores relacionais (>, >=, <, <=, ==, !=), os quais s ao utilizados para comparar objetos. Prot otipo Operador Descri ca o Andr e Duarte Bueno
AOS OPERADORES DE C++ 8.10. INTRODUC AO > >= < <= == != maior maior ou igual menor menor ou igual igual diferente
209
Um exemplo de uso dos operadores de compara ca o e apresentado na listagem C.1. A fun ca o main() cria dois inteiros, a e b. Em seguida, ela pede ao usu ario que entre com os valores de a e b. O programa chama ent ao a fun ca o void compara(int a, int b);, utilizada para comparar os valores a e b, e mostrar na tela o resultado da compara ca o. Veja na sa da que o usu ario entrou com os valores 3 e 4. A fun ca o Compara() n ao retorna nada (void), recebe como par ametros dois inteiros (int x, int y) e e usada para comparar os valores de a e b. Note que os objetos a e b, criados dentro de main(), s ao passados por c opia para a fun ca o Compara(). Veremos as diferentes formas de passagem de par ametros na se ca o 13.6. Listing 8.7: Usando os operadores de compara ca o, incremento, decremento, e os operadores compostos.
# include < iostream > // D e c l a r a fun c~ ao Compara void Compara ( int x , int y ) ; int main () { int a , b ; std :: cout << " Entre com dois numeros inteiros ( a espa c o b enter ) : " ; // O b s e r v e abaixo a l e i t u r a de duas v a r i a v e i s em uma u nica linha . // Isto pode ser feito , mas deve ser e v i t a d o. std :: cin >> a >> b ; std :: cin . get () ; // Pega o enter Compara (a , b ) ; // E x e c u t a fun c~ a o C o m p a r a () a += 5; // O p e r a d o r c o m p o s t o . Compara (a , b ) ; // E x e c u t a fun c~ a o C o m p a r a () b - -; // O p e r a d o r de d e c r e m e n t o . Compara (a , b ) ; // E x e c u t a fun c~ a o C o m p a r a () a *= ++ b ; // O p e r a d o r de i n c r e m e n t o . Compara (a , b ) ; // E x e c u t a fun c~ a o C o m p a r a () return 0; // E n c e r r a o p r o g r a m a } // Define a fun c~ a o C o m p a r a ( c o digo da fun c~ ao ) void Compara ( int x , int y ) { if ( x == y ) // O p e r a d o r e s de c o m p a r a c~ ao std :: cout << x << " == " << y << " \ t " ; if ( x != y ) std :: cout << x << " != " << y << " \ t " ; if ( x < y ) std :: cout << x << " < " << y << " \ t " ; if ( x > y ) std :: cout << x << " > " << y << " \ t " ; if ( x <= y ) std :: cout << x << " <= " << y << " \ t " ; if ( x >= y )
210
std :: cout << x << " >= " << y << " \ t " ; }
Entre com dois numeros inteiros ( a espa c o b enter ) : 3 4 3 != 4 3 < 4 3 <= 4 8 != 4 8 > 4 8 >= 4 8 != 3 8 > 3 8 >= 3 32 != 4 32 > 4 32 >= 4
Neste exemplo adicionamos, al em do uso de operadores, o uso de fun co es separadas de main(), o que e t pico em programas estruturados. Nota: como os conceitos de operadores (+, -, *, ...) e de estruturas de controle j a s ao bastante conhecidos, eles foram inclu dos no Ap endice C Operadores e no Ap endice D Estruturas de controle. Continue lendo o livro normalmente. Se tiver problemas para entender como funciona determinado operador ou estrutura de controle, consulte o item espec co no ap endice. Nota: veremos o uso de m etodos no Cap tulo 13 M etodos e no Cap tulo 14 Sobrecarga de m etodos.
8.11
Vimos os conceitos de fun co es e m etodos na se ca o 3.5. Lembre-se que fun co es no estilo de C, s ao normalmente fun co es globais, utilizadas em programa ca o estruturada. A id eia de usar fun co es e possibilitar que partes do c odigo que s ao constantemente repetidas sejam separadas do uxo principal. J a vimos na se ca o 8.6 a fun ca o main(). Veremos aqui o prot otipo e exemplos de declara ca o, deni ca o e uso de fun co es no estilo de C. Veja no prot otipo a seguir que uma fun ca o tem um retorno, um nome e uma lista de par ametros. Prot otipo: retorno NomeDaFun ca o(par ametros); Normalmente as fun co es s ao declaradas antes da fun ca o main(), e denidas depois de main(). Isto possibilita que as fun co es possam ser chamadas de dentro de main(). Veja a seguir algumas listagens com exemplos de fun co es. Veja na listagem 8.8 uma fun ca o simples, usada para calcular o cubo de um n umero. Observe que que a fun ca o cubo() e chamada diversas vezes dentro do for. Listing 8.8: Fun ca o cubo.
# include < iostream > int cubo ( int y ) ; int main () { // D e c l a r a c~ a o da fun c~ ao
211
Veja na listagem 8.9 uma fun ca o simples, sem retorno e sem par ametros. Observe que usamos recurs ao para fun ca o main(). Uma recurs ao existe quando uma fun ca o chama a s mesma. Veremos o uso de recurs oes na se ca o E.3. Listing 8.9: Fun ca o com void.
# include < iostream > void f () ; void g ( void ) ; // C ++ // C p r e c i s a do s e g u n d o void
int main () { std :: cout << " \ a \ n " ; std :: cout << " Executar f () ou g () ? " ; char resp = f ; std :: cin >> resp ; std :: cin . get () ; // Pega o enter if ( resp == f || resp == F ) f () ; else if ( resp == g || resp == G ) g () ; else { std :: cout << " Sele ca ~ o errada , selecionou ( " << resp << " ) " << std :: endl ; main () ; // R e c u r s ~ ao } return 0; } void f () { std :: cout << " Fun ca ~ o void n~ a o retorna nada ( selecionou f ) " << std :: endl ; } void g ( void ) { std :: cout << " Fun ca ~ o void n~ a o retorna nada ( selecionou g ) " << std :: endl ; } Executar f () ou g () ? g Fun ca ~ o void n~ a o retorna nada ( selecionou g )
212
Apresenta-se na listagem 8.10 uma fun ca o em linha, utilizada para calcular o volume de uma esfera. Veremos em detalhes os conceitos de fun co es em linha na se ca o 13.10. Uma vari avel declarada com const e uma vari avel que n ao pode ser alterada. Veremos em detalhes o uso de const na se ca o 12.4. Listing 8.10: Fun ca o em linha: volume esfera.
# include < iostream > // V a r i a v e i s g l o b a i s devem ser d e c l a r a d a s com m a i usculas // const indica ser constante , n~ a o muda const double PI = 3.14159; /* Um p r o g r a m a d o r C usaria # define PI 3 . 1 4 1 5 9 */ // Fun c~ a o em linha inline double V o l u m e E s f e r a ( const double raio ) { return 4.0 / 3.0 * PI * raio * raio * raio ; } /* Um p r o g r a m a d o r C usaria uma macro , sem n e n h u m a v e r i f i c a c~ a o de tipo . # define V o l u m e E s f e r a ( raio ) ( 4 . 0 / 3 . 0 * PI * raio * raio * raio ) */ int main () { double raio ; std :: cout << " Entre com o raio : " ; std :: cin >> raio ; std :: cin . get () ; std :: cout << " Raio r = " << raio << " volume V = " << V o l u m e E s f e r a ( raio ) << std :: endl ; return 0; } Entre com o raio : 5 Raio r =5 volume V = 523.598
Veja na listagem 8.11 uma fun ca o utilizada para gerar n umeros rand omicos num determinado intervalo de valores. Listing 8.11: Exemplo de uso da biblioteca <cstdlib>.
# include < iostream > # include < iomanip > // A b i b l i o t e c a abaixo , no C chama stdlib .h , no C ++ chama c s t d l i b // a mesma f o r n e c e a fun c~ a o srand - s e m e n t e para g e r a d o r // e rand - gera n u mero r a n d o m i c o . # include < cstdlib > int main () {
213
4 6 4 10 4 1 10 3 5 4
8.12
Um escopo e uma regi ao de c odigo que cont em declara co es. Cada declara ca o adiciona um nome ao escopo, e o uso desses nomes deve ser resolvido pelo compilador. Isto signica que n ao podemos ter dois nomes iguais no mesmo escopo pois o compilador caria confuso e acusaria uma ambig uidade. No exemplo a seguir int y; e declarado duas vezes, o que causa uma ambig uidade. Exemplo: int main() { int x; int y; int y; return 0; }
// // // //
In cio do escopo de main(), do bloco de main() Declara um inteiro x Declara um inteiro y Erro, mesmo nome no mesmo escopo (ambiguidade)
214
No exemplo a seguir criamos, dentro do bloco de main(), um bloco interno. Observe que temos duas vari aveis y: a primeira y = 3; e a segunda y = 4;. Note que, quando um bloco interno e fechado, os objetos criados dentro do bloco s ao destru dos automaticamente. Exemplo: int main() { // In cio do escopo de main() int x; int y = 3; std::cout < < "y = " < < y ; // Sa da: y = 3 { // Bloco interno, define novo escopo int y = 4; std::cout < < "y = " < < y ; // Sa da: y = 4 } // y = 4 sai de escopo e e destru do automaticamente std::cout < < "y = " < < y ; // Sa da: y = 3 return 0; } // Fim do escopo de main() Veremos mais detalhes sobre escopo ao longo deste livro e na se ca o B.4.
8.13
Sempre deixe uma linha em branco antes de uma declara ca o. Isto deixa o c odigo mais claro. Um objeto s o pode ser utilizado depois de ter sido declarado. Sempre que poss vel, inicie os objetos na sua declara ca o. Quando uma express ao for complexa, coloque par enteses extras para facilitar o entendimento do c odigo. Sempre use espa cos para maior claridade. Sempre use indenta ca o para deixar o c odigo organizado (voc e pode usar o programa indent. Veja se ca o ??). Use nomes curtos para objetos muito usados e nomes longos para objetos e m etodos pouco usados. Utilize um padr ao para o nome dos objetos (veja se ca o 8.3). No C temos de declarar todas as vari aveis no in cio do programa; no C++ podemos declarar os objetos em qualquer parte. O ideal e declarar os objetos perto de onde ser ao utilizados. Sempre declare um objeto por linha. Exemplo: // Cria int* a; e int b; int *a, b; // Declarar um objeto por linha deixa o programa mais claro int* a; int b; Objetos est aticos s ao inicializados com 0. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
215
Objetos locais, criados dentro de um bloco (ou fun ca o), n ao s ao inicializados. Voc e precisa passar-lhes um valor. Nem todos os compiladores aceitam o uso de caracteres universais. A linguagem C/C++ reservou para uso futuro os seguintes prexos: is (exemplo: isblank()), mem (exemplo: memf()), str (exemplo: strtof()), to (exemplo: toascii()), wcs (exemplo: wcstof()). Utilize a palavra-chave export para informar que aquele objeto/classe/m etodo e acess vel externamente. Note que podemos montar a sa da que aparecer a na tela do computador usando o objeto std::cout e o operador de inser ca o < <. Podemos ir redirecionando caracteres e vari aveis do programa para tela do computador. Por exemplo, na linha std::cout < < "Mensagem1 " < < "Mensagem2 " < < "Mensagem3 "; enviamos para tela o texto "Mensagem1 Mensagem2 Mensagem3 ". 2 Objetos podem ser modicados com as palavras-chave const (constante, n ao muda), volatile (podem mudar de forma inesperada) e static (duram toda a execu ca o do programa). Veja se ca o B.3. 2 Voc e n ao deve confundir a classe de armazenamento com o escopo do objeto. A classe de armazenamento se refere ao tempo de vida do objeto (tempor ario ou permanente), j a o escopo do objeto dene onde ele pode ser utilizado (onde e vis vel). Veja uma descri ca o dos conceitos de classes de armazenamento na se ca o B.1, dos modicadores de acesso na se ca o B.3 e do escopo das vari aveis na se ca o B.4 do Ap endice B. 2 Segundo [Lischner, 2003], uma express ao integral constante deve ter seu valor denido na compila ca o. As situa co es em que isto e necess ario incluem: tamanho de um array, inicializa ca o dos valores de uma enumera ca o, r otulos de instru co es case:, inicializa ca o de membros est aticos e argumentos de templates.
8.14
Neste cap tulo vimos alguns conceitos b asicos de C++, como os coment arios, s mbolos, especicador, lvalues. Aprendemos o que s ao os identicadores, os operadores e os literais. Vimos um grupo de palavras-chaves reservadas pelo C++, as palavras-chave de C++. Aprendemos que o nome dos objetos deve ser simples e claro. Aprendemos ainda a forma como declaramos e denimos os objetos, e as diferen cas da declara ca o (informa que o objeto existe) para deni ca o (reserva espa co na mem oria para o objeto). Vimos uma introdu ca o a diversos conceitos b asicos de C++, como fun ca o main(), uso de cin e cout, as diretrizes de pr e-processador (#ifdef..#endif), algumas estruturas de controle (for, while), fun co es da biblioteca-padr ao (pow(x,y)), alguns operadores, e uma introdu ca o ao conceito de fun co es. Finalmente, vimos a rela ca o entre declara co es e escopo. Nota: ao longo do livro veremos outros exemplos e listagens que esclarecem temas como escopo, cria ca o, destrui ca o e tempo de vida dos objetos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
216
8.15
Exerc cios
1. Qual a diferen ca b asica entre uma declara ca o e uma deni ca o? 2. Fa ca uma lista das palavras-chave que voc e j a memorizou. 3. Quais s ao os tipos padr oes de C++ que voc e j a conhece? 4. Modique a listagem 8.1 usando os caracteres apresentados na Tabela 22.3. 5. Modique a listagem 8.2 criando e usando novas vari aveis. Incluir outras opera co es como multiplica ca o e divis ao. 6. Modique a listagem 8.3, incluindo novas diretrizes de pr e-processador (veja Ap endice A Diretrizes de pr e-processador). 7. Modique as listagens 8.4, 8.5 e 8.6 fazendo com que elas fa cam algo mais u til. 8. Rode agora o programa da se ca o 7.8. Voc e j a conseguiria modic a-lo? Comece adicionando coisas novas dentro do m etodo Run(). 9. Um programa pode ser encerrado a qualquer momento chamando-se a fun ca o exit();, a qual encerra o programa destruindo os objetos criados, ou chamando abort();, que encerra o programa sem destruir os objetos criados. Monte um programa que use exit(); e outro que use abort();. Nota: se voc e n ao est a familiarizado com o uso de algoritmos, consulte as refer encias [Holloway, 2006] (algoritmos em C++) e [Cormen et al., 2002, Boente, 2006].
Cap tulo 9
Tipos
Neste cap tulo veremos uma introdu ca o ao conceito de tipos: o que e um tipo (Se ca o 9.1) e quais os tipos predenidos de C++ (Se ca o 9.2). A deni ca o de tipos do usu ario (Se ca o 9.3), como vetores no estilo de C (Se ca o 9.3.1), como estruturas (Se ca o 9.3.2), uni oes (Se ca o 9.3.3), enumera co es (Se ca o 9.3.4), e classes (Se ca o 9.3.5). Os tipos denidos em bibliotecas externas (Se ca o 9.4), como a classe <string> (Se ca o 9.4.1) e a classe <vector> da STL (Se ca o 9.4.2). Como manipular os tipos de C++ (Se ca o 9.5), como criar apelidos com typedef (Se ca o 9.5.1), o uso de size_t() (Se ca o 9.5.2) e sizeof() para obter o tamanho dos objetos (Se ca o 9.5.3), e o uso de typeid() para vericar o tipo do objeto (Se ca o 9.5.4). Veremos tamb em a vantagem da tipica ca o forte do C++ (Se ca o 9.6). Nota: neste cap tulo apresentaremos v arios tipos de objetos que s ao utilizados em um programa um cap em C++. E tulo extenso, com muitas informa co es, n ao se preocupe se n ao entender tudo em uma primeira leitura. Ao longo dos pr oximos cap tulos estes conceitos ser ao reapresentados de forma mais detalhada.
9.1
Um tipo e uma abstra ca o de algo (Se ca o 3.1). Para a linguagem C++ os tipos podem ser classicados em tr es grupos: Tipos predenidos da linguagem, como bool, char, int, double (Se ca o 9.2). Tipos denidos pelo programador (Se ca o 9.3). Tipos denidos em bibliotecas externas, como a STL (Se ca o 9.4).
9.2
Os tipos num ericos predenidos da linguagem C++ s ao bool, char, int, float e double.
O tipo bool e utilizado para armazenar valores booleanos 0 (false/falso) ou 1 (true/verdadeiro), sendo utilizado como ag, por exemplo, em estruturas de controle. char e utilizado para armazenar caracteres ou n umeros inteiros pequenos. int e usado para armazenar n umeros inteiros, com ou sem sinal (unsigned). J a float e double s ao utilizados para armazenar n umeros utuantes (n umeros racionais). 217
218
No n umero 7.48e9, 7.48 e a mantissa, e 9 o expoente. O ponto e o separador da parte fracion aria (quando utiliza-se o locale C. Veja Se ca o 22.9.2. O caracter e ou E indica nota ca o exponencial. Se o resultado de uma determinada conta for innito (um n umero maior que a precis ao suportada), a sa da ser a Inf ou Innity. Se o resultado for um valor indeterminado (como em 0/0) a sa da ser a NaN ou Not a Number. CUIDADO: A divis ao de dois n umeros inteiros retorna um n umero inteiro, assim, 4 / 3 = 1. A divis ao de um n umero inteiro por um n umero utuante retorna um n umero utuante. Uma representa ca o do consumo de mem oria em bytes dos diferentes tipos e apresentada na Figura 9.1. Observe que um double consome o dobro de mem oria de um float. A escolha por float ou double depender a do uso: se voc e precisa de mais precis ao use double; se quer economizar mem oria use float. Os intervalos de valores suportados pelos tipos predenidos est ao listados na Tabela 9.1. Observe que char pode ser utilizado como uma letra ou como um n umero com intervalo entre -128 e +127. De fato, char e utilizado como n umero em alguns programas de processamento de imagens. Um n umero inteiro short int, vai de -32768 at e 32767. Isto signica que a conta realizada com um short int n ao poder a ultrapassar esses valores. Se precisar de n umeros inteiros grandes, use int, long int, ou long long.
1 1 1 1 1 1 2 3 4 5 2 6 3 7 4 8 5 2 2 6 3 3 7 2 4 4 8 bool, char, unsigned char short int, unsigned short int, unsigned int, long, unsigned long, int* float long long, double
9 10 11 12 long double
Figura 9.1: Tipos predenidos de C++ e suas dimens oes (32 bits). Vimos exemplos de como criar e utilizar um objeto com base em um tipo predenido de C++, nas listagens 8.2, 8.4, 8.5, 8.6 e C.1. Veremos na Se ca o 9.5.3 que o n umero de bytes consumido por um n umero inteiro varia de acordo com a plataforma. Veja na Listagem 9.1 um programa que utiliza os tipos predenidos de C++. Observe que este exemplo n ao tem nem entrada nem sa da de dados, n ao sendo necess aria a inclus ao de arquivos externos. Listing 9.1: Usando os tipos pr e-denidos de C++.
1 2 3 4 5 6 int main () { // Tipos pr e - d e f i n i d o s da l i n g u a g e m C ++ // Tipo booleano , i n t e r v a l o 0 ou 1 (1 byte ) bool flag = 0;
219
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// Tipo char , i n t e r v a l o -128 a +127 (1 byte ) char ch = b ; char nch = 14; // Tipo int , i n t e r v a l o int int_x = 777; -2147483648 a + 2 1 4 7 4 8 3 6 4 7 (4 bytes , 32 bits )
// Tipo float , i n t e r v a l o +/ - 3.4. e +/ -38 (7 d g i t o s de p r e c i s ~ a o ) (4 bytes ) float float_y = 3.212 f ; // Tipo double , i n t e r v a l o +/ - 1.7 e +/ -308 (15 d g i t o s de p r e c i s ~ a o ) (8 bytes ) double double_z = 7.48 e9 ; // Tipo long double , i n t e r v a l o +/ - 3.4 e +/ -4932 // (19 d g i t o s de p r e c i s ~ a o) (12 bytes ) long double l o n g _ d o u b l e _ r = 1.2 e -18; return 0; }
Observe no exemplo da Listagem 9.2 o uso e as diferen cas dos tipos int (inteiro) e unsigned int (inteiro sem sinal). Observe que quando usamos int a opera ca o x - y e v alida pois int aceita n umeros negativos. J a quando usamos unsigned int, z s o pode armazenar n umeros inteiros positivos, n ao podendo armazenar o resultado de x - y quando y > x. Observe na sa da gerada pelo compilador a mensagem de warning por estarmos armazenando um inteiro negativo em um inteiro sem sinal (unsigned int t = -1;). Observe na sa da que quando usamos int temos x = 300 e y = 500, e z = x - y apresenta o valor correto -200. Quando usamos unsigned int, aparece um valor absurdo, 4294967096, no lugar de -200. Como dito, isto ocorre porque z s o pode armazenar n umeros inteiros positivos. Vamos explicar este problema com um exemplo. Observe na Tabela 9.1 que um n umero unsigned int, vai de 0 at e +4.294.967.295, se criarmos um n umero t usando unsigned int t = 4.294.967.295; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
o valor de t e incrementado do valor 1 e ultrapassa o limite denido. Como os n umeros s ao tratados de maneira c clica, o novo valor de t passa a ser 0 (zero). O mesmo problema ocorre quando ultrapassamos o limite inferior, isto e, se t = 0; o c odigo t = t -1; faz com que t assuma o valor +4.294.967.295. Listing 9.2: Diferen cas no uso de inteiro com sinal (signed) e sem sinal (unsigned).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 # include < iostream > int main () { { std :: cout << " - - - - - - - - - - > Testando a utiliza ca ~ o de int " << std :: endl ; int x , y , z ; std :: cout << " Entre com int x ( ex : 300) : " ; std :: cin >> x ; std :: cout << " Entre com int y ( ex : 500) : " ; std :: cin >> y ; std :: cin . get () ; z = x + y; std :: cout << " int z = x + y = " << z << std :: endl ; z = x - y; std :: cout << " int z = x - y = " << z << std :: endl ; } std :: cout << " - - - - - - - - - - > Testando a utiliza ca ~ o de unsigned int " << std :: endl ; unsigned int x , y , z ; std :: cout << " Entre com unsigned int x ( ex : 300) : " ; std :: cin >> x ; std :: cout << " Entre com unsigned int y ( ex : 500) : " ; std :: cin >> y ; std :: cin . get () ; z = x + y; std :: cout << " unsigned int z = x + y = " << z << std :: endl ; z = x - y; std :: cout << " unsigned int z = x - y = " << z << std :: endl ; // Se x if ( x > z = x else z = y > y r e t o r n a z = x - y , caso c o n t r a r i o ( else ) r e t o r n a z = y - x y) - y; - x;
// A r m a z e n a a i n f o r m a c~ a o do sinal , o b s e r v e que sinal e do tipo int . int sinal ; if ( x > y ) sinal = +1; else sinal = -1; // Cria objeto int para a r m a z e n a r o r e s u l t a d o int r e s u l t a d o _ c o r r e t o = sinal * z ; std :: cout << " z = | x - y | = " << z << std :: endl ; std :: cout << " sinal de x - y = " << sinal << std :: endl ; std :: cout << " int r e s u l t a d o _ c o r r e t o = sinal * z = " << r e s u l t a d o _ c o r r e t o << std :: endl ; unsigned int t = -1; std :: cout << " unsigned int t = -1 --> t = " << t << std :: endl ; return 0; }
221
9.2.1
o mesmo representa que tipo de n umero inteiro? e um short? um int? um long int? ou um long long int? Por padr ao, 7 e um int. Podemos denir de forma exata o tipo do literal usando suxos. Veja lista de suxos e exemplo de uso a seguir: I,L u,U long unsigned
Por exemplo: O n umero 7.45 e um double, 7.45f e um float, e 7.45L e long double. O n umero 7L e um long int, 7uL e um unsigned long int. O n umero 7LL e um long long int. O n umero que inicia com 0x e um n umero hexadecimal. O n umero que inicia com 0 (zero) e um n umero octal. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
222
9.2.2
Veja na Listagem 9.3 um programa que mostra informa co es sobre os tipos predenidos de C++. Como este exemplo utiliza conceitos avan cados de C++, como o uso de templates e bibliotecas padr oes de C++, n ao se preocupe se n ao entender seu funcionamento nesta primeira leitura. O arquivo de cabe calho <limits> inclui a classe template <numeric_limits>, a qual inclui atributos e m etodos que fornecem informa co es sobre os tipos predenidos. Por exemplo, a chamada a numeric_limits<Tipo>::is_integer() retorna verdadeiro se o Tipo for char, short, int, unsigned int. Neste exemplo, a fun ca o Info() recebe o tipo de objeto e uma string com seu nome. Em seguida, envia para a tela informa co es b asicas sobre o tipo como: e inteiro?; valores m aximos e m nimos suportados; expoentes m nimos e m aximos; valor innito e dados como radix, epsilon, round_error e round_style. Listing 9.3: Vericando os limites dos tipos pr e-denidos de C++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 # include < iostream > # include < string > # include < limits > using namespace std ; // Fun c~ a o t e m p l a t e u t i l i z a d a para i n f o r m a r dados sobre o n u mero . // Recebe dois par^ a metros , p r i m e i r o o n u mero n , s e g u n d o o nome s template < typename Tipo > void Info ( Tipo n , string s ) { cout << " \n - - - > Informa co ~ e s sobre n u meros " << s << " <--- " ; s = " \ nnumeric_limit s < " + s + " >:: " ; cout << s << " is_integer = " << numeric_limits < Tipo >:: is_integer << s << " max () = " << numeric_limits < Tipo >:: max () << s << " min () = " << numeric_limits < Tipo >:: min () << s << " m i n _ e x p o n e n t = " << numeric_limits < Tipo >:: m i n _ e x p o n e n t << s << " m i n _ e x p o n e n t 1 0 = " << numeric_limits < Tipo >:: m i n _ e x p o n e n t 1 0 << s << " m a x _ e x p o n e n t = " << numeric_limits < Tipo >:: m a x _ e x p o n e n t << s << " m a x _ e x p o n e n t 1 0 = " << numeric_limits < Tipo >:: m a x _ e x p o n e n t 1 0 << s << " digits = " << numeric_limits < Tipo >:: digits << s << " digits10 = " << numeric_limits < Tipo >:: digits10 << s << " radix = " << numeric_limits < Tipo >:: radix << s << " infinity () = " << numeric_limits < Tipo >:: infinity () << s << " epsilon () = " << numeric_limits < Tipo >:: epsilon () << s << " round_err or () = " << numeric_limits < Tipo >:: round_err or () << s << " round_sty le = " << numeric_limits < Tipo >:: round_sty le << endl ; } int main () { char c ; int i ; long l ; long long ll ; float f ; double d ; long double ld ; Info (c , " char " ) ; Info (i , " int " ) ; Info (l , " long " ) ; Info ( ll , " long long " ) ; Info (f , " float " ) ; Info (d , " double " ) ; Info ( ld , " long double " ) ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ linux64 ./ a . out
223
Nota: veja no manual do seu ambiente de desenvolvimento onde est ao armazenados os arquivos da biblioteca de C++. No GNU/Linux est ao em /usr/include/c++/vers aoDoCompilador. D e uma olhada no arquivo de biblioteca <limits> (exemplo: /usr/include/c++/4.1.1/limits). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
224
9.2. USO DE TIPOS PREDEFINIDOS DE C++ Esse arquivo cont em vari aveis que denem os limites para os tipos predenidos da linguagem.
9.2.3
Os tipos inteiros (char, short, int, long) e os tipos utuantes (float, double, long double) tamb em s ao conhecidos como tipos aritm eticos. Um tipo aritm etico pode ser automaticamente convertido para outro. Por default, um tipo menor e convertido em um tipo maior (exemplo: int e convertido para float). A id eia e que os valores sejam preservados. Cuidado especial deve ser tomado quando convertemos um tipo com sinal negativo para um tipo sem sinal (veja Listagem 9.2). Um tipo utuante, quando convertido para int, e truncado (exemplo: int y = 4.33; // y = 4). Utilize unsigned char quando precisar trabalhar com n umeros entre 0 e 255. Utilize signed char quando precisar trabalhar com n umeros entre -128 e 127. A palavra-chave const e usada para indicar que o conte udo do objeto n ao muda. No exemplo a seguir o valor de y ser a sempre 5. Exemplo: const int y = 5; // Cria objeto constante do tipo inteiro Por default, o n umero 5.3 e um double; j a 5.3f e um n umero float. Podemos atribuir a um bool um valor diferente de 0 e 1. Neste caso, todo valor diferente de zero assume o valor 1 (true/verdadeiro). Um caracter e representado dentro de aspas simples, como na sequ encia: a, \b, \u03co. O caracter a e uma letra simples. O caracter \b e um caracter de escape (veja Tabela 22.3). J a \u03co e um caracter universal. Uma string de C (cstring) e representada dentro de aspas duplas, como em: "oi tudo bem!" observe que podemos quebrar a string utilizando uma barra invertida, "oi tudo \ bem" concatenar strings, "oi" " tudo" " bem" ou incluir caracteres de escape "oi\t tudo\t bem\a". Um espa co , uma tabula ca o horizontal \t, uma tabula ca o vertical \v, um avan co de formul ario \fe um caracter de nova linha \n s ao conhecidos e tratados como whitespace caracters. 2 Uma wide string tamb em e representada dentro de aspas duplas, mas a string e antecedida da letra L como em: L"oi tudo bem!". Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
225
9.3
Veja nesta se ca o exemplos preliminares de deni ca o e uso de tipos do usu ario. Veremos como criar tipos do usu ario utilizando vetores (Se ca o 9.3.1), estruturas (Se ca o 9.3.2), uni oes (Se ca o 9.3.3), enumera co es (Se ca o 9.3.4) e classes (Se ca o 9.3.5).
9.3.1
Em C/C++, podemos criar um vetor usando o tipo do objeto a ser armazenado no vetor, o nome do vetor e o n umero de elementos do vetor que e colocado dentro de []. Veja a seguir o prot otipo para criar e usar um vetor no estilo de C. Prot otipo: // Para criar um vetor em C Tipo NomeVetor [dimens ao]; Tipo NomeVetor []= {lista de elementos}; // Para acessar um elemento do vetor NomeVetor[posi ca o]; O exemplo a seguir ilustra a cria ca o e o uso de um vetor de n umeros inteiros. Observe que denimos explicitamente o tamanho de v1, com a dimens ao 5. O tamanho de v2 e calculado pelo compilador, em tempo de compila ca o. Usamos um for para calcular a soma dos elementos de v1 e v2 e armazenar em v3. Exemplo: int v1[5]; for( int i = 0; v[i] = i; int v2[] = { 3, int v3[5]; for( int i = 0; v3[i] = v1[i]
// Cria vetor v1 i < 5 ; ++i ) // Inicializa valores de v1 4, 7, 9, 1 }; // Cria vetor v2 e j a inicializa // Cria vetor v3 i < 5 ; ++i ) + v2[i];
Dica: em C e C++ os vetores iniciam com o ndice 0 e n ao com 1. Assim, num vetor de tamanho n, o primeiro elemento e o elemento v[0], e o u ltimo elemento o v[n-1]. Nota: o Ap endice H, Vetores e matrizes arrays, mostra em detalhes o uso de vetores e arrays importante no estilo de C. Veremos na Se ca o 15.3 o uso de aloca ca o din amica e vetores. E destacar que o uso de vetores no estilo de C e obsoleto; eles t em sido substitu dos por <vector> de C++. Veremos uma introdu ca o aos vetores no estilo de C++ na Se ca o 9.4.2. Veremos o uso avan cado de vetores e arrays no Cap tulo ?? Biblioteca Blitz++.
9.3.2
Introdu c ao ` as estruturas
A linguagem C utiliza a palavra-chave struct para criar estruturas de dados que s ao utilizadas para armazenar vari aveis, dentro de uma entidade u nica (sem fun co es). O prot otipo para deni ca o de uma estrutura inicia-se com a palavra-chave struct e, em seguida, o nome da estrutura e o bloco com a deni ca o das vari aveis que fazem parte da estrutura. N ao se esque ca do ponto e v rgula ap os o nal do bloco. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
226 Prot otipo: // Declara estrutura SNomeEstrutura struct SNomeEstrutura; // Dene estrutura SNomeEstrutura struct SNomeEstrutura { Tipo1 vari avel1; Tipo2 vari avel2; };
Depois de denida uma estrutura, o seu nome passa a ser um tipo do usu ario, podendo ser utilizada de forma semelhante a de qualquer outro tipo de C++. Para criar um objeto do tipo SNomeEstrutura fa ca: SNomeEstrutura nomeObjeto; Podemos utilizar as vari aveis da estrutura usando nomeObjeto.variavel1 = valor; O exemplo da Listagem 9.4 ilustra a declara ca o e utiliza ca o de estruturas simples. Dentro da struct SPessoa criamos dois vetores de caracteres no estilo de C, nome e matr cula. A fun ca o main() utiliza a estrutura SPessoa para criar um professor. Em seguida, solicita os dados do professor. Na linha SPessoa aluno[numeroAlunos]; criamos um vetor aluno para armazenar informa co es sobre os alunos. Observe que cada casa do vetor armazena uma estrutura do tipo SPessoa. Um la co for e utilizado para entrada dos dados dos alunos, e, ent ao, uma rela ca o com os dados do professor e dos alunos e enviada para a tela. Neste exemplo denimos um tipo novo, o tipo SPessoa, criamos objetos a partir deste tipo, o professor e o vetor aluno, e utilizamos os objetos criados. Listing 9.4: Usando struct.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # include < iostream > // Define uma nova e s t r u t u r a struct SPessoa { char nome [50]; // Vetor nome com 50 c a r a c t e r e s ( uma c s t r i n g ) char matricula [20]; // Vetor m a t r i c u l a com 20 c a r a c t e r e s }; int main () { std :: cout << " Entre com o n u mero de alunos da disciplina ( ex =3) : " ; int n u m e r o A l u n o s ; std :: cin >> n u m e r o A l u n o s ; std :: cin . get () ; SPessoa professor ; std :: cout << " Entre com o nome do professor ( sem espa co ): ";
227
Nota: veremos o uso de estruturas em detalhes no Ap endice G Estruturas, uni oes, enumePrograma ca o Orientada a Objeto com C++ Andr e Duarte Bueno
228 ra co es.
9.3.3
Tamb em podemos criar novos tipos, ou tipos do usu ario utilizando uni oes. Uma union (uni ao) permite a um conjunto de objetos ocupar o mesmo local na mem oria. Veja o prot otipo a seguir. Observe que, como os objetos ocupam o mesmo local na mem oria, somente um objeto pode ser utilizado por vez e que o tamanho da union ser a dado pelo tamanho do maior objeto. Note ainda que podemos colocar dois objetos denidos pelo usu ario dentro de uma union, mas s o podemos utilizar um de cada vez. Isto e, quando um e usado, o outro e perdido. Prot otipo: // Declara uni ao UNomeUniao union UNomeUniao; // Dene uni ao UNomeUniao union UNomeUniao { Tipo1 v1; Tipo2 v2; } A Listagem 9.5 inicia denindo a uni ao UPropriedade, com dois atributos um double e um int. Em seguida, cria objeto a partir da uni ao denida, UPropriedade obj;. O acesso aos atributos da uni ao e simples, nomeObjetoUni ao.nomeAtributo (exemplo: obj.raioHidraulico;). Observe que o sizeof() da uni ao tem a mesma dimens ao do sizeof() de um double. Veremos o uso de sizeof() na Se ca o 9.5.3. Listing 9.5: Usando union.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # include < iostream > int main () { union U P r o p r i e d a d e { int r a i o H i d r a u l i c o ; double condutanc i a ; };
U P r o p r i e d a d e obj ; // Cria objeto do tipo UPropriedade , com nome obj obj . r a i o H i d r a u l i c o = 3; std :: cout << " r a i o H i d r a u l i c o = " << obj . r a i o H i d r a u l i c o << \ t ; obj . condutanci a = 5.0; std :: cout << " condut^ a nci a = "
std :: cout << " sizeof ( double ) = " << sizeof ( double ) << \ t ; std :: cout << " sizeof ( U P r o p r i e d a d e ) = " << sizeof ( U P r o p r i e d a d e ) return 0; } raioHidraulico = 3 sizeof ( double ) = 8 condut^ a nc i a = 5 sizeof ( U P r o p r i e d a d e ) = 8
Nota: veremos o uso de uni oes em detalhes no Ap endice G Estruturas, uni oes, enumera co es. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
229
9.3.4
Uma enumera ca o e uma seq u encia de valores que tem como objetivo enumerar algum processo. Uma enumera ca o e um tipo denido pelo usu ario. No prot otipo a seguir, v1 , v2 , v3 ,..., vn s ao os valores, e ENome e o nome da enumera ca o. Prot otipo: enum ENome { v1, v2, v3,...,vn }; Veja no exemplo a seguir como declarar e usar uma enumera ca o. EDia e o nome da enumera ca o e dom = 1, seg = 2, ter = 3, qua = 4, qui = 5, sex = 6, sab = 7, os valores da enumera ca o. Observe que os valores de cada elemento da enumera ca o s ao incrementados de 1. Note que criamos um objeto do tipo da enumera ca o na linha EDia dia; e o utilizamos da forma como usamos os tipos predenidos de C++. Exemplo: enum EDia { dom, seg, ter, qua, qui, sex, sab }; EDia dia; dia = seg; cout < < "hoje e " < < dia; Nota: veremos o uso de enumera co es em detalhes no Ap endice G Estruturas, uni oes, enumera co es.
9.3.5
Introdu c ao ` as classes
A forma mais comum de criar tipos do usu ario e utilizar o conceito de classe. C++ permite a constru ca o do conceito de classe, com atributos e m etodos, exatamente da forma discutida na Parte I Filosoa e modelagem orientada a objeto. N ao se preocupe se n ao entender exatamente o que est a sendo feito, pois, no Cap tulo 11 Classes, descreveremos em detalhes como criar e utilizar as classes de C++. Implementaremos nossa primeira classe na Listagem 9.6. Nosso objetivo e mostrar a forma como C++ dene uma classe e mostrar que uma classe denida pelo usu ario se comporta da mesma forma que os tipos predenidos da linguagem. Observe que a declara ca o de um objeto do tipo CComplexo (exemplo: CComplexo a, b;) usa o mesmo formato que a declara ca o de um tipo predenido de C++ (exemplo: int x;). A forma de uso tamb em e igual (exemplo: c = a + b). Nota: neste exemplo utilizamos o conceito de sobrecarga de operador na linha c = a + b;. Veja o conceito de operadores no Ap endice C Operadores, e de sobrecarga de operadores no Cap tulo 21 Sobrecarga de operador. O conceito de friend ser a apresentado no Cap tulo 20 Friend. Listing 9.6: Exemplo preliminar de deni ca o de classe do usu ario.
1 2 3 4 5 6 7 8 # include < iostream > // / E x e m p l o p r e l i m i n a r de d e f i n i c~ a o de um tipo de usu a rio , // / por meio de uma classe // / D e f i n i c~ a o do tipo do u s u a r i o CComplexo , r e p r e s e n t a um n u mero c o m p l e x o class CComplexo { public :
230
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
// / A t r i b u t o s real e img double real , img ; // / M e todo usado para d e f i n i c~ a o dos v a l o r e s de real e img void Set ( double _real , double _img ) { real = _real ; img = _img ; } // / S o b r e c a r g a do o p e r a d o r + friend CComplexo operator +( CComplexo & c1 , CComplexo & c2 ) ; }; // / E x e m p l o da d e f i n i c~ a o da s o b r e c a r g a de um o p e r a d o r + // / O o p e r a t o r+ cria um novo n u mero c o m p l e x o com nome c3 onde a r m a z e n a a soma // / dos v a l o r e s reais e i m a g i n a r i o s de c1 e c2 . CComplexo operator +( CComplexo & c1 , CComplexo & c2 ) { CComplexo c3 ; c3 . real = c1 . real + c2 . real ; c3 . img = c1 . img + c2 . img ; return c3 ; } int main () { CComplexo a , b ; // / Fun c~ ao principal
// / Cria os o b j e t o s a e b do tipo C C o m p l e x o // / Chama m e todo Set dos o b j e t o s a e b a . Set (5 , 4) ; // / a . real = 5; a . img = 4 b . Set (2 , 6) ; // / b . real = 2; b . img = 6 CComplexo c ; // / Cria um novo objeto do tipo c o m p l e x o com nome c c = a + b; // / Soma os c o m p l e x o s a e b e a r m a z e n a em c // / Mostra o r e s u l t a d o na tela std :: cout << " c ( " << c . real << " ," << c . img << " ) = " << " a ( " << a . real << " ," << a . img << " ) + " << " b ( " << b . real << " ," << b . img << " ) " << std :: endl ; return 0; // / E n c e r r a o p r o g r a m a
Agora que voc e j a sabe usar os tipos predenidos de C++ (char, int, float, etc.), j a tem id eia de como se declara e se dene um tipo do usu ario (a estrutura SPessoa, a uni ao UPropriedade, a enumera ca o EDia e a classe CComplexo), podemos ver um exemplo que utiliza uma biblioteca externa (a biblioteca-padr ao de C++, a STL). Nota: os tipos num ericos predenidos da linguagem C++, bool, char, int, float e double, podem ser vistos como classes denidas pelo criador do C++ e que est ao escondidas de voc e. Assim, pode-se imaginar que existem as classes: class bool{};, class char{};, class int{};, class float{};, class double{};.
9.4
Uma biblioteca e um conjunto de arquivos objetos reunidos em um u nico arquivo. Voc e pode criar e utilizar suas pr oprias bibliotecas ou utilizar bibliotecas desenvolvidas por terceiros. Veremos como criar nossas pr oprias bibliotecas no Cap tulo ?? Bibliotecas, e na Se ca o ?? Crit erios para sele ca o de bibliotecas externas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
231
Nesta se ca o vamos apresentar uma introdu ca o a duas classes da biblioteca-padr ao de C++: as classes <string> e <vector>.
9.4.1
Basicamente uma string e uma seq u encia de caracteres. Para utilizar a classe string de C++, inclua o arquivo de cabe calho <string>, crie objetos do tipo string e, em seguida, acesse seus m etodos. Veja no exemplo a seguir diferentes formas para criar strings: Exemplo: #include <string> int main() { // Cria string vazia com nome s1 std::string s1; // Cria string com nome s2 e conte udo "a classe string" std::string s2 ("a classe string"); // Cria string com nome s3 e inicializa com " e legal" std::string s3 = " e legal"; // Cria string com nome s4, uma c opia de s3 std::string s4 (s3); // Cria string s5, com espa co para 10 caracteres, preenche com b std::string s5 (10, b); // Cria string com nome s6 e redimensiona para 100 caracteres std::string s6 ("eu terei espa co para 100 caracteres"); s6.resize(100); return 0; } Veja a seguir o prot otipo de alguns m etodos da classe string. Note que size_type, normalmente, e um int informando a dimens ao da string. A palavra-chave const em um par ametro indica que o mesmo n ao vai ser alterado ( e constante). A palavra-chave const no nal da declara ca o de um m etodo indica que este m etodo n ao modica o objeto ( e somente leitura). size type size() const; Retorna o n umero de elementos utilizados pelo container (veja Figura 32.1). Para mudar o size() de um container use resize(novaDimens~ ao). void reserve (size type n = 0); Reserva espa co de mem oria para n elementos (n caracteres). void clear (); Zera a string. A string ca vazia. bool empty () const; Retorna true se a string estiver vazia. void erase(iterator p); Remove o elemento da posi ca o p, isto e, o elemento acessado usando o iterador p. string substr (size type pos = 0, size type n = npos) const; Cria uma substring a partir da posi ca o pos, considerando n caracteres. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
232
size type nd (const char * s, size type pos, size type n) const; Procura a primeira ocorr encia da string s, de modo que a pesquisa inicia em pos e considera at e n caracteres. size type nd (const string & str, size type pos = 0) const; Procura a primeira ocorr encia da cstring str, a pesquisa inicia em pos. const char* c str(); Retorna uma string constante no estilo de C (uma cstring). A palavra-chave const no in cio da declara ca o de um m etodo indica que este m etodo retorna um objeto constante (const char*). Na Listagem 9.7, alguns m etodos da classe string s ao testados. Uma descri ca o detalhada da classe string e apresentada no Cap tulo 24 A classe <string>. Listing 9.7: Exemplo preliminar de uso da classe <string> de C++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # include < iostream > # include < string > int main () { // Cria string com nome s1 std :: string s1 ; s1 = " Oi , tudo bem " ; // Cria string com nome s2 e a r m a z e n a " C ++ e legal " std :: string s2 ( " C ++ e legal " ) ; // Cria string com nome s3 e i n i c i a l i z a com " demais " std :: string s3 = " demais " ; // Tamanho , c a p a c i d a d e e d i m e n s ~ ao std :: cout << " \ ns1 . size () = " << " \ ns1 . capacity () = " << " \ ns1 . max_size () = " m a xima da string s1 << s1 . size () << s1 . capacity () << s1 . max_size () << std :: endl ;
// R e t o r n a true se s1 e s t i v e r vazia if ( s1 . empty () ) std :: cout << " A std :: string s1 esta vazia " << std :: endl ; // C o n c a t e n a c~ ao s1 += s2 + s3 ; std :: cout << " Ap o s s1 += s2 + s3 ; \ ns1 = " << s1 << " \ ns2 = " << s2 << " \ ns3 = " << s3 << std :: endl ; return 0; }
233
9.4.2
A STL, ou Standard Template Library, e uma biblioteca de objetos avan cada que foi desenvolvida utilizando os mais modernos conceitos da programa ca o orientada a objeto em C++. Todo desenvolvimento da STL foi acompanhado e aprovado pelo comit e de padroniza ca o do C++, o ANSI C++ (veja Se ca o 7.3), sendo parte integrante das distribui co es-padr ao de C++. Entre as caracter sticas da STL destacam-se: N ao utiliza polimorsmo em fun ca o do desempenho. Utiliza extensivamente os templates (veremos os templates no Cap tulo 27 Templates). A STL e constru da com base em tr es conceitos (Se ca o 31.1.2): Containers objeto utilizado para armazenar grupos de objetos (como <vector>). Iteradores objetos utilizados para percorrer o container (s ao ponteiros inteligentes). Programa c ao gen erica conjunto de fun co es gen ericas que manipulam os containers utilizando os iteradores. A STL e apresentada em detalhes na Parte III deste livro. No exemplo da Listagem 9.8 voc e ver a a utiliza ca o da classe <vector>, uma classe extremamente u til disponibilizada pela STL. Mas antes de discutirmos o exemplo, vamos apresentar alguns conceitos b asicos de <vector>. Um <vector> e um tipo de container em que os dados est ao armazenados de forma seq u encial; funciona como um vetor no estilo de C (Se ca o 9.3.1), permitindo acesso aleat orio (veja agora as Figuras 32.1 e 31.2). O container <vector> tem r apida inser ca o de objetos no nal do vetor e lenta no meio. Como em vetores comuns de C, <vector> n ao verica os ndices. Isto signica que se o vetor tem dez casas, podemos acessar de v[0] at e v[9]. N ao podemos acessar v[10]. O Acesso a v[10] provoca um acesso de mem oria ilegal, e o programa pode travar/terminar (veremos exemplos de bugs na Listagem ??). Veja no exemplo a seguir como criar e usar um <vector>. Para usar um container do tipo <vector>, inclua o arquivo de cabe calho <vector>. Observe que, como criei objetos do tipo <vector>, posso acessar os m etodos da classe, no caso, o m etodo v.size() retorna o n umero de elementos do container. Exemplo: #include <vector> int main() { // Cria um vetor para armazenar n umeros inteiros // v1 tem tamanho zero. std::vector<int> v1(); // Cria um vetor de inteiros, com 15 elementos, e nome v2 std::vector<int> v2(15); // Cria um vetor de floats com 16 elementos todos iguais a 3.55 std::vector<float> v3(16,3.55); std::cout < < "\nn umero de elementos do container =" < < v3.size() < < "\ncapacidade do container =" < < v3.capacity() < < "\no vetor esta vazio? " < < v3.empty() < < std::endl; return 0; } Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
234
Os m etodos size(), reserve(), clear(), empty() e erase(), brevemente descritos na Se ca o 9.4.1, s ao v alidos para <vector>. Veja a seguir outros m etodos u teis de <vector>. void push back(const T& x); Insere uma c opia do objeto x no nal do vetor (no m do container). void pop back(); Remove o u ltimo elemento do vetor (sem retorno). No exemplo da Listagem 9.8 e criado um vetor e solicitada ao usu ario a entrada de dados. Cada novo valor que o usu ario introduz e armazenado no vetor. Para encerrar a entrada de dados, o usu ario digita Ctrl + d no GNU/Linux e Mac OS X, e ctrl + z no Windows. Em seguida, o programa mostra os valores do vetor. Este exemplo inclui o uso do objeto container <vector> e os m etodos push_back(), size(), empty(), clear(), front() e back(). Note ainda que como a classe <vector> e uma classe gen erica (template), posso criar um vetor de inteiros, de n umeros utuantes ou de outro tipo qualquer. Observe que para criar um <vector> usamos std::vector<Tipo> nomeVetor;, ou seja, e necess ario passar dentro de <> o tipo de objeto que o vetor vai armazenar. No exemplo estamos criando um vetor de inteiros, logo, usamos std::vector <int> v;. O programa utiliza streams, como std::cout e std::cin, para sa da e entrada de dados. O m etodo good() pode ser acessado pela istream std::cin para vericar se a u ltima entrada foi correta. Neste exemplo usamos if(std::cin.good()) para vericar se a entrada foi correta. Caso armativo, o objeto data e acrescentado no m do vetor v com push_back(data);. O programa utiliza ainda estruturas de controle, como, do...while() (veja Se ca o D.3.3), e for (veja Se ca o 8.9.1, D.3.1). Listing 9.8: Exemplo preliminar de uso da classe <vector> da biblioteca STL.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # include < iostream > // Entrada e sa da # include < vector > // Classe de vetores , do container vector int main () // Defini ca ~ o da fun ca ~ o main () . { // Cria um vector , do tipo int , com nome v ( um vetor de inteiros ) // Como um vector pode armazenar objetos de diferente s tipos // ( char , int , float , CComplexo ) preciso informar dentro de <> // o tipo a ser manipulad o pelo vetor . std :: vector < int > v ; int data ; std :: cout << << << <<
" No DOS um Ctrl + z encerra a entrada de dados ." " No Mac um Ctrl + d encerra a entrada de dados ." " No GNU / Linux um Ctrl + d encerra a entrada de dados ." std :: endl ;
// Inicia la c o do .. while , vai ser repetido enquanto a entrada for correta // note que do .. while e executado pelo menos uma vez . do { std :: cout << "\ nEntre com o dado (" << v . size () << ") : "; std :: cin >> data ; std :: cin . get () ; if ( std :: cin . good () ) v . push_back ( data ) ; } while ( std :: cin . good () ) ; // Se a entrada for v a lida // Adiciona data ao final do vetor v // Enquanto n~ a o digitar ctrl +d , ou ctrl + z
235
Primeiro elemento do vetor = 1 U ltimo elemento do vetor = 3 v [0]=1 v [1]=2 v [2]=3 O vetor n~ a o esta vazio O vetor esta vazio
Bem, vimos exemplos de como declarar, denir e utilizar os tipos predenidos de C++, tipos do usu ario e tipos denidos em bibliotecas externas (como a STL). Revise os exemplos e veja que a forma como se declara, dene-se e se usa os tr es tipos de objetos e a mesma.
9.5
Manipulando tipos
Veremos a seguir um conjunto de conceitos de C++ utilizados para manipular os diferentes tipos de objeto de C++.
9.5.1
Um typedef nada mais e do que um apelido para uma declara ca o de um objeto. Veja a seguir o prot otipo para denir e usar um typedef. Prot otipo: typedef TipoConhecido Apelido; Apelido nomeObjeto; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
236
No exemplo a seguir vamos criar um apelido para o tipo const float, com nome cfloat. Um objeto const e float poder a ser criado usando-se cfloat. Exemplo: typedef const float cfloat; cfloat objeto_float_constante; No pr oximo exemplo criaremos outros apelidos, como uint, uchar, ptrInt e schar. Exemplo: typedef unsigned int uint; typedef unsigned char uchar; typedef int* ptrInt; typedef signed char schar; A vantagem do uso de typedefs e que o programador precisa digitar um n umero menor de caracteres. A desvantagem e que em alguns editores perde-se o recurso de identica ca o da sintaxe utilizada, conhecido como sintax highlighty e dispon vel na maioria dos editores de programas (como o emacs, gedit, kate).
9.5.2
O tipo size_t e um conceito gen erico que representa a dimens ao de um objeto (seu tama um tipo integral, sem sinal. O tipo efetivo de size_t depende da plataforma, sendo nho). E usualmente implementado como um int. Veja a seguir o prot otipo para uso de size_t(). Prot otipo: size t(objeto); Nota: de um modo geral size_t e formatado como unsigned int.
9.5.3
O operador sizeof() e utilizado para retornar o tamanho de um objeto em bytes. Quando aplicado a um vetor, retorna o n umero total de bytes do vetor. Pode ser aplicado ao ponteiro de uma fun ca o, mas n ao se aplica a uma fun ca o. Veja a seguir o prot otipo de sizeof(): Prot otipo: sizeof(Tipo); Retorna o tamanho do Tipo. sizeof(obj); Retorna o tamanho do objeto. sizeof(Tipo*); Retorna o tamanho da classe do ponteiro. Na Listagem 9.9 mostramos na pr atica o uso de sizeof(). No in cio da listagem, colocamos em coment ario as instru co es para compilar o programa para plataforma de 32 e 64 bits. At e aqui, todo programa que compilamos tinha o nome a.out . Podemos informar o nome do execut avel com a op ca o -o. Por exemplo, a linha g++ -m64 sizeof.cpp -o sizeof-64 Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
237
e usada para compilar o arquivo sizeof.cpp para plataforma de 64 bits (op ca o -m64), e solicita que o nome do execut avel seja sizeof-64 (op ca o -o sizeof-64). Observe que tamb em geramos uma vers ao de 32 bits do programa. Note as diferen cas no tamanho em bytes dos tipos predenidos de C++: 64 bits: sizeof(long int) = 8 sizeof(long double) = 16 sizeof(&nome) = 8 32 bits: sizeof(long int) = 4 sizeof(long double) = 12 sizeof(&nome) = 4 Note que a sa da das listagens 9.3, 9.9 e as informa co es da Tabela 9.1 s ao dependentes da plataforma (16, 32, 64 ou 128 bits). Isto signica que antes de usar os tipos predenidos voc e deve vericar quais os valores assumidos pelos tipos predenidos na sua plataforma. Listing 9.9: Usando sizeof().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // Vers~ a o 32 bits : g ++ - m32 sizeof . cpp -o sizeof -32 // Vers~ a o 64 bits : g ++ - m64 sizeof . cpp -o sizeof -64 # include < iostream > int main () { char nome [] = " Uma string de C ou cstring " ; std :: cout << " \ n sizeof ( bool ) = " << " \ n sizeof ( char ) = " << " \ n sizeof ( unsigned char ) = " << << << << "\n "\n "\n "\n sizeof ( int ) = " sizeof ( unsigned int ) = " sizeof ( long int ) = " sizeof ( long long int ) = "
<< sizeof ( bool ) << sizeof ( char ) << sizeof ( unsigned char ) << << << << sizeof sizeof sizeof sizeof ( int ) ( unsigned int ) ( long int ) ( long long int )
<< " \ n sizeof ( float ) = " << " \ n sizeof ( double ) = " << " \ n sizeof ( long double ) = "
<< sizeof ( float ) << sizeof ( double ) << sizeof ( long double )
<< " \ n sizeof (& nome ) = " << " \ n sizeof ( nome ) = " return 0; }
<< sizeof (& nome ) << sizeof ( nome ) << std :: endl ;
[ b u e n o @ l d s c 0 5 Cap -09] $ g ++ - m64 sizeof . cpp -o sizeof -64 [ b u e n o @ l d s c 0 5 Cap -09] $ ./ sizeof -64 sizeof ( bool ) =1 sizeof ( char ) =1 sizeof ( unsigned char ) =1 sizeof ( int ) =4 sizeof ( unsigned int ) =4 sizeof ( long int ) =8 <--
238
sizeof ( long long int ) =8 sizeof ( float ) =4 sizeof ( double ) =8 sizeof ( long double ) =16 sizeof (& nome ) = 8 sizeof ( nome ) = 27
<-<--
[ b u e n o @ l d s c 0 5 Cap -09] $ g ++ - m32 sizeof . cpp - o sizeof -32 [ b u e n o @ l d s c 0 5 Cap -09] $ ./ sizeof -32 sizeof ( bool ) =1 sizeof ( char ) =1 sizeof ( unsigned char ) =1 sizeof ( int ) =4 sizeof ( unsigned int ) =4 sizeof ( long int ) =4 <-sizeof ( long long int ) =8 sizeof ( float ) =4 sizeof ( double ) =8 sizeof ( long double ) =12 <-sizeof (& nome ) = 4 <-sizeof ( nome ) = 27
Veja outro exemplo de uso de sizeof() na Listagem C.1. Nota: veremos como gerar programas multiplataforma no Cap tulo ?? Como montar um programa multiplataforma com as ferramentas da GNU. O compilador g++ e descrito em detalhes no Cap tulo ?? Compilando com gcc e g++.
9.5.4
Para facilitar a verica ca o do tipo de determinado objeto, foi desenvolvida a biblioteca <typeinfo>. Essa biblioteca sobrecarrega os operadores == e != para comparar tipos do usu ario. O operador typeid(), quando aplicado a um objeto, retorna o tipo do objeto. Veja a seguir o prot otipo para uso de typeid(). Prot otipo: typeid(objeto); typeid(objeto).name(); Para uso do typeid() e preciso estar ativada a op ca o -RTTI Run Time Type Identication do compilador. No compilador da GNU, o g++, esta op ca o j a e ativada por padr ao. Leia no manual de seu compilador como ativar esta op ca o. Se voc e passar para a fun ca o typeid() um ponteiro (ou refer encia) com o valor 0, a fun ca o typeid() lan ca uma exce ca o do tipo bad_typeid. Veja no exemplo da Listagem 9.10 como vericar se dois objetos a e b s ao do mesmo tipo. Observe que o m etodo typeid() retorna um objeto com informa co es sobre o tipo, assim, voc e pode chamar o m etodo name() para obter o nome da classe do objeto. Listing 9.10: Usando typeid().
1 2 3 4 5 6 # include < iostream > # include < string > # include < typeinfo > // Uso de typeid () using namespace std ; class A { public : int a ; };
239
public : int k ; };
int b ; };
// Cria objeto do tipo A com nome a // Cria objeto do tipo B com nome b // Cria objeto do tipo K com nome k " \ ntypeid ( a ) " \ ntypeid ( a ) " \ ntypeid ( a ) " \ ntypeid ( b ) == == == == typeid ( a ) -> " typeid ( b ) -> " typeid ( k ) -> " typeid ( k ) -> " << << << << ( typeid ( typeid ( typeid ( typeid (a) (a) (a) (b) == == == == typeid typeid typeid typeid (a)) (b)) (k)) (k))
<< " \ ntypeid ( a ) . name () ->" << ( typeid ( a ) . name () ) << " \ ntypeid ( b ) . name () ->" << ( typeid ( b ) . name () ) << " \ ntypeid ( k ) . name () ->" << ( typeid ( k ) . name () ) << endl ; int o b j e t o I n t e i r o = 3; string n o m e O b j e t o I n t e i r o = typeid ( o b j e t o I n t e i r o ) . name () ; cout << " nomeObjetoI nt e ir o - > " << n o m e O b j e t o I n t e i r o << endl ; double o b j e t o D o u b l e = 3; string n o m e O b j e t o D o u b l e = typeid ( o b j e t o D o u b l e ) . name () ; cout << " nomeObjetoDo ub le - > " << n o m e O b j e t o D o u b l e << endl ; return 0; } typeid ( a ) == typeid ( a ) - >1 typeid ( a ) == typeid ( b ) - >0 typeid ( a ) == typeid ( k ) - >0 typeid ( b ) == typeid ( k ) - >0 typeid ( a ) . name () - >1 A typeid ( b ) . name () - >1 B typeid ( k ) . name () - >1 K nomeObjetoIn te i ro - > i nomeObjetoDou bl e - > d
9.6
A tipica ca o forte obriga o programador a tomar mais cuidado na declara ca o, deni ca o e utiliza ca o dos objetos, atributos e m etodos. Em troca, tem uma garantia maior de que o c odigo n ao apresenta problemas, pois, com a tipica ca o forte, o compilador pode encontrar mais facilmente os erros do programa.
9.7
Um tipo do usu ario, ou um tipo de uma biblioteca externa, estar a bem denido se puder ser utilizado da mesma forma que um tipo predenido de C++. Em uma plataforma de 32 bits, o tipo float tem 32 bits, double tem 64 bits e long double tem 96 bits. Note que o tipo long double possui 12 bytes de comprimento e e exatamente assim que o processador 80 x 87 trabalha com n umeros em pontos utuantes. Dessa forma, pode-se passar um objeto do tipo long double diretamente para programas em assembler. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
240
O compilador g++ (descrito no Cap tulo ?? Compilando com gcc e g++) suporta o tipo long long, que representa um inteiro de 64 bits. A convers ao de tipos e discutida no Cap tulo 25 Convers oes.
9.8
Neste cap tulo aprendemos que a linguagem C++ e altamente prototipada. Aprendemos a criar e usar objetos predenidos de C++ (como int e float). Vimos que os tipos predenidos podem ser do tipo inteiro (char, short int, int, long int) ou utuantes (float, double, long double). Os mesmos podem ser explicitamente indicados no c odigo com uso de suxos, como em 7.45f (float) ou 89LL (long long int). Aprendemos a usar o arquivo de cabe calho <limits> e o template numeric_limits<Tipo> para obter informa co es num ericas sobre os tipos predenidos. Vimos exemplos preliminares que mostram como proceder para criar tipos do usu ario e a utiliz a-los da mesma forma que os tipos predenidos de C++. Vimos os vetores no estilo de C, uma introdu ca o ` as estruturas, ` as uni oes, ` as enumera co es e ` as classes, aprendendo a criar tipos do usu ario (tipos do programador). Criamos uma estrutura SPessoa, uma uni ao UPropriedade, uma enumera ca o EDia e uma classe CComplexo. Aprendemos os conceitos b asicos da classe <string> e seu uso para manipular objetos strings em C++. Tamb em aprendemos a utilizar um objeto <vector> da STL. O m etodo push_back(); e usado para adicionar elementos no nal do vetor. O m etodo size(); retorna o tamanho do vetor. O m etodo empty(); retorna true se o vetor estiver vazio e false se estiver com algum elemento. O m etodo clear(); e utilizado para zerar o vetor (apagar todos os elementos). Vimos ainda conceitos como typedef para criar apelidos, typeid() para vericar o tipo do objeto, e sizeof() para obter o tamanho dos objetos. Nos pr oximos cap tulos descreveremos, passo a passo, como criar nossas pr oprias classes (tipos do usu ario) e como utilizar em detalhes os containers da STL.
9.9
Exerc cios
1. Quais s ao os tipos predenidos de C++ e seus respectivos valores m nimos, m aximos? 2. Se vou trabalhar com uma matriz em que os valores variam de -100 a +100, qual tipo devo utilizar? 3. Por que devo tomar cuidado com unsigned? 4. Modique a Listagem 9.1 acrescentando sa da para tela. 5. Modique a Listagem 9.2, troque int por char e veja os resultados. 6. Compile e rode a Listagem 9.3 em computadores de 32 e 64 bits. Verique as diferen cas nas sa das. 7. Modique a Listagem 9.4, acrescentando novas vari aveis na estrutura criada. 8. Documentar a Listagem 9.4, descrevendo o que ocorre a cada linha. 9. Modique a Listagem 9.5, criando uma uni ao de tipos diferentes. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
9.9. EXERC ICIOS 10. Implementeexemplo que utilize enumera co es (Se ca o 9.3.4).
241
11. Modique a Listagem 9.7, acrescentando o uso de find(), reserve(), substr(), clear() e replace(). 12. Modique a Listagem 9.8, acrescentando o uso de erase(), pop_back() e clear(). 13. A Listagem 9.8 apresenta um trecho de c odigo repetido. Monte uma fun ca o externa para tratar esse trecho de c odigo. 14. Compare os m etodos disponibilizados para <vector> e para <string>. 15. Compile e rode a Listagem 9.9, em um computador 32 bits, e anoteos resultados. Repita o procedimento para um computador de 64 bits. 16. Tente modicar a Listagem 9.6. Tente acrescentar um operador de subtra ca o -. 17. Na Listagem 9.2 explique porque foi poss vel criar os n umeros x, y, z duas vezes dentro de main()? 18. Se voc e tiver curiosidade, pode ler antecipadamente a Se ca o 32.1, que descreve o container <vector>.
242
Cap tulo 10
Namespace
Vimos na se ca o 6.2.2 os conceitos de assuntos e pacotes. Veremos, ent ao, que os mesmos podem ser implementados em C++ utilizando-se o conceito de namespace. Para isso, estudaremos o que e um namespace (Se ca o 10.1) e como usar o espa co de nomes da biblioteca-padr ao de C++ (Se ca o 10.2). Em seguida, mostraremos como usar a palavra-chave using para liberar o acesso a determinado objeto (Se ca o 10.3), como denir e utilizar um espa co de nomes para criar pacotes (Se ca o 10.4) e como usar um namespace an onimo (Se ca o 10.5). Veremos ainda o uso avan cado dos namespaces (Se ca o 10.6), como compor namespaces (Se ca o 10.6.1), como criar namespaces aninhados (Se ca o 10.6.2) e como usar vari aveis est aticas em um namespace (Se ca o 10.6.3).
10.1
O que e um namespace?
Vimos na Se ca o 6.2.2 que um pacote e um conjunto de classes mais fortemente relacionadas entre si, e que essas classes costumam fazer parte do mesmo assunto. Usualmente C++ usa o conceito de namespace para empacotar grupos de classes. Como o pr oprio nome diz, namespace signica espa co para nomes. Um namespace e um espa co utilizado para declarar vari aveis, fun co es, classes, uni oes, estruturas, enumera co es etc. Um namespace dene um escopo. Quando voc e monta seu programa utilizando bibliotecas externas, podem ocorrer duplica co es de nomes, isto e, um objeto denido em uma das bibliotecas externas pode ter o mesmo nome de um objeto denido por voc e. Por exemplo: voc e criou as fun co es min() e max(), as quais retornam o menor e o maior valor de um vetor, mas a STL j a possui essas fun co es. Desta forma, ao chamar a fun ca o min(), o compilador n ao sabe qual fun ca o min() voc e quer chamar a que voc e deniu ou a da STL? Solucionar o problema da duplica ca o de nomes pode ser complexo, pois, se esses nomes pertencerem a bibliotecas externas, voc e precisar a contactar os desenvolvedores dessas bibliotecas para resolver os conitos, ou renomear seus objetos e fun co es. Veremos a seguir como usar o namespace padr ao de C++ e, na Se ca o 10.4, como denir um namespace. 243
244
10.2
Para utilizar os objetos da biblioteca-padr ao de C++ e preciso incluir a palavra-chave std e, em seguida, o operador de resolu ca o de escopo ::. Veja o prot otipo. Prot otipo: // Para usar uma fun ca o da std std::nomeFuncao(); // Para usar um objeto da std std::nomeObjeto; // Para chamar uma fun ca o da std com par ametros da std std::nomeFuncao(std::nomePar ametro); Nas listagens de c odigo j a apresentadas, j a utilizamos std::cout, std::cin.get() e std::endl.
10.3
A palavra-chave using e utilizada para mudar o escopo de uma vari avel, um atributo, um objeto, uma fun ca o ou um m etodo. De um modo geral, using pode ser utilizado para: Liberar o uso de um objeto de um namespace para uso no escopo local. No exemplo a seguir liberamos apenas o uso de cout. Exemplo: using std::cout; cout < < "oi tudo bem" < < std::endl; Liberar o acesso de fun co es de escopo diferente no escopo local. No exemplo a seguir liberamos o uso da fun ca o abort(), da biblioteca-padr ao de C. Veja exemplo da Listagem 10.2. Exemplo: #include <cstdlib> using std::abort; // Torna a fun c~ ao abort() acess vel Liberar o uso de todas as classes, objetos e fun co es declaradas dentro de um namespace para uso no escopo local. No exemplo a seguir liberamos todos os objetos, fun co es e classes da std:: para uso local. Exemplo: using namespace std; int x = 3; cout < < " Entre com x : "; cin > > x; cin.get(); cout < < " x = " < < x < < endl; Compor namespaces. Veremos exemplo na Se ca o 10.6.1. 2 Mudar a visibilidade (p ublica, protegida ou privada) dos membros de uma classe em heran cas (Se ca o 17.5). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
245
10.4
Nesta se ca o veremos como criar um pacote utilizando o conceito de namespace. Veja o prot otipo. Observe que colocamos a palavra-chave namespace seguido do nome do namespace. Tudo que estiver dentro do bloco far a parte do namespace, do escopo do namespace. Por conven ca o o nome de um namespace/pacote inicia com letra min uscula. Prot otipo: // Declara ca o/deni ca o do namespace namespace nomeNamespace { // Declara ca o de vari avel/objeto Tipo nome; // Declara ca o de fun ca o retorno NomeFun ca o (par ametros); // Declara ca o de classe class CNomeClasse { // Declara ca o de atributo da classe Tipo nomeAtributo; // Declara ca o de m etodo da classe retorno NomeM etodo(par ametros); }; // Fim da classe } // Fim do namespace // Denindo fun co es de um namespace fora do namespace retorno nomeNamespace::NomeFun ca o(par ametros){...}; // Denindo m etodos de um namespace fora do namespace retorno nomeNamespace::CNomeClasse::NomeM etodo(par ametros){...}; Veja na Listagem 10.1 um exemplo de deni ca o e uso de um namespace. Observe que criamos tr es n umeros x: um global, x = 3, um dentro de main(), x = 2, e um dentro do namespace n1, x = 7. Tamb em criamos dentro do namespace n1 o namespace n2. Dentro da fun ca o main() mostramos como acessar o x global e do namespace, e como chamar a fun ca o Saida(). Observe que dentro de main(), x se refere ao x de main() e, dentro da fun ca o Saida(), x se refere ao x do namespace. Ou seja, cada fun ca o acessa o objeto que est a no seu escopo. Listing 10.1: Denindo e usando um namespace.
# include < iostream > int x = 3; namespace n1 { const int x = 7; void Saida () ; namespace n2 { int y = 4; } } // // // // // // // // // // Objeto x no escopo global Cria um bloco n a m e s p a c e com o nome n1 Inicio do bloco do n a m e s p a c e n1 Objeto x do n a m e s p a c e n1 Fun c~ a o Saida () do n a m e s p a c e n1 Cria n a m e s p a c e n2 a n i n h a d o dentro de n1 Inicio do bloco do n a m e s p a c e n2 Objeto y do n a m e s p a c e n1 :: n2 Fim do bloco do n a m e s p a c e n2 Fim do bloco do n a m e s p a c e n1
int main () {
// Fun c~ a o main ()
246
std :: cout << " \ nFun ca ~ o main () : " << std :: endl ; int x = 2; // Cria x no escopo de main () // U t i l i z a x = 2 std :: cout << " x = " << x << std :: endl ; // U t i l i z a x = 3 global std :: cout << " :: x = " << :: x << std :: endl ; // U t i l i z a x do n a m e s p a c e n1 , x = 7 std :: cout << " n1 :: x = " << n1 :: x << std :: endl ; // U t i l i z a y do n a m e s p a c e n1 :: n2 std :: cout << " n1 :: n2 :: y = " << n1 :: n2 :: y << std :: endl ; n1 :: Saida () ; // Chama fun c~ a o Saida () do n a m e s p a c e n1 return 0; } // D e f i n i c~ a o da fun c~ a o Saida () do n a m e s p a c e n1 void n1 :: Saida () { std :: cout << " \ nFun ca ~ o Saida () do namespace n1 " << " \ nx = " << x // x do n a m e s p a c e << " \ n :: x = " << :: x // x global << " \ nn2 :: y = " << n2 :: y << std :: endl ; } Fun ca ~ o main () : x = 2 :: x = 3 n1 :: x = 7 n1 :: n2 :: y = 4 Fun ca ~ o Sa da () do namespace n1 x = 7 :: x = 3 n2 :: y = 4
O exemplo da Listagem 10.2 mostra o uso de using para colocar duas fun co es de diferentes escopos no escopo de main(). Quando chamamos F(2.33); (linha 25), e executada a fun ca o global (que recebe um int) e n ao a do namespace. Isto ocorre poque a fun ca o F(double) do namespace n ao est a no escopo da fun ca o global. Para colocar as duas fun co es no mesmo escopo usamos using. Quando compilamos um programa o compilador pode emitir mensagens de warning ou cuidado, indicando que estamos utilizando algum recurso da linguagem de forma incorreta. Ao compilar a Listagem 10.2, aparece a mensagem de warning ao converter um float para int na linha 25. Listing 10.2: Usando using para colocar fun co es no mesmo escopo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # include < iostream > void F ( int i ) // Fun c~ a o global { std :: cout << " Global : void F ( int i ) " << std :: endl ; } namespace M e u N a m e s p a c e // Cria um n a m e s p a c e M e u N a m e s p a c e { // Fun c~ a o F ( double ) do n a m e s p a c e M e u N a m e s p a c e . void F ( double d ) { std :: cout << " namespace M e u N a m e s p a c e : void F ( double d ) " << std :: endl ;} // Fun c~ a o G () do n a m e s p a c e M e u N a m e s p a c e . void G () { std :: cout << " namespace M e u N a m e s p a c e : void G () " << std :: endl ; F (3) ;
247
// // // // // // // // // //
Posso c o l o c a r as f u n c~ o e s no escopo de main () Coloca mn :: F ( double ) no escopo de main () Coloca F ( int ) no escopo de main () Chama fun c~ a o F ( int ) global Chama fun c~ a o F ( double ) do n a m e s p a c e
[ b u e n o @ l d s c 0 5 ] $ g ++ namespace . cpp namespace . cpp : In function int main () : namespace . cpp :25: warning : passing double for argument 1 to void F ( int ) [ b u e n o @ l d s c 0 5 ] $ ./ a . out Global : void F ( int i ) Global : void F ( int i ) namespace N : void F ( double namespace N : void F ( double namespace N : void G () namespace N : void F ( double Global : void F ( int i ) namespace N : void F ( double
d) d) d) d)
10.5
Namespaces an onimos
Um namespace pode ser an onimo, isto e, sem nome. Neste caso, vari aveis, fun co es, objetos e classes denidas dentro do namespace est ao no escopo em que o namespace e denido. No exemplo a seguir criamos um namespace an onimo. Observe que a vari avel x pode ser acessada diretamente. Exemplo: namespace // Cria namespace an^ onimo { int x = 0; // Se comporta como uma vari avel global void f(); } int main() { cout < < x < < endl; // Acessa x do namespace an^ onimo diretamente } As vari aveis criadas dentro de um namespace an onimo s o podem ser utilizadas no arquivo em que o namespace foi denido. Funciona da mesma maneira que vari aveis est aticas globais (veja Se ca o B.4). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
248
Programadores de C costumam usar static para indicar que determinada vari avel tem escopo de arquivo. O mesmo pode ser feito com C++, mas e melhor usar um namespace an onimo, porque este pode conter classes, enumera co es e templates, enquanto static suporta apenas fun co es e objetos [Lischner, 2003].
10.6
Veremos nesta se ca o o uso avan cado dos namespaces: Como compor (Se ca o 10.6.1), como criar namespaces aninhados (Se ca o 10.6.2) e como usar vari aveis est aticas em um namespace (Se ca o 10.6.3).
10.6.1
Voc e pode compor dois ou mais namespaces. No exemplo a seguir o namespace minhalib inclui os namespace lib1 e lib2. As linhas using namespace lib1; e using namespace lib2; fazem com que lib1 e lib2 quem no mesmo escopo da minhalib. Exemplo: // Compondo namespaces namespace lib1{...}; namespace lib2{...}; namespace minhalib { using namespace lib1; using namespace lib2; ... }
10.6.2
Namespace aninhado2
Namespaces podem ser aninhados (como classes aninhadas, veja Se ca o 11.5.4). Veja na Listagem 10.1 um exemplo.
10.6.3
Vari aveis est aticas denidas em um namespace precisam ser denidas. Veja Listagem 10.3.
// Uso de v a r i avel est a t i c a em um n a m e s p a c e # include < iostream > namespace m { struct S { static int i ; }; } // Define o a t r i b u t o e s t a t i c o i , da e s t r u t u r a S , do n a m e s p a c e m int m :: S :: i = 1; int main () { // usa a t r i b u t o e s t a t i c o do n a m e s p a c e m , da e s t r u t u r a S std :: cout << m :: S :: i << std :: endl ; return 0; }
249
10.7
Por conven ca o o nome de um pacote/namespace inicia com letra min uscula. Se uma vari avel ou fun ca o e declarada com o mesmo nome de um namespace, ent ao, a vari avel declarada oculta o namespace. O acesso ao namespace deve ser feito usando o operador de resolu ca o de escopo. Fun co es denidas dentro do namespace s ao vis veis entre si (veja no exemplo da Listagem 10.2 as fun co es F() e G()). Em arquivos de cabe calho (*.h) nunca utilize using namespace std;. Por exemplo: para acessar cout nos arquivos de cabe calho use std::cout. Isto se justica, pois, se colocarmos using namespace std; no in cio do arquivo que declara a classe, a inclus ao de um objeto global com o mesmo nome de um objeto do namespace cria uma ambig uidade. Pode-se criar um sin onimo para um namespace. No exemplo a seguir, ml e um apelido para Minha_lib_versao_x_y_z (veja Listagem 10.2): Exemplo: namespace ml = Minha_lib_versao_x_y_z; Utilize um nome de namespace grande e depois crie um sin onimo para ele. Use namespace para grupos de classes que formam um assunto, classes que representam um conceito em comum. A declara ca o using e transitiva, isto e, se o namespace A usa o namespace B, e o namespace B usa o namespace C, um nome acess vel em A tamb em e acess vel em C, [Lischner, 2003]. Um namespace pode ser denido dentro de outro namespace, mas n ao pode ser denido dentro de um bloco (reveja Se ca o 10.6.2 e Listagem 10.1). Um namespace pode ser criado sem um nome namespace an onimo (veja Se ca o 10.5). Exemplo: namespace {...} Segundo [Lischner, 2003], namespaces de C++ s ao semelhantes a namespaces de Java. A diferen ca e que em Java, duas classes do mesmo pacote (namespace) t em privil egios de acesso, o que n ao ocorre em C++. Quando declaramos uma classe dentro de um namespace, todos os atributos, m etodos e operadores devem ser declarados dentro do mesmo namespace. Um namespace n ao tem custo computacional. 2 A senten ca using namespace std; e v alida no escopo em que foi denida, e s o deve ser utilizada em programas pequenos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
250
10.8
Neste cap tulo aprendemos que o conceito de namespace existe para resolver o problema da duplica ca o de nomes por meio da cria ca o de escopos adicionais. Vimos que podemos usar os objetos da biblioteca-padr ao diretamente, basta incluir a declara ca o using namespace std; no in cio do programa. Aprendemos a criar nossos pr oprios namespaces, de forma que podemos usar namespaces para criar o conceito de assunto/pacotes em C++. Aprendemos que um namespace e um escopo, e as fun co es, vari aveis e classes denidas dentro do namespace est ao no escopo do namespace. A deni ca o do escopo e da visibilidade dos objetos em C++ ser a vista na Se ca o 11.2 e no Ap endice B.4. Vimos ainda que a palavra-chave using pode ser utilizada para colocar objetos e fun co es de diferentes escopos em um mesmo escopo. Aprendemos que podemos criar um namespace an onimo, podemos compor namespaces e criar namespaces aninhados. No pr oximo cap tulo, Cap tulo 11 Classe, veremos como implementar o conceito de classes em C++.
10.9
Exerc cios
1. Diga com suas palavras o que e um namespace e quais suas vantagens. 2. Monte os diagramas UML para a Listagem 10.1, acrescentando os pacotes necess arios. 3. Modique a Listagem 10.1, acrescentando um nome longo para n1 e n2, e, em seguida, denindo n1 e n2 como sin onimos. 4. Acrescente o conceito de namespace nas listagens 9.1, 9.2 e 9.6. 5. Modique a Listagem 10.2, acrescentando um namespace n3. 6. Adicione uma vari avel static float j na Listagem 10.3.
Cap tulo 11
Classes
Vimos, no Cap tulo 3 Conceitos b asicos de orienta ca o a objeto, que a classe e a unidade de dentro da classe que declaramos os atributos, encapsulamento dos atributos e dos m etodos. E os m etodos e seus controles de acesso. Neste cap tulo veremos o prot otipo para declarar e denir uma classe em C++ (Se ca o 11.1). Veremos como utilizar as palavras-chave public, protected e private para denir a visibilidade (acesso) dos atributos e m etodos da classe (Se ca o 11.2), bem como a rela ca o entre classes e escopo (Se ca o 11.3) e o uso de diretrizes de pr e-processador com classes (Se ca o 11.4). Veremos ainda o uso avan cado de classes (Se ca o 11.5), as classes abstratas (Se ca o 11.5.1), as classes de interface (Se ca o 11.5.2), o encapsulamento e a robustez de c odigo (Se ca o 11.5.3), as classes aninhadas (Se ca o 11.5.4), as classes do tipo POD (Se ca o 11.5.5) e as classes do tipo trivial (Se ca o 11.5.6).
11.1
Uma classe e um conjunto de atributos (vari aveis ou objetos) reunidos com um conjunto de m etodos (fun co es). Os atributos e m etodos inclu dos na classe s ao aqueles que fazem sentido ` a classe; s ao chamados ainda de elementos da classe. Quando voc e cria uma classe, est a denindo um novo tipo trata-se de um tipo do usu ario. Voc e deve incluir na documenta ca o do programa o conceito e a forma de uso do novo tipo. Um mesmo nome n ao pode ser dado a um m etodo e a um atributo. Para identicar as classes e seus relacionamentos, fa ca associa co es diretas com conceitos do mundo real. Veja exemplo a seguir: Exemplo: Uma classe edif cio, janela, porta etc. Ao criar suas classes, d e a elas um formato simples. Isto pode ser feito dividindo uma classe grande e complexa em classes menores. Crie classes pequenas para realizar tarefas pequenas. Note que o uso de classes extensas torna sua manuten ca o mais complexa. A classe n ao e um objeto, e uma descri ca o do objeto (deni ca o da forma e do conte udo do objeto). 251
252 11.2. ENCAPSULAMENTO EM C++ UTILIZANDO O ESPECIFICADOR DE ACESSO A declara ca o de uma classe dene um escopo, todos os membros da classe est ao no escopo da classe. Adicionalmente, todos os membros de uma classe t em de ser declarados em seu interior. Veja a seguir o prot otipo para declara ca o e deni ca o de uma classe em C++. Verique que existem diferentes tipos de atributos e de m etodos. Ao lado do prot otipo, h a um coment ario informando a se ca o em que o mesmo ser a apresentado. Prot otipo: // Declara ca o, diz que existe a classe class CNomeClasse; // Deni ca o, inclui o corpo da classe class CNomeClasse { // Especicadores de acesso public: // Acesso p ublico, veja se ca o 11.2 protected: // Acesso protegido, veja se ca o 11.2 private: // Acesso privado, veja se ca o 11.2 // Atributos Tipo nome; // Atributos de objeto, veja se ca o 12.2 static Tipo nome; // Atributos de classe, est aticos - static , veja se ca o 12.3, const Tipo nome; // Atributos constantes - const , veja se ca o 12.4 mutable Tipo nome; // Atributos mutantes - mutable , veja se ca o 12.5.1 volatile Tipo nome; // Atributos vol ateis - volatile , veja se ca o 12.5.2 // M etodos Tipo M etodo(par ametros); // M etodos normais, veja se ca o 13.7 Tipo M etodo(par ametros) const ; // M etodos constantes - const , veja se ca o 13.8 static Tipo M etodo(par ametros); // M etodos est aticos - static , veja se ca o 13.9 inline Tipo M etodo(par ametros); // M etodos em linha - inline , veja se ca o 13.10 virtual Tipo M etodo(par ametros); // M etodos virtuais - virtual , veja se ca o 19.2 virtual Tipo M etodo(par ametros)=0; // M etodos virtuais puros, veja se ca o 19.4 }; // Encerra a deni ca o da classe importante observar a presen E ca de (;) no nal do bloco que declara a classe.
11.2
Para a an alise orientada a objeto, encapsulamento e o ato de esconder do usu ario informa co es que n ao s ao de seu interesse. Assim, o encapsulamento envolve a separa ca o dos elementos vis veis de um objeto dos invis veis. Reveja as se co es 3.1, 3.2 e a Figura 3.2. Lembre-se que a vantagem do uso do encapsulamento surge quando h a a necessidade de se modicar um programa ou biblioteca existente. Para implementar o conceito de encapsulamento (ou ocultamento de informa ca o), C++ oferece as palavras-chave public, protected e private. public Signica que o atributo ou m etodo faz parte da interface do objeto, podendo ser acessado de qualquer local. Veremos exemplos nas listagens 13.1, 13.2, 13.3. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
253
protected Signica que o atributo ou m etodo est a protegido de acesso externo. S o pode ser acessado pelos m etodos da classe, pelos m etodos das classes-derivadas (classes herdeiras) e por fun co es amigas friend. Veremos exemplos na Listagem 13.5. private Signica que o atributo ou m etodo s o pode ser acessado pelos m etodos da classe (m etodos internos da classe) e por fun co es amigas friend. Veremos exemplos nas listagens 13.2, 13.3. Para aumentar o encapsulamento da classe, declare tudo como privado. S o deixe como p ublico o que for essencial e zer parte da interface da classe. Evite atributos protegidos, uma vez que eles podem ser utilizados em diversas classes derivadas, sendo dif cil identicar o impacto de mudan cas nestes atributos. A utiliza ca o de public, protected e private ser a esclarecida por meio dos exemplos e listagens apresentados ao longo do livro.
11.3
Classes e escopo
Vimos que um escopo e uma regi ao de c odigo que cont em declara co es, que cada declara ca o adiciona um nome ao escopo, e que o uso desses nomes deve ser resolvido pelo compilador. Conclui-se, ent ao, que n ao podemos ter dois nomes iguais no mesmo escopo, pois isso causa uma ambig uidade. Uma classe dene um escopo. Todo membro (atributo/m etodo) declarado dentro da classe est a no escopo da classe. Para acessar os atributos declarados em uma classe precisamos ter um objeto. Vimos na Se ca o 11.2 que s o podemos acessar externamente os membros p ublicos da classe, ou seja, o membro deve ser vis vel. 2 Atributos de classe, isto e, atributos declarados com static pertencem ` a classe e n ao ao objeto, podendo ser acessados sem um objeto se forem p ublicos. 2 Uma fun ca o friend n ao pertence ao escopo da classe. A palavra-chave friend apenas indica que a fun ca o e amiga. Veremos fun co es e m etodos amigos no Cap tulo 20 Friend.
11.4
Em nossos programas costumamos incluir algumas bibliotecas, como a <iostream>. Se tivermos um programa com muitos arquivos, a biblioteca <iostream> pode ser inclu da mais de uma vez. Para evitar que a <iostream> seja inclu da mais de uma vez na mesma unidade de tradu ca o, no in cio do arquivo <iostream> est ao presentes as seguintes diretrizes de pr eprocessador. Exemplo: #ifndef __IOSTREAM // In cio do bloco #ifndef #define __IOSTREAM // Seq u^ encia da biblioteca.... Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
// Fim do bloco
As instru co es apresentadas realizam os seguintes passos: primeiro vericam se a vari avel __IOSTREAM j a foi denida; se ainda n ao foi, ela e denida e, em seguida, as instru co es compilam a seq u encia da biblioteca. Se a vari avel __IOSTREAM j a foi denida, todo o restante do bloco e pulado. Observe que com essas instru co es a Seq u encia da biblioteca.... s o e pr e-processada uma u nica vez. Da mesma forma, nossas pr oprias classes tamb em devem utilizar as diretrizes de pr eprocesssador para evitar que a classe seja redenida. Veja a seguir como implementar a classe CEndereco ilustrada na Figura 12.1. Observe que basta iniciar o arquivo com as linhas #ifndef CEndereco e #dene CEndereco, e terminar o arquivo com a linha #endif. Exemplo: #ifndef __CEndereco #define __CEndereco #include <string> class CEndereco { protected: int numero; string rua; public: int Numero(); string Rua(); }; #endif // // // // // // // In cio do bloco __CEndereco Define vari avel __CEndereco Classe string da biblioteca padr~ ao Cria classe CEndereco Controle de acesso Acesso protegido Atributos
11.5
Veremos nesta se ca o o uso avan cado de classes em C++. Os conceitos aqui apresentados t em uma rela ca o direta com o conceito de m etodos virtuais, que ser a apresentado na Se ca o 19.2 e com o conceito de polimorsmo, que ser a apresentado na Se ca o 19.3.
11.5.1
Classes abstratas2
M etodos virtuais s ao m etodos que t em seu endere co denido dinamicamente, ou seja, durante a execu ca o do programa. M etodos virtuais puros s ao m etodos que s ao declarados como virtuais na classe-base e que n ao s ao implementados (n ao s ao denidos). Eles ser ao descritos na Se ca o 19.4. Uma classe que cont em m etodos virtuais n ao implementados e uma classe abstrata, n ao podendo ser utilizada para criar objetos. Exemplo: class CNomeClasse { // M etodo virtual puro virtual void NomeM etodo(parametro) = 0; }; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
255
Se n ao podemos criar um objeto, ent ao para que serve uma classe abstrata? Embora n ao possamos criar objetos, podemos criar ponteiros para classes abstratas. Normalmente usamos um ponteiro para classe-base da hierarquia para acessar os diferentes objetos criados. Veremos exemplos na Se ca o 19.3.
11.5.2
Classes de interface2
Segundo [Parga, 2006], Um dos desaos de se trabalhar com POO e criar uma rela ca o um-para-um entre os elementos do problema do mundo real e os elementos da solu ca o onde est a sendo modelado o problema, ou seja, o desao e identicar com clareza os objetos reais, dando-lhes limites claros, al em de denir de forma simples sua interface de acesso. O mesmo autor arma ainda que a interface s o estabelece que pedidos possam ser feitos a um objeto. A codica ca o necess aria para satisfazer cada pedido deve estar denida na classe que implementa essa interface. Esta segunda frase destaca que podemos ter duas classes: a primeira descreve a interface de acesso ( e uma classe abstrata); a segunda implementa de fato as funcionalidades da classe. Em C++ voc e pode criar uma classe de interface, basta que ela s o tenha m etodos p ublicos vazios. Observe que a classe n ao tem atributos, apenas m etodos que informam a forma de acesso ` a classe. Veja a seguir um exemplo de classe de interface. Coloquei a inicial I para indicar que a classe e uma classe de interface. Lembre-se que usamos a inicial C para indicar que se trata de uma classe do usu ario. Observe que usamos o conceito de m etodos virtuais puros, veja Se ca o 19.2. class ICPessoa { public: // Acesso p ublico ICPessoa(){}; virtual ~ICPessoa(){}; virtual std::string Nome() virtual int Idade() virtual std::string Sexo() virtual CEndereco Endereco() };
= = = =
0; 0; 0; 0;
Note a diferen ca entre classe abstrata e classe de interface. A classe abstrata pode ter atributos e m etodos normais; j a a classe de interface s o deve ter m etodos p ublicos.
11.5.3
O conceito de encapsulamento e essencial ao desenvolvimento de softwares robustos e seguros e envolve aspectos como: ocultar os membros internos; garantir que altera co es nos membros internos n ao afetem a interface do objeto; proteger os membros internos de acessos n ao-autorizados. Outro mecanismo u til para garantir maior robustez e denir a interface da classe apenas com m etodos normais, n ao virtuais. Esta t ecnica e conhecida como NVI NonVirtual Interface , [Sutter, 2006]. Os mesmos chamariam m etodos virtuais, veja o exemplo: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
256
Exemplo: class CNome{ public: // M etodos p ublicos n~ ao virtuais void M1() { return M1_v(); }; void M2() { return M2_v(); }; private: virtual void M1_v(); // M etodos privados virtuais virtual void M2_v(); }; Isto garante maior robustez, pois a interface permanece xa, enquanto podemos redeclarar e redenir os m etodos virtuais mais a ` vontade. Por exemplo, poder amos reescrever a classe da seguinte forma: Exemplo: class CNome{ public: void M1() { M1_v_preProcessamento(); M1_v(); M1_v_posProcessamento(); }; void M2() { M2_v(); }; private: virtual void M1_v_preProcessamento(); virtual void M1_v(); virtual void M1_v_posProcessamento(); virtual void M2_v(); }; Note que a interface de M1() n ao foi mudada, mas sua implementa ca o sim. Inclu mos os m etodos virtuais virtual void M1_v_preProcessamento(); e virtual void M1_v_posProcessamento();.
11.5.4
Classes aninhadas3
Podemos declarar classes aninhadas (classes dentro de classes). Veja no exemplo a seguir que a classe CNomeClasse tem uma classe aninhada CNomeClasseAninhada. Veja exemplo na Listagem G.1. Exemplo: class CNomeClasse { public: int x; // Classe aninhada class CNomeClasseAninhada { int y; }; }; Nota: o comportamento de classes aninhadas em C++ e diferente do encontrado em Java. Uma classe aninhada em C++ e como um membro static em Java. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
257
11.5.5
Um POD Plain Old Data e um tipo especial de classe. Veja a seguir suas caracter sticas: Uma classe POD e compat vel com estruturas de C. Todos os seus membros de dados s ao armazenados de forma cont gua. Uma classe POD pode ser copiada usando-se fun co es da biblioteca-padr ao de C, como memcpy(). A vantagem de uma classe POD e que a mesma pode ser manipulada como uma estrutura. Por exemplo, o uso de memcpy() garante melhor desempenho na c opia de uma estrutura. Segundo [Lischner, 2003] uma classe do tipo POD n ao pode ter: construtores e destrutores; operador de c opia; m etodos virtuais; classes-base; membros privados ou protegidos n ao est aticos; membros de dados n ao est aticos que s ao refer encias.
11.5.6
Uma classe trivial e um tipo especial de classe. Segundo [Lischner, 2003] uma classe trivial n ao pode ter: construtores e destrutores; operador de c opia; m etodos virtuais; classes-base. Veja a seguir outras caracter sticas de uma classe trivial: Todas as classes-base de uma classe trivial devem ser triviais. Todos os membros n ao est aticos devem ser triviais. As classes triviais s ao importantes porque uni oes s o podem ter membros triviais. Veremos uni oes na Se ca o G.2. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
258
11.6
Os atributos que comp oem a classe podem ser de diferentes tipos. No exemplo, da classe CEndereco, utilizam-se uma string e um int. Costumo adotar o seguinte padr ao para classes: primeiro coloco os atributos e m etodos p ublicos, depois os protegidos e, por m, os privados. Linguagens como Java e C# t em o conceito de classe de interface. 2 Uma classe-base imediata e chamada de clase-base direta. Uma classe-base n ao imediata e chamada ainda de classe ancestral. 2 Note que fun co es friend n ao est ao no escopo da classe. 2 Uma classe com pelo menos um m etodo virtual e uma classe polim orca. 2 Uma classe A qualquer n ao pode conter um objeto do tipo A, mas somente um ponteiro para A. Antes do nal da deni ca o de uma classe, seu nome s o pode ser utilizado se o tamanho da classe n ao for necess ario. 2 Lembre-se: uma classe do usu ario e um tipo novo e deve ter todos os elementos esperados, isto e, construtor/destrutor, construtor de c opia, operadores, m etodos de convers ao, atributos e m etodos. 2 Uma classe com atributos const ou refer encias t em de ter obrigatoriamente um construtor para inicializar esses atributos. Veja Se ca o 16.1. 2 Se um m etodo tem inicializadores, isto e, atributos com valores predenidos, estes devem car vis veis na classe (arquivo *.h), pois quem utiliza a classe olha o arquivo de cabe calho (*.h) e nem sempre tem acesso ao arquivo de implementa ca o (*.cpp). Veja Se ca o 13.6.4. 2 Note que uma classe de interface tamb em pode ser implementada utilizando heran cam ultipla. 3 Como um membro privado participa da pesquisa de resolu ca o do m etodo a ser executado, e vis vel nos arquivos em que foi inclu do, mas n ao pode ser chamado porque e privado, de modo que algumas chamadas podem se tornar inv alidas ou amb guas, mesmo que o m etodo nunca possa ser executado [Sutter, 2006]. Veja Se ca o 14.3.1. 3 Podemos ter classes locais, isto e, classes declaradas dentro de blocos, mas elas t em as seguintes restri co es [Lischner, 2003]: N ao podem ter membros est aticos. Todos os m etodos internos devem ser inline. Uma classe local n ao pode ser utilizada como argumento de um template. 3 O polimorrmo em tempo de compila ca o utilizando templates possibilita a quebra do conceito de encapsulamento e, portanto, deve ser evitado. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
259
11.7
Vimos e revimos alguns conceitos b asicos sobre classes e o prot otipo para declarar e denir uma classe em C++. Aprendemos a denir a visibilidade (encapsulamento) com o uso das palavras-chave public, protected e private. Vimos que C++ usa m etodos p ublicos e abstratos para criar classes de interface. Lembre-se: os m etodos abstratos s ao declarados mas n ao denidos. Aprendemos que os membros da classe est ao no escopo da classe. Aprendemos a evitar que um mesmo bloco com deni ca o de um namespace ou classe seja compilado duas vezes usando as diretrizes de pr e-processador #ifndef, #define e #endif. Aprendemos a diferenciar classes abstratas de classes de interface. Aprendemos que a deni ca o da interface de uma classe e extremamente importante, e um dos momentos cruciais no design de um sistema. Isto signica que deve-se dispender um bom tempo de an alise com a correta deni ca o da interface. Isto se justica, pois a redeni ca o da interface tem um custo elevado. Aprendemos a aumentar o encapsulamento das classes usando a t ecnica NVI (Se ca o 11.5.3). Finalmente, vimos como criar classes aninhadas, classes do tipo POD e classes triviais.
11.8
Exerc cios
1. Abra um editor UML (como umbrello ou vp), monte um diagrama de classes e, em seguida, gere o c odigo. Abra os arquivos gerados em um editor de texto e verique se os mesmos seguem o prot otipo denido neste cap tulo (Se ca o 11.1). 2. Baixe alguns programas em C++ na internet e veja se os mesmos seguem o prot otipo denido neste cap tulo (Se ca o 11.1). Observe que cada autor costuma ter um estilo um pouco diferente, mas a estrutura geral e a mesma. 3. D e uma olhada no estilo dos arquivos da biblioteca-padr ao (no GNU/Linux est ao em /usr/include/c++/vers ao, no Windows est ao instalados no diret orio do pacote de desenvolvimento). 4. D e exemplos de objetos com atributos e m etodos que devem ser p ublicos. Em seguida, indique atributos protegidos e privados. 5. Exponha com suas palavras o que e uma classe de interface. 6. Para que servem as classes triviais? 7. Neste momento voc e pode reler a Se ca o 6.11.3, senten cas para conseguir o reuso de classes. 8. Explique com suas palavras como funciona o escopo em uma classe. 9. Para que servem as classes abstratas? E as classes de interface? 10. O que s ao classes aninhadas? 11. O que signica POD? E NVI?
260
Cap tulo 12
Atributos
Neste momento voc e pode reler a Se ca o 3.4, a qual apresenta o conceito de atributo. Veremos neste cap tulo o prot otipo para declarar e denir atributos em C++ (Se ca o 12.1), o que s ao atributos de objeto (Se ca o 12.2), atributos de classe static (Se ca o 12.3) e os atributos constantes const (Se ca o 12.4). Veremos ainda o uso avan cado dos atributos (Se ca o 12.5), os atributos mutantes mutable (Se ca o 12.5.1) e os atributos vol ateis volatile (Se ca o 12.5.2). Nota: exemplos completos de classes com atributos e m etodos ser ao apresentados no Cap tulo 13 M etodos.
12.1
Em C++ um atributo pode ser um tipo predenido da linguagem, um tipo denido pelo programador ou um tipo denido em uma biblioteca externa, como a STL (veja Cap tulo 9 Tipos). Veja a seguir o prot otipo para declara ca o de um atributo normal, de um atributo de classe (ou est atico) e de atributos const, mutable e volatile. Ao lado do prot otipo est a o n umero da se ca o em que o mesmo ser a apresentado. Prot otipo: // Arquivo CNomeClasse.h class CNomeClasse { // Atributos Tipo nome; // Atributos de objeto, veja se ca o 12.2 static Tipo nome; // Atributos de classe, est aticos - static , veja se ca o 12.3, const Tipo nome; // Atributos constantes - const , veja se ca o 12.4 mutable Tipo nome; // Atributos mutantes - mutable , veja se ca o 12.5.1 volatile Tipo nome; // Atributos vol ateis - volatile , veja se ca o 12.5.2 }; // Arquivo CNomeClasse.cpp Tipo CNomeClasse::nomeA; // Deni ca o de atributo est atico 261
262
12.2
Atributos de objeto
Um atributo de objeto e declarado dentro da classe sem a utiliza ca o do modicador de tipo static. Para criar um atributo de objeto, coloca-se o tipo seguido do nome do atributo. Exemplo: class CNomeClasse { public: int x; }; O exemplo da Listagem 12.1 ilustra a declara ca o, dentro da classe, de alguns atributos. O diagrama UML da classe CEndereco e da classe CTeste e ilustrado na Figura 12.1. No in cio do arquivo inclu mos as classes- padr ao de C++ que ser ao utilizadas e denimos o uso dos objetos no escopo da std. Criamos as classes CEndereco e CTeste. A classe CEndereco tem dois atributos: o primeiro e um n umero inteiro utilizado para armazenar o n umero da casa; o segundo e a string rua, utilizada para armazenar o nome da rua. Os m etodos Numero() e Rua() retornam, respectivamente, o n umero e nome da rua. Os m etodos ser ao apresentados no Cap tulo 13 M etodos. A segunda classe, CTeste, tem cinco atributos. Dois deles s ao tipos predenidos (int e float), o terceiro atributo, CEndereco, e um objeto da classe que denimos anteriormente. Temos ainda um atributo <string> e um atributo <vector>. Ou seja, a classe CTeste tem atributos de diversos tipos. Observe que dentro da classe CTeste, declaramos um objeto do tipo CEndereco. Os tipos ou classes denidas por n os passam a funcionar da mesma forma que os tipos predenidos da linguagem. Note que a classe <vector> e uma classe template, e que precisamos passar dentro de <> o tipo de objeto que ser a armazenado no vetor vd. No caso, vd armazenar a n umeros do tipo double. Dentro da fun ca o main(), criamos um objeto do tipo CTeste com nome obj. Em seguida, utilizamos os atributos denidos em CTeste, como x, nome e vd. Note que para acessar os atributos do objeto usa-se nomeObjeto.nomeAtributo (exemplo: obj.x = 3.1;). A linha obj.vd.push_back(34.5); e usada para adicionar no vetor vd o n umero 34.5. Veja na Figura 12.1 como ca um objeto do tipo CEndereco e CTeste na mem oria. Os m etodos ser ao descritos em detalhes no Cap tulo 13 M etodos. Listing 12.1: Usando atributos de objeto em uma classe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # include < iostream > # include < string > # include < vector > using namespace std ; // // // // E n t r a d a e sa da de dados Classe string de C ++ C o n t a i n e r < vector > da stl E s t a m o s usando o n a m e s p a c e std
class CEndereco // Cria classe C E n d e r e c o { public : int numero ; // A t r i b u t o s string rua ; public : // M etodos int Numero () { return numero ; } string Rua () { return rua ; } }; class CTeste // Cria classe CTeste
263
// // // // //
int e um tipo pr e - d e f i n i d o de C ++ float e um tipo pr e - d e f i n i d o de C ++ C E n d e r e c o foi d e f i n i d o acima O tipo string e um tipo da biblioteca - padr~ ao O tipo vector e um tipo da biblioteca - padr~ ao
// Dentro da fun c~ a o main () cria e usa um objeto do tipo CTeste int main () { CTeste obj ; // Cria objeto do tipo CTeste com nome obj obj . x = 3.1; // A r m a z e n a o valor 3.1 em obj . x obj . endereco . rua = " Avenida Atlantida " ; obj . endereco . numero = 360; obj . nome = " Joao da Silva " ; // A r m a z e n a " jo~ a o " em obj . nome obj . vd . push_back (34.5) ; cout << " \ nobj . x = " << obj . x << " \ nobj . nome = " << obj . nome << " \ nendereco . rua = " << obj . endereco . rua << " \ nendereco . numero = " << obj . endereco . numero << " \ nobj . vd [0] = " << obj . vd [0] << endl ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ a . out obj . x = 3.1 obj . nome = Joao da Silva endereco . rua = Avenida Atlantida endereco . numero = 360 obj . vd [0] = 34.5
Figura 12.1: Como cam os objetos do tipo CTeste e CEndereco na mem oria.
UML Objeto do tipo CTeste na memria Objeto do tipo CEndereco na memria
CEndereco
+numero: int +rua: string +Numero(): int +Rua(): string
CTeste
+contador: int +x: float +endereco: CEndereco +nome: string +vd: vector<double> Inclui todo o vetor vd
numero rua
12.3
Existem dois tipos de atributos dentro de uma classe: os atributos de objeto (individuais, s ao armazenados no objeto) e os atributos de classe (coletivos, s ao armazenados na classe). O objetivo dos atributos de classe e possibilitar o seu compartilhamento por todos os objetos criados. Outro objetivo dos membros est aticos em classes e eliminar o uso de vari aveis globais. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
264
Para criar um atributo de classe, coloca-se a palavra-chave static seguida do tipo e do nome do atributo.
O exemplo a seguir ilustra a declara ca o e a deni ca o de atributos de classe (est aticos). O atributo mec e um atributo est atico.
Exemplo: #include "CEndereco.h" class CUniversidade { public: // Atributo de objeto, do tipo int, com nome numeroAlunos int numeroAlunos; // Atributo de objeto, do tipo CEndereco, com nome endereco CEndereco endereco; // Atributo de classe (static), do tipo string, com nome mec static string mec; }; string CUniversidade::mec = "Minist erio Educa c~ ao e Cultura"; int main() { // Cria dois objetos do tipo CUniversidade CUniversidade ufsc,unicamp; return 0; }
Observe que atributos est aticos precisam ser denidos fora da classe. Observe a forma da deni ca o.
Veja na Figura 12.2 o diagrama UML da classe CUniversidade e como ca a mem oria para os objetos ufsc e unicamp. Observe que tanto o objeto ufsc quanto o objeto unicamp t em os atributos numeroAlunos e endereco, mas o atributo mec e armazenado na classe e compartilhado pelos dois objetos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
265
Figura 12.2: Como cam os objetos na mem oria quando a classe tem atributos est aticos.
Diagrama UML Objetos ufsc e unicamp na memria Memria do programa
CUniversidade
+mec: string +numeroAlunos: int +endereco: TEndereco Atributo esttico aparece sublinhado Atributo esttico armazenado na classe e compartilhado pelos objetos ufsc e unicamp. Objeto ufsc numeroAlunos endereco Objeto unicamp numeroAlunos endereco classe CUniversidade mec
Note que a altera ca o de um atributo est atico se reete em todas as inst ancias da classe. Se o atributo for est atico e p ublico, poder a ser acessado externamente sem um objeto. Basta passar o nome da classe, o operador de resolu ca o de escopo (::) e o nome do atributo. Exemplo: string orgao_regulador = CUniversidade::mec; Nota: atributos inteiros constantes e est aticos e enumera co es podem ser denidos dentro da classe. Exemplo: class CNomeClasse { static const int valor = 5; };
12.4
O objetivo de um atributo const e fornecer ao objeto um atributo que ele poder a acessar, mas n ao poder a alterar, ou seja, e utilizado para cria ca o de atributos constantes (somente leitura). Um atributo const deve ser inicializado nos m etodos construtores da classe, n ao podendo mais ser alterado. Os m etodos construtores ser ao descritos na Se ca o 16.1, e o uso de atributos const na Se ca o 16.4. No exemplo a seguir, o atributo static const float pi; pertence ` a classe e n ao pode ser modicado. O atributo max pertence ao objeto, e inicializado no construtor da classe e n ao pode ser alterado ( e constante). Exemplo: class CMath { // Atributo est atico e constante, do tipo float, // com nome pi pertence a classe static const float pi; // Atributo normal e constante, do tipo int, // com nome max, pertence ao objeto Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
266
const int max; // Inicializa atributo max no m etodo construtor (detalhes na sec~ ao 16.4) CMath(int _max) : max(_max){}; }; // Inicializa atributo est atico const float CMath::pi = 3.141516; Veja outro exemplo na Listagem 13.3.
12.5
Veremos nesta se ca o o uso avan cado de atributos em C++. O que s ao os atributos mutantes mutable (Se ca o 12.5.1) e os atributos vol ateis volatile (Se ca o 12.5.2).
12.5.1
Se uma classe tem um m etodo membro const, TipoDeRetorno NomeM etodo(par^ ametros) const; este n ao pode alterar os atributos da classe. Uma forma de contornar isto e denir o atributo como mutable. A palavra-chave mutable signica que o atributo pode mudar, mesmo que ele seja declarado como const. Membros mutable s ao usados em atributos que s ao logicamente const, mas que por motivos operacionais podem ser alterados [Lischner, 2003]. A utilidade real de mutable ocorre quando um m etodo utiliza diversos atributos do objeto, mas voc e quer ter certeza de que estes n ao ser ao alterados e por isso declara o m etodo como const. No entanto, por algum motivo, um determinado atributo precisa ser alterado, bastando para tal deni-lo com o qualicador mutable. Exemplo: class CTeste { public: mutable int x; void Altera_x() const; } A seguir, embora o m etodo Altera_x() seja const, x e alterado pois foi declarado como mutable. void CTeste::Altera_x()const { x++; }; A palavra-chave mutable pode ser utilizada em classes como uma alternativa ao const_cast<> (Se ca o 25.8). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
267
12.5.2
A palavra-chave volatile e utilizada para dar a um atributo o status de volatile. Este tipo de atributo pode mudar de forma inesperada. volatile e utilizado na programa ca o paralela com threads. Veja exemplos de uso de volatile no Cap tulo ?? Introdu ca o ao processamento paralelo com m ultiplas threads. Veremos exemplo na Listagem ??.
12.6
Observe que voc e pode combinar alguns qualicadores e um especicador. Veja no exemplo a seguir a utiliza ca o dos qualicadores const e volatile e do especicador int. Exemplo: int x; const int y; const volatile int x; Lembre-se: os atributos devem ser, na medida do poss vel, sempre privados e devem ser acessados usando m etodos p ublicos. Desta forma o acesso pelos clientes e uniforme. Uma das vantagens desta t ecnica e poder substituir os m etodos void NomeAtributo() por vers oes que, al em de retornar/setar o atributo, realizam alguma opera ca o adicional. No exemplo a seguir, quando mudamos o n umero de intervalos, nx, devemos recalcular dx, considerando os intervalos de integra ca o xmax e xmin. Exemplo: // Cria atributo nx int nx; // Seta novo valor para nx, e j a atualiza dx void Nx(int _nx) { nx = _nx; dx = (xmax - xmin) / nx; }; // Obt em valor de nx int Nx() { return nx; }; O uso de m etodos para acessar os atributos da classe garante a invari ancia da classe. Membros est aticos podem ser utilizados para compartilhar atributos entre objetos da mesma classe. Se o atributo for o mesmo para todas as classes da hierarquia, use static. Em alguns casos, mas n ao sempre, o uso de const faz com que o programa que mais r apido. Como o uso de const aumenta a seguran ca do programa, use e abuse de const. Para maiores detalhes veja [Sutter, 2006]. 2 Se o atributo for const, este n ao muda. Como ele n ao muda seu valor, deve ser denido no construtor. 2 Lembre-se que a declara ca o const n ao garante totalmente que o atributo seja const, pois podemos usar const_cast<>, mutable ou volatile para mudar um atributo const. 2 Um objeto est atico denido em um m etodo e criado na primeira execu ca o do m etodo e destru do no nal da execu ca o do programa. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
268 Exemplo int M etodo() { static int x = 0; ... return x; } 3 Uma classe local n ao pode conter membros est aticos.
12.7
Vimos o conceito de atributos na Se ca o 3.4, e, neste cap tulo, aprendemos a implementar diferentes tipos de atributos com C++. Aprendemos a declarar e denir atributos na Se ca o 12.1. Vimos que na maioria dos casos trabalharemos com atributos de objeto, mas, quando necess ario, podemos usar os atributos de classe (declarados com static). Aprendemos que podemos declarar dentro da classe atributos const, mutable e volatile, sendo que const e mais utilizado. Lembre-se que um const e um atributo que vai ser inicializado na constru ca o do objeto e que vai se manter constante. No pr oximo cap tulo, Cap tulo 13 M etodos, veremos na pr atica v arios exemplos de classes. Veremos como inicializar os atributos no construtor na Se ca o 16.4 e a ordem de constru ca o dos atributos de um objeto na Se ca o 16.6.1.
12.8
Exerc cios
1. Na Listagem 12.1 use o operador sizeof() para obter o tamanho dos objetos CEndereco e CTeste. 2. Monte um exemplo que inclua atributos normais, est aticos e const. 3. Construa uma classe com atributos const (Se ca o 12.4).
Cap tulo 13
M etodos
Vimos na Se ca o 3.5 o conceito de m etodos. Neste cap tulo mostraremos como implementar o conceito de m etodos em C++. Veremos uma introdu ca o aos m etodos de C++ (Se ca o 13.1), o prot otipo para declarar, denir e utilizar m etodos em uma classe (Se ca o 13.2), os detalhes da declara ca o (Se ca o 13.3), deni ca o (Se ca o 13.4) e retorno dos m etodos (Se ca o 13.5). Al em disso, veremos como funciona a passagem de par ametros (Se ca o 13.6), por c opia (Se c ao 13.6.1), por refer encia (Se ca o 13.6.2), por ponteiro (Se ca o 13.6.2) e o uso de par ametros predenidos (Se ca o 13.6.4). Veremos tamb em o que s ao os m etodos normais (Se ca o 13.7), os m etodos constantes const (Se ca o 13.8) e os m etodos est aticos static (Se ca o 13.9), al em de aprendermos como otimizar o programa utilizando os m etodos em linha inline (Se ca o 13.10). Por m, veremos links para se co es em que trataremos do uso avan cado de m etodos e algumas senten cas u teis. Nota: neste momento voc e pode reler a Se ca o 6.11.4, senten cas para conseguir o reuso de m etodos e para construir m etodos robustos.
13.1
O leitor mais atento deve ter percebido que o que estamos fazendo e denir um conjunto de ferramentas relacionadas ao uso dos objetos. Imagine o objeto como sendo uma caixa, onde atributos/propriedades podem ser armazenados. Os m etodos s ao funcionalidades que podemos realizar com nossa caixa. Imagine que temos uma caixa com bolinhas de gude, de todos os tipos e cores. As bolinhas de gude s ao atributos do tipo todo parte do objeto caixa. Ou seja, voc e sabe que uma bolinha de gude n ao e uma caixa, mas que uma caixa pode ter bolinhas de gude. A pergunta e: voc e deixaria qualquer um mexer em suas bolinhas de gude? Provavelmente muito prov n ao. E avel que voc e queira dividir sua caixa em tr es partes. Na primeira divis ao, p ublica, voc e coloca as bolinhas de gude que qualquer um poder a acessar. Na segunda divis ao, protegida, voc e coloca bolinhas especiais, que somente voc e e seus lhos poder ao mexer. Finalmente, em uma terceira divis ao, voc e vai colocar aquelas bolinhas especiais, que somente voc e ter a acesso. Esta divis ao e bastante pr oxima de nossa realidade, de nosso dia-a-dia. A mesma e implementada em C++ com os especicadores de controle de acesso public, protected e private. Vamos a um outro exemplo, uma pessoa. Uma pessoa tem atributos normais, que mudam com o tempo. Como exemplo a idade, o peso. Tamb em temos atributos que s ao constantes, n ao mudam. Como exemplo, o sexo e a data de nascimento, os quais s ao denidos quando 269
270
o objeto tem origem e n ao muda nunca mais. Finalmente, um grupo de irm aos tem algumas caracter sticas em comum, compartilhadas. Como exemplo, o sobrenome e o nome do planeta em que vivemos (nosso programa s o atende aos terr aqueos). Veremos em nossos exemplos que esses conceitos da vida real s ao implementados em C++ com os atributos normais (peso), const (data de nascimento, nome dos pais) e static (sobrenome, planeta em que vivem). Enm, os conceitos j a existem. Precisamos usar os mecanismos da linguagem C++ para informar o compilador que o objeto tem um determinado comportamento. Isto e feito com o uso das palavras-chave public, protected, private, const, static etc.
13.2
Vimos anteriormente os conceitos de declara ca o (Se ca o 8.4) e deni ca o (Se ca o 8.5). Para m etodos a declara ca o informa que o m etodo existe (sua assinatura); j a sua deni ca o reserva espa co de mem oria para o c odigo do m etodo. A rela ca o entre a declara ca o e a deni ca o e dada pela assinatura do m etodo. Veja a seguir o prot otipo para declara ca o de um m etodo. Os itens dentro de [] s ao opcionais. Cada um desses itens ser a explicado neste ou nos pr oximos cap tulos. Prot otipo: [Pr e-qualicador] TipoRetorno NomeM etodo([Tipo Par ametro,...]) [P os-qualicador] Pr e-qualicador inline , static , extern , explicit , virtual , friend TipoRetorno void, bool , char , short , int , long , float , double , tipos do usu ario, tipos de bibliotecas externas,... NomeM etodo Nome do m etodo denido pelo programador (Tipo Par ametro,...) Tipo e nome de cada par ametro [na declara ca o o nome e opcional, na deni ca o e obrigat orio], o tipo pode incluir: void, bool , char , short , int , long , float , double , tipos do usu ario, tipos de bibliotecas externas,... P os-qualicador const , volatile , [lista de exce co es que podem ser lan cadas] Veja a seguir o prot otipo para declarar e denir os m etodos de uma classe. Observe que os m etodos s ao declarados dentro da classe (no arquivo CNomeClasse.h) e denidos fora da classe (no arquivo CNomeClasse.cpp), com exce ca o dos m etodos inline, os quais podem ser declarados e denidos dentro da classe. Veja ainda que a declara ca o dos m etodos normais, est aticos, em linha e virtuais e diferente, mas a deni ca o e igual. A deni ca o do m etodo const inclui a palavra-chave const. Ao lado do prot otipo do m etodo colocamos o n umero da se ca o em que o mesmo ser a apresentado. Prot otipo: // Arquivo CNomeClasse.h class CNomeClasse { Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
DE UM METODO 13.3. DECLARAC AO // Declara ca o de M etodos Tipo M etodo(par ametros); Tipo M etodo(par ametros) const ; static Tipo M etodo(par ametros); inline Tipo M etodo(par ametros); virtual Tipo M etodo(par ametros); virtual Tipo M etodo(par ametros)=0;
271
// M etodos normais, veja se ca o 13.7 // M etodos constantes - const , veja se ca o 13.8 // M etodos est aticos - static , veja se ca o 13.9 // M etodos em linha - inline , veja se ca o 13.10 // M etodos virtuais - virtual , veja se ca o 19.2 // M etodos virtuais puros, veja se ca o 19.4
// M etodo inline impl cito, veja se ca o 13.10 Tipo M etodo(par ametros) { ... Implementa ca o do m etodo ... return(Tipo); } }; // Fim da declara ca o da classe Prot otipo: // Arquivo CNomeClasse.cpp #include CNomeClasse.h // Deni ca o de um m etodo da classe Tipo CNomeClasse::M etodo(par ametros) { ... Implementa ca o do m etodo ... return(Tipo); } // Deni ca o de um m etodo const da classe Tipo CNomeClasse::M etodo(par ametros) const { ... Implementa ca o do m etodo ... return(Tipo); } Nota: o acesso aos m etodos da classe pode ser modicado com as palavras-chave public, protect e private (veja Se ca o 11.2). Veja na Se ca o 10.4 o prot otipo para declarar e denir um m etodo em uma classe denida dentro de um namespace. Veremos a seguir cada uma das tarefas realizadas por um m etodo. Al em disso, veremos como declarar e denir um m etodo, seu retorno e seus par ametros.
13.3
Declara c ao de um m etodo
Um m etodo recebe como par ametros de entrada um conjunto de objetos, realiza determinada seq u encia de opera co es e, em seguida, retorna um objeto. As tarefas realizadas por um m etodo em C++ s ao: Receber uma lista de objetos (par ametros). Executar um conjunto de tarefas. Retornar apenas um objeto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
272
A declara ca o de um m etodo e a descri ca o de seu retorno, seu nome e seus par ametros, antes de sua deni ca o. A vantagem das declara co es e que elas facilitam o trabalho do compilador, ou seja, auxiliam na identica ca o da chamada de m etodos com par ametros errados. No exemplo a seguir o retorno e do tipo int, o nome do m etodo e SomaInt(), e os par ametros s ao dois objetos do tipo int. Note que na declara ca o de um m etodo, o nome dos par ametros e opcional. A declara ca o do m etodo SomaFloat() inclui como retorno um float, e como par ametro, dois objetos do tipo float, com nomes a, b. Exemplo: // Arquivo CSoma.h class CSoma { public: // Declara c~ ao do m etodo SomaInt(), par^ ametro sem nome int SomaInt( int , int ); // Declara c~ ao do m etodo SomaFloat(), par^ ametro com nome float SomaFloat( float a, float b ); };
13.4
Deni c ao de um m etodo
A deni ca o de um m etodo e a implementa ca o de seu c odigo, do conjunto de instru co es que ser ao executadas pelo m etodo. Veja a seguir a implementa ca o do m etodo SomaInt() e seu uso dentro da fun ca o main(). Observe que colocamos o retorno, int, o nome da classe, CSoma, o operador de resolu ca o de escopo (::), o nome do m etodo, SomaInt(), e seus par ametros ( int a, int b ). O nome da classe seguido de :: e necess ario pois informa ao compilador que o m etodo SomaInt() pertence a classe CSoma. Se n ` ao colocarmos CSoma::, deixando apenas int SomaInt( int a, int b );, teremos uma fun ca o global e n ao um m etodo da classe (um erro comum). Exemplo: // Arquivo CSoma.cpp // Inclui o arquivo "CSoma.h" com a defini c~ ao da classe CSoma #include "CSoma.h" // Defini c~ ao do m etodo SomaInt() da classe CSoma int CSoma::SomaInt ( int a, int b ) { return a + b; } // Arquivo programa.cpp // Uso do m etodo SomaInt() da classe CSoma #include "CSoma.h" #include <iostream> int main() { // Cria objetos do tipo int com nomes x e y int x = 3; int y = 4; // Cria objeto do tipo CSoma com nome obj CSoma obj; // Uso do m etodo SomaInt() de obj Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
13.5. RETORNO DE UM METODO int z = obj.SomaInt(x,y); std::cout < < "\nSoma = " < < z < < std::endl; return 0; }
273
Observe que para criar um objeto do tipo int, fazemos int nomeObjeto;. Para criar um objeto do tipo do usu ario, o procedimento e o mesmo, CSoma obj;. Tendo um objeto da classe CSoma, podemos acessar seus atributos e m etodos p ublicos diretamente, como em obj.SomaInt(x,y);.
13.5
Retorno de um m etodo
Todo m etodo deve ter um tipo de retorno. O retorno e os par ametros de um m etodo podem ser de qualquer tipo, isto e, um tipo predenido de C++, um tipo do usu ario ou um tipo denido em uma biblioteca externa. C++ tem alguns padr oes de retorno denidos no arquivo de cabe calho <cstdlib>, como EXIT_SUCESS e EXIT_FAILURE. #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 Quando voc e n ao quiser nenhum retorno, dever a especicar o tipo void. O uso de void como retorno signica que o m etodo n ao tem retorno. No exemplo a seguir o M etodo() n ao tem nenhum retorno, o que e informado com a palavra-chave void. Exemplo: class CMath { int abs(int x); double sqrt(double x); void M etodo(); };
// M etodo com retorno do tipo int // M etodo com retorno do tipo double // M etodo sem retorno e sem par^ ametro
O retorno de um m etodo pode ser uma chamada a outro m etodo ou a um objeto. 2 O retorno de um m etodo n ao pode ser um array nem uma fun ca o, mas pode ser um ponteiro ou refer encia a um array ou fun ca o. Veja Ap endice H Vetores e matrizes arrays.
13.6
Quando declaramos um m etodo devemos incluir a lista de par ametros. Isto e, a lista de objetos que o m etodo receber a. Veremos nesta se ca o que os par ametros podem ser passados por c opia (Se ca o 13.6.1), refer encia (Se ca o 13.6.2), ou ponteiro (Se ca o 13.6.3). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
274
13.6.1
Neste caso o m etodo recebe como par ametro uma c opia do objeto. Note que como e criada mais lento porque precisa criar uma c opia, o objeto original n ao sofre nenhuma altera ca o. E uma c opia de cada objeto passado como par ametro. No exemplo a seguir, dentro de main(), o objeto int a n ao vai sofrer nenhuma altera ca o, pois o m etodo M() vai receber uma c opia de a, com nome x. Exemplo: class CNomeClasse { public: int M(int x); }; int CNomeClasse::M(int x) { return x = 5; } int main() { CNomeClasse obj; int a = 1; int b = obj.M(a); return 0; }
13.6.2
Uma refer encia e um apelido para um objeto. Veja no exemplo a seguir como criar uma refer encia. Exemplo: int x; // Cria objeto do tipo inteiro com nome x int& ref_x; // Cria uma refer^ encia para x ref_x = 5; // Usa a refer^ encia para armazenar o valor 5 em x Veremos descri ca o detalhada do uso de refer encias no Cap tulo 15 Ponteiros, refer encias e gerenciamento de mem oria. Como uma refer encia e um apelido para um objeto, quando o m etodo recebe como par ametro a refer encia, ele recebe o pr oprio objeto e n ao uma c opia. Note que a passagem de par ametro por refer encia e mais r apida, pois o m etodo tem acesso direto aos objetos (sem criar uma c opia destes). Observe ainda que o objeto passado pode sofrer altera co es dentro do m etodo. No exemplo a seguir, dentro de main(), o objeto a vai sofrer altera ca o, pois o m etodo M() vai receber o pr oprio a. Note que dentro de main() o nome do objeto e a, e dentro do m etodo M() o apelido de a e x. Exemplo: class CNomeClasse { public: int M(int& x); };
13.6. PARAMETROS DOS METODOS int CNomeClasse::M(int &x) { return x = 5; } int main() { CNomeClasse obj; int a = 1; int b = obj.M(a); return 0; } // Defini c~ ao do m etodo M()
275
13.6.3
Neste caso o m etodo recebe como par ametro um ponteiro para o objeto. Um ponteiro e um objeto que aponta para outro objeto, podendo ser usado para alterar os valores armazenados no objeto apontado. Veja no exemplo a seguir que dado um objeto x do tipo inteiro, podemos criar um ponteiro para x usando int* ptr_x = &x;. Observe que usamos o caracter * para indicar que estamos criando um ponteiro para um inteiro. O caracter & (e comercial) e usado para pegar o endere co de x e armazenar em ptr_x. Exemplo: int x; // Cria objeto do tipo inteiro com nome x int* ptr_x; // Cria ponteiro para inteiro ptr_x = &x; // Pega o endere co do objeto x e armazena em ptr Veremos descri ca o dos ponteiros no Cap tulo 15 Ponteiros, refer encias e gerenciamento de mem oria. No exemplo a seguir declaramos como par ametro um ponteiro com nome pb, que e utilizado dentro do m etodo M() para acessar o objeto. O objeto acessado pelo ponteiro pode sofrer altera co es. Exemplo: class CNomeClasse { public: int M(int *pb); // Declara c~ ao do m etodo M() }; int CNomeClasse::M(int* pb)// Defini c~ ao do m etodo M() { return *pb = 5; } int main() { CNomeClasse obj; int a = 1; int b = obj.M( &a ); // Chamada do m etodo M()(uso) return 0; // aqui a = 5, b = 5 } Note que a passagem por ponteiro e semelhante ` apassagem por refer encia no que tange ` a modica ca o do par ametro. Isto e, ambos modicam o objeto passado como par ametro. Veja na Listagem 13.1 exemplo ilustrando a passagem de par ametros. N ao se preocupe se n ao entender a parte que usa ponteiros; depois de ler o cap tulo de ponteiros, releia esse Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
276
exemplo. O programa inicia com a inclus ao da biblioteca <iostream>. Em seguida, cria a classe CTeste com quatro m etodos p ublicos, Soma_Valor(), Soma_Referencia(), Soma_Ponteiro() e Soma_ReferenciaPonteiro(). Na fun ca o main() criam-se duas vari aveis a e b, do tipo int. Os valores de a e b s ao mostrados na tela. Depois disso, cria-se um objeto do tipo CTeste, e os m etodos de CTeste s ao executados. No in cio da execu ca o de Soma_Valor(), criam-se as vari aveis x e y c opias de a e b. Assim, a modi ca o de x e y dentro de Soma_Valor() n ao altera os valores dos par ametros passados, no caso a e b denidos dentro de main(). Por m, as vari aveis a e b s ao passadas como par ametros dos outros tr es m etodos. Nestes tr es casos, os valores de a e b denidos dentro de main() s ao modicados. Listing 13.1: Passando par ametros por valor, refer encia e ponteiro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 # include < iostream > using std :: cout ; using std :: endl ; class CTeste { public : int Soma_Valor ( int , int ) ; int S o m a _ R e f e r e n c i a ( int & , int &) ; int S o m a _ P o n t e i r o ( int * , int *) ; int S o m a _ R e f e r e n c i a P o n t e i r o ( int *& , int *&) ; }; // D e f i n i c~ a o de um m e todo que recebe p a r ^ a m e t r o s por valor ( int ) int CTeste :: Soma_Valo r ( int x , int y ) { int soma = x + y ; x = 5; // In u til , usado apenas para m o s t r a r que a , b y = 7; // d e f i n i d o s dentro de main () n~ a o s~ ao alterados return soma ; } // D e f i n i c~ a o de um m e todo que recebe p a r ^ a m e t r o s por r e f e r ^ e n c i a ( int &) int CTeste :: S o m a _ R e f e r e n c i a ( int & x , int & y ) { int soma = x + y ; x = 55; y = 77; return soma ; } // D e f i n i c~ a o de um m e todo que recebe p a r ^ a m e t r o s por p o n t e i r o ( int *) int CTeste :: S o m a _ P o n t e i r o ( int *x , int * y ) { int soma = * x + * y ; * x = 555; * y = 777; return soma ; } // D e f i n i c~ a o de um m e todo que recebe p a r ^ a m e t r o s como // r e f e r ^ e n c i a para um p o n t e i r o ( int *&) int CTeste :: S o m a _ R e f e r e n c i a P o n t e i r o ( int *& x , int *& y ) { int soma = * x + * y ; * x = 5555; * y = 7777; return soma ; }
277
int main () { // Cria o b j e t o s a e b do tipo int int a = 1; int b = 2; cout << " a = " << a << " , b = " << b << endl ; // Cria objeto obj do tipo CTeste CTeste obj ; // Chama m e t o d o s do objeto obj cout << " Ap o s chamar Soma_Valor (a , b ) ; " << " soma = " << obj . Soma_Valor (a , b ) << " , a = " << a << " , b = " << b << endl ; cout << " Ap o s chamar S o m a _ R e f e r e n c i a (a , b ) ; " << " soma = " << obj . S o m a _ R e f e r e n c i a (a , b ) << " , a = " << a << " , b = " << b << endl ; cout << " Ap o s chamar S o m a _ P o n t e i r o (& a ,& b ) ; " << " soma = " << obj . S o m a _ P o n t e i r o (& a , & b ) << " , a = " << a << " , b = " << b << endl ;
p o n t e i r o s para a e b = &a; = &b; " Ap o s chamar S o m a _ R e f e r e n c i a P o n t e i r o ( pa , pb ) ; " " soma = " << obj . S o m a _ R e f e r e n c i a P o n t e i r o ( pa , pb ) " , a = " << a << " , b = " << b << endl ;
return 0; } a = 1 , b = Ap o s chamar Ap o s chamar Ap o s chamar Ap o s chamar 2 Soma_Valor (a , b ) ; soma = 3 , a = 1 , b = 2 S o m a _ R e f e r e n c i a (a , b ) ; soma = 3 , a = 1 , b = 2 S o m a _ P o n t e i r o (& a ,& b ) ; soma = 132 , a = 55 , b = 77 S o m a _ R e f e r e n c i a P o n t e i r o ( pa , pb ) ; soma = 1332 , a = 555 , b = 777
13.6.4
A utiliza ca o de par ametros predenidos consiste em atribuir valores iniciais aos par ametros de um m etodo. Assim, quando o m etodo e chamado sem par ametros, ser ao utilizados os par ametros predenidos. Veja o prot otipo. Note que se o par ametro pn n ao for passado, o m etodo vai assumir que pn tem o valor vn. Prot otipo: TipoRetorno NomeM etodo(Tipo p1 = v1, Tipo p2 = v2, ... ,Tipo pn = vn); No exemplo a seguir, o m etodo M() tem os par ametros a, b e c previamente inicializados com os valores 4, 7 e 9.3, respectivamente. Observe que o m etodo M() pode ser chamado de diferentes formas e que os par ametros que deixam de ser fornecidos s ao aqueles que est ao mais ` a direita. Exemplo: int CNomeClasse::M(int a = 4, int b = 7, float c = 9.3) { Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
278 return a + b + c; } int main() { // O m etodo M() pode CNomeClasse obj; obj.M(77, 5, 66.6); obj.M(33, 75); obj.M(67); obj.M(); return 0; }
ser chamado das seguintes formas: // // // // a a a a = = = = 77, 33, 67, 4, b b b b = = = = 5, 75, 7, 7, c c c c = = = = 66.6 9.3 9.3 9.3
Um par ametro predenido pode ser a chamada a um m etodo, veja o exemplo: Exemplo: int CNome::M1() { return 2; } int CNome::M2(int x, int y = CNome::M1(), int z = 3) { return x + y + z; } Par ametros predenidos podem ser acumulados em mais de uma declara ca o. No exemplo a seguir, o m etodo M2() foi declarado diversas vezes. Lembre-se que declara co es podem ser repetidas. Observe que a chamada a M2() sem par ametros funciona, pois considera as declara co es (2) e (3). Embora v alido, este procedimento deve ser evitado, porque as declara co es podem estar em arquivos diferentes. Exemplo: int M2(int x, int y, int z); // Declara c~ ao (1) int M2(int x, int y, int z = 3); // Declara c~ ao (2) int M2(int x = 1, int y = 2, int z); // Declara c~ ao (3) void Teste() { CNomeClasse obj; obj.M2(); // Equivale a obj.M2(1, 2, 3) } Note que se os tipos dos par ametros forem diferentes teremos sobrecarga de m etodos, a qual ser a discutida no Cap tulo 14 Sobrecarga de m etodos. Veremos a seguir os diferentes tipos de m etodos de uma classe.
13.7
M etodos normais
Os m etodos normais s ao declarados dentro da classe sem nenhum qualicador adicional, isto e, sem uso dos qualicadores inline, static, virtual ou const. Veja o prot otipo: Prot otipo: class CNome { // Declara ca o TipoRetorno NomeM etodo(par ametros); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
13.7. METODOS NORMAIS }; // Deni ca o TipoRetorno CNomeClasse::NomeM etodo(par ametros) {.. c odigo..} // Uso objeto.NomeM etodo(par ametros);
279
Veremos o uso dos m etodos normais mediante a implementa c ao da classe CPessoa. Veja na Figura 13.1 o diagrama UML da classe CPessoa e na Listagem 13.2 sua implementa ca o. Neste exemplo, usamos os tipos predenidos de C++, os tipos do usu ario e os tipos da biblioteca-padr ao de C++ (<string> e <vector>).
CPessoa
+nome: string +matricula: string +Entrada(): void +Saida(): void
Figura 13.1: A classe CPessoa. O programa inicia pela inclus ao das bibliotecas que ser ao utilizadas e pela libera ca o do uso do namespace std. Em seguida, dene a classe CPessoa, com atributos nome, matricula e dois m etodos, um para Entrada() e outro para Saida() de dados. O m etodo Entrada() pede para o usu ario a entrada dos atributos do objeto, o nome da pessoa e seu n umero de matricula. O m etodo Saida() envia para a tela o nome e matricula do objeto. Na fun ca o main(), criamos um objeto do tipo CPessoa, com nome professor e solicitamos seus dados. Em seguida, criamos um <vector> da STL (Se ca o 9.4.2) para armazenar dois objetos do tipo CPessoa. Dentro do primeiro for(), para cada aluno i, executamos o m etodo Entrada(), ou seja, lemos os dados do aluno[i]. No segundo for(), cada aluno[i] envia para a tela seus atributos, chamando o m etodo Saida(). Note no exemplo da Listagem 13.2 que os dados do professor s ao lidos diretamente usando getline (cin, professor.nome);, isto s o e poss vel porque os atributos nome e matricula s ao p ublicos. Listing 13.2: Classe com atributo e m etodo normal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # include < iostream > # include < string > # include < vector > using namespace std ; /* * A classe C P e s s o a r e p r e s e n t a uma pessoa ( um aluno ou um p r o f e s s o r ) de uma u n i v e r s i d a d e . Tem um nome , uma matr cula , e m etodos b a s i c o s para e n t r a d a e sa da de dados . */ class CPessoa { public : std :: string nome ; // A t r i b u t o s n o r m a i s std :: string matricula ; void Entrada () ; // M e todo normal void Saida () const ; // M e todo const };
280
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
// S o l i c i t a a t r i b u t o s do objeto void CPessoa :: Entrada () { cout << " Entre com o nome do aluno : " ; getline ( cin , nome ) ; cout << " Entre com a matr cula do aluno : " ; getline ( cin , matricula ) ; } // Mostra void { cout << << } a t r i b u t o s do objeto CPessoa :: Saida () const " Nome do aluno : " << nome " \ nMatr cul a : " << matricula << endl ;
int main () { string linha = " \n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " ; const int n u m e r o A l u n o s = 2; // Cria CPessoa cout << getline cout << getline um objeto do tipo C P e s s o a com nome p r o f e s s o r professor ; " Entre com o nome do professor : " ; ( cin , professor . nome ) ; " Entre com a matr cula do professor : " ; ( cin , professor . matricula ) ;
// Cria um vetor de o b j e t o s do tipo C P e s s o a com nome aluno vector < CPessoa > aluno ( n u m e r o A l u n o s ) ; for ( int contador = 0; contador < n u m e r o A l u n o s ; contador ++) { cout << " \ nAluno " << contador << endl ; aluno [ contador ]. Entrada () ; } cout << linha << " \ nRELA C~ A O DE PROFESSOR E S E ALUNOS : " << linha << " \ nNome do professor : " << professor . nome << " \ nMatr cul a : " << professor . matricula << endl ; for ( int contador = 0; contador < n u m e r o A l u n o s ; contador ++) { cout << linha << " \ nAluno " << contador << endl ; aluno [ contador ]. Saida () ; } cout << linha ; return 0; } Entre com o nome do professor : Andre Duarte Bueno Entre com a matr cula do professor : 123 Aluno 0 Entre com o nome do aluno : Giovanni Colonese Entre com a matr cula do aluno : 324 Aluno 1 Entre com o nome do aluno : Alan Galante Entre com a matr cula do aluno : 984 ------------------------------------------------------RELA C~ A O DE PROFESSOR E S E ALUNOS : -------------------------------------------------------
281
Este e um de seus primeiros programas orientados a objeto. Simples, n ao e? Voc e declarou uma classe: class CPessoa... Deniu os m etodos da classe: void CPessoa::Entrada(){...} Criou objetos da sua classe: CPessoa professor; Usou o objeto: cout < < "Nome do professor: " < < professor.nome < < "\n";
13.8
Se um m etodo da classe n ao altera o estado e os atributos do objeto, ele deve ser declarado como const. Observe no prot otipo a seguir que a palavra-chave const e colocada no nal da declara ca o: Prot otipo: class CNome { // Declara ca o TipoRetorno NomeM etodo(par ametros) const; }; // Deni ca o TipoRetorno NomeClasse::NomeM etodo(par ametros) const {.. c odigo..} // Uso objeto.NomeM etodo(par ametros); A declara ca o const instrui o compilador de que o m etodo n ao pode alterar o estado do objeto. Observe no pr oximo exemplo que a palavra-chave const e colocada antes do (;) ponto-e-v rgula que naliza a declara ca o. Exemplo: class CNomeClasse { int valor; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
282 int Valor() const; int MudaValor(); }; int CNomeClasse::Valor() const { return valor; } void CNomeClasse::Valor(int v) { return valor = v; }
13.8. METODOS CONSTANTES CONST // Declara c~ ao de m etodo const // Declara c~ ao de m etodo normal // Defini c~ ao de m etodo const // Defini c~ ao de m etodo normal // muda atributo valor
Se dentro de um m etodo const algum atributo for modicado, ou um m etodo n ao const for chamado, o compilador acusar a o erro. Exemplo: int CNomeClasse::Valor() const // Outra defini c~ ao para Valor { ++valor; // Erro, n~ ao pode mudar atributo Valor(5); // Erro, n~ ao pode chamar m etodo normal return valor; } Se um m etodo qualquer receber como par ametro um objeto const, esse m etodo s o poder a acessar os m etodos const desse objeto, ou seja, n ao poder a acessar os m etodos que modicam o estado do objeto. Exemplo: void f(const CNomeClasse& obj) { cout < < obj.Valor(); // ok, o m etodo Valor() e const obj.MudaValor(); // Erro, n~ ao pode chamar m etodo normal } Releia a Listagem 13.2, observe que o m etodo Saida() e const. Veja na Listagem 13.3 um exemplo de uso de par ametros e m etodos const. Neste exemplo criamos uma classe CNumeroRandomico, a qual e usada para fornecer n umeros rand omicos. O atributo random armazena o n umero rand omico. O m etodo Random() retorna o n umero rand omico. O m etodo Update() gera um novo n umero rand omico. Como Update() altera o estado do objeto, isto e, altera o valor de random, ele n ao pode ser declarado como const. A fun ca o main() solicita a entrada de uma semente e cria um objeto CNumeroRandomico, em seguida chama Inicializa() passando a semente. Dentro do for, chama o m etodo Update(), que gera um novo n umero rand omico e ent ao chama Random(). Esse exemplo mostra o uso de duas fun co es da biblioteca-padr ao de C, a srand(), para informar o valor da semente e a rand(), para gerar um novo n umero rand omico. Nota: veremos, no Ap endice K Arquivos de cabe calho, os arquivos de cabe calho padr ao de C/C++ e uma breve descri ca o das fun co es mais utilizadas. Listing 13.3: Classe com m etodo const.
1 2 3 4 5 # include < iostream > # include < iomanip > # include < cstdlib > using namespace std ; // F u n c~ o e s srand () e rand ()
283
// A t r i b u t o s n o r m a i s // n u mero r a n d o m i c o // s e m e n t e g e r a d o r a i n i c i a l // M etodos // M e todo de i n i c i a l i z a c~ ao void Inicializa ( const int _semente = 1) ; // M e t o d o s const double Random () const ; // R e t o r n a n u mero r a n d o m i c o int Semente () const ; // R e t o r n a a s e m e n t e void Update () ; // M e todo normal
}; // M e todo de i n i c i a l i z a c~ ao void C N u m e r o R a n d o m i c o :: Inicializa ( const int _semente ) { semente = _semente ; random = 0; srand ( semente ) ; } double C N u m e r o R a n d o m i c o :: Random () { return random ; } int C N u m e r o R a n d o m i c o :: Semente () { return semente ; } const
const
// Update gera um novo n u mero r a n d ^ o m i c o e a r m a z e n a em random void C N u m e r o R a n d o m i c o :: Update () { random = rand () ; } int main () { cout << " \ nEntre com uma semente : " ; int semente ; cin >> semente ; cin . get () ; C N u m e r o R a n d o m i c o gerador ; gerador . Inicializa ( semente ) ; cout << " Valor da semente : " << gerador . Semente () << " Valor inicial : " << gerador . Random () << endl ; for ( int i = 0; i < 5; i ++) { gerador . Update () ; cout << " gerador . Random ( " << setw (3) << i << " ) = " << setw (15) << gerador . Random () << endl ; } return 0; } bash -3.00 $ ./ a . out Entre com uma semente : 4 Valor da semente : 4 Valor inicial : 0 gerador . Random ( 0) = 1.96808 e +09 gerador . Random ( 1) = 2.87724 e +08 gerador . Random ( 2) = 4.10622 e +08 gerador . Random ( 3) = 5.58519 e +08
284
gerador . Random ( 4) = 4.60165 e +08
Dica: a biblioteca Matpack, descrita no Cap tulo ?? Biblioteca Matpack, inclui diversas classes utilit arias para gera ca o de n umeros rand omicos.
13.9
Vimos que existem dois tipos de atributos: os atributos de objeto (Se ca o 12.2) e de classe (Se ca o 12.3). Se voc e montar um m etodo que s o opera sobre os atributos est aticos da classe, pode declar a-lo como sendo um m etodo est atico. Adicionalmente, um m etodo est atico e p ublico pode ser acessado sem um objeto da classe, basta colocar o nome da classe, o operador de resolu ca o de escopo (::) e o nome do m etodo. Veja a seguir o prot otipo: Prot otipo: class CNome { // Declara ca o static TipoRetorno NomeM etodo(par ametros); }; // Deni ca o TipoRetorno NomeClasse::NomeM etodo(par ametros) {.. c odigo..} // Uso NomeClasse::NomeM etodoEst atico(); Veja na Listagem 13.4 um exemplo de classe com atributo e m etodo est atico. Este exemplo e um aperfei coamento da Listagem 13.2. Como inova ca o temos o atributo iaa, e o n umero de alunos e solicitado ao usu ario. Tamb em temos um atributo est atico, numeroAlunos, utilizado para armazenar o total de alunos (e professores) que foram criados. O m etodo est atico NumeroAlunos() retorna o n umero de alunos e pode ser acessado sem um objeto. Listing 13.4: Classe com atributo e m etodo est atico.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # include < iostream > # include < string > # include < vector > using namespace std ; /* A classe C P e s s o a r e p r e s e n t a uma pessoa ( um aluno ou um p r o f e s s o r ) de uma u n i v e r s i d a d e . Tem um nome , uma matricula , um iaa , e m etodos b a s i c o s para e n t r a d a e sa da de dados . */ class CPessoa { public : std :: string nome ; std :: string matricula ; float iaa ; private : static int n u m e r o A l u n o s ; public : void Entrada () ; void Saida () const ; // Um m e todo e s t a t i c o s o pode a c e s s a r e a l t e r a r a t r i b u t o s e s t aticos static int N u m e r o A l u n o s () ;
285
int main () { string linha = " \n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " ; cout << " \ nEntre com o n u mero de alunos da disciplin a ( ex : 3) : " ; int n u m e r o A l u n o s ; cin >> n u m e r o A l u n o s ; cin . get () ; CPessoa professor ; cout << " Entre com o nome do professor : " ; getline ( cin , professor . nome ) ; cout << " Entre com a matr cula do professor : " ; getline ( cin , professor . matricula ) ; vector < CPessoa > aluno ( n u m e r o A l u n o s ) ; for ( int contador = 0; contador < aluno . size () ; contador ++) { cout << linha << " \ nAluno " << contador << endl ; aluno [ contador ]. Entrada () ; } cout << linha << " \ nRELA C~ A O DE PROFESSORE S E ALUNOS : " << linha << " \ nNome do professor : " << professor . nome << " \ nMatr cula : " << professor . matricula << " \ n " ; for ( int contador = 0; contador < aluno . size () ; contador ++) { cout << linha << " \ nAluno " << contador << endl ; aluno [ contador ]. Saida () ; } // Usa m e todo e s t a t i c o sem ter um objeto cout << " \ nN u mero alunos = " << CPessoa :: N u m e r o A l u n o s () << endl ; return 0;
286
85 }
Entre com o n u mero de alunos da disciplina ( ex : 3) : 3 Entre com o nome do professor : Andr e Duarte Bueno Entre com a matr cula do professor : 654 ---------------------------------------------------------Aluno 0 Entre com o nome : Tiago Schaewer Entre com a matr cula : 548 Entre com o IAA : 9.8 ---------------------------------------------------------Aluno 1 Entre com o nome : Alan Galante Entre com a matr cula : 987 Entre com o IAA : 9 ---------------------------------------------------------Aluno 2 Entre com o nome : Giovanni Colonese Entre com a matr cula : 475 Entre com o IAA : 9.3 ---------------------------------------------------------RELA C~ A O DE PROFESSOR E S E ALUNOS : ---------------------------------------------------------Nome do professor : Andr e Duarte Bueno Matr cula : 654 ---------------------------------------------------------Aluno 0 Nome : Tiago Schaewer Matr cula : 548 IAA : 9.8 ---------------------------------------------------------Aluno 1 Nome : Alan Galante Matr cula : 987 IAA : 9 ---------------------------------------------------------Aluno 2 Nome : Giovanni Colonese Matr cula : 475 IAA : 9.3 N u mero alunos =3
Dica: substitua o uso de atributos est aticos por fun co es est aticas que retornam uma refer encia para objetos est aticos. Veja o exemplo: Exemplo: const double& Pi() { static const double pi = 3.141516; return pi; }
13.10
Quando voc e dene um m etodo, o compilador reserva um espa co de mem oria que e ocupado pelo c odigo do m etodo. Quando voc e chama um m etodo com par ametros, o compilador passa os par ametros para o m etodo a ser executado, mudando a linha de execu ca o do programa (P1). Depois de executado o m etodo, o programa retorna para o local onde estava (P2) e executa a instru ca o seguinte ` a chamada do m etodo. Observe que existem dois passos intermedi arios, ir at e onde o m etodo est a e depois retornar, o que consome tempo de processamento. A Figura 13.2 ilustra o processo considerando a seq u encia com m etodo normal e inline. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
287
Observe que na seq u encia normal a fun ca o main() faz x = 3; e cria o objeto obj, do tipo C. Em seguida, o m etodo M() e chamado (P1), dentro do m etodo executa a seq u encia int z = x + 3; e faz z*z. Finalizado o m etodo M(), o mesmo retorna o valor de z*z (P2) e armazena em y. O valor de y e enviado para a tela e, ent ao, o programa e encerrado. Na seq u encia com m etodo inline, o c odigo de C::M() e copiado para dentro de main(), eliminando os passos intermedi arios (P1) e (P2).
// Declarao da classe class C { // Declara mtodo inline inline int M(int x); }; // Define mtodo M() int C::M(int x) { int z = x + 3; return z * z; } // Seqncia Normal #include "C.h" int main() { int x = 3; (P1) C obj; int y = obj.M(x); cout << "y = "<< y << endl; return 0; } // Seqncia com mtodo inline #include "C.h" int main() { int x = 3; Trecho de C obj; cdigo int z = x + 3; copiado de int y = z * z; C::M() cout << "y = "<< y << endl; return 0; }
(P2)
Figura 13.2: Como cam os m etodos inline. Veja a seguir algumas caracter sticas dos m etodos inline: M etodos inline devem ser m etodos pequenos, por isso o termo em linha. S ao m etodos que s ao executados mais rapidamente. Uma especica ca o inline e uma sugest ao para que seja feita a sua substitui ca o e n ao a sua chamada; o compilador e que decide. Se o m etodo for grande, o compilador ir a desconsiderar o especicador inline. Um m etodo inline e ideal para retorno de valores. Um m etodo denido dentro da deni ca o da classe e inline por default. Veja linhas 20-24 da Listagem 13.5. A utiliza ca o de m etodos inline torna o programa mais r apido, por em maior. Coloque o c odigo de todos os m etodos inline dentro da deni ca o da classe. Um m etodo recursivo (que chama a si mesmo) n ao pode ser inline. Isto ocorre porque o m etodo teria de ser substitu do onde e chamado, e, como e recursivo, o n umero de substitui co es e indenido ou implica na gera ca o de c odigos muito extensos. Veremos na Se ca o 28.1.2 fun co es expandidas em tempo de compila ca o, uma maneira de construir m etodos recursivos em tempo de compila ca o. Altera co es em um m etodo inline implicam na necessidade de se recompilar todas as bibliotecas que fa cam uso deste, ou seja, utilize inline com cuidado. Em resumo, os m etodos inline foram criados para otimizar o programa. Quando um m etodo inline e chamado, o compilador, em vez de chamar o m etodo, coloca uma c opia deste onde uma situa ele est a sendo chamado. E ca o semelhante ` a que ocorria com as antigas macros de C, com a vantagem de fazer verica ca o de tipo. Veja a seguir um exemplo: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
288 Exemplo: class CRetangulo { int base, altura; public: // inline impl cito, pois o int Base() const { void Base(int _base) { int Altura() const { void Altura(int _altura) { int Perimetro() const { // inline expl cito, uso da inline int Area() { };
m etodo e definido dentro da classe return base; }; base = _base; }; return altura; }; altura = _altura; }; return base*base + altura*altura; }; palavra-chave inline return base*altura; };
Nota: no exemplo anterior usamos m etodos com mesmo nome, mas n umero de par ametros diferente. Veja o Cap tulo 14 Sobrecarga de m etodos. Veja na Figura 13.3 o diagrama UML da classe CPonto, cujo c odigo para implementa ca o e apresentado nas listagens 13.5 e 13.6. Observe a utiliza ca o de m etodos inline para acesso aos atributos da classe e o uso de m etodos const. A classe CPonto ser a utilizada na Listagem 13.7.
A classe CPonto inclui dois atributos normais do tipo inteiro e um atributo de classe.
CPonto
+x: int +y: int +contador: static int = 0 +Desenha(): virtual void
289
Na Listagem 13.7 um objeto do tipo CPonto e criado, CPonto ponto;, e utilizado ponto.Set(x,y); ponto.Desenha();. Quando o bloco e encerrado o objeto ponto sai de escopo e e destru do. Observe que, depois de destruir o objeto ponto, utilizamos o m etodo Contador(). Isto e poss vel porque o m etodo e p ublico e est atico. Listing 13.7: Usando m etodos e atributos de uma classe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # include < iostream > # include " CPonto . h " using namespace std ; // E x e m p l o de c r i a c~ a o e uso de um objeto do tipo CPonto int main () { int x = 5; int y = 4; { CPonto p1 ; // Cria objeto do tipo CPonto com nome p1 p1 . Set (x , y ) ; // Chama m e todo Set () do objeto p1 p1 . Desenha () ; // Chama m e todo D e s e n h a () do objeto p1 CPonto p2 ; p2 . Set ( p1 ) ; p2 . Desenha () ; // Cria objeto do tipo CPonto com nome p2 // Chama m e todo Set () do objeto p2 // Chama m e todo D e s e n h a () do objeto p2
290
22 23 24 25 26 27 28 29 p3 . Set ( x , y ) ; p3 . Desenha () ; }
// Chama m e todo e s t a t i c o e p u blico , o b s e r v e que n~ a o p r e c i s a de um objeto cout << " Contador = " << CPonto :: Contador () << endl ; return 0; } CPonto : Coordenada x = 5 CPonto : Coordenada y = 4 CPonto : Coordenada x = 5 CPonto : Coordenada y = 4 CPonto : Coordenada x = 10 CPonto : Coordenada y = 8 Contador = 0
13.11
Inclu mos nesta se ca o refer encias para se co es que incluem o uso avan cado de m etodos em C++. Os m etodos n ao virtuais foram apresentados neste cap tulo. Veremos outras caracter sticas dos m etodos n ao virtuais na Se ca o 19.1. Veremos os m etodos virtuais, na Se ca o 19.2, e como implementar o polimorsmo, na Se ca o 19.3. Veremos os m etodos virtuais puros na Se ca o 19.4. Veremos os m etodos virtuais sobrecarregados na Se ca o 19.5. Apresentaremos um exemplo cobrindo o uso pr atico de polimorsmo na Se ca o 19.6.
13.12
Os m etodos p ublicos formam a interface da classe e devem ter nomes claros e uniformes (veja Tabela 8.2). Se um m etodo manipula preferencialmente os atributos de um objeto, ele provavelmente e um m etodo desse objeto. Em C++, todos os m etodos precisam de uma declara ca o, a qual auxilia o compilador a encontrar erros. Objetos grandes devem ser passados por refer encia ou por ponteiros. Evite utilizar par ametros de m etodos com nome igual ao de outros objetos para evitar ambig uidades. Analise os par ametros dos m etodos. Se estes n ao forem alterados, dever ao ser declarados como const. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
291
O uso de void como par ametro signica que o m etodo n ao recebe nenhum argumento. Exemplo: // Declarando uma fun c~ ao sem retorno e sem par^ ametro void fun c~ ao(void);// C void fun c~ ao(); // C++ Seguran ca se voc e quer ter certeza de que o par ametro n ao ser a alterado, deve pass a-lo como refer encia constante. Veja o exemplo a seguir. O especicador const informa que o objeto e constante e n ao pode ser alterado dentro do m etodo. Deste modo, o m etodo pode acessar o objeto, mas n ao pode modic a-lo. Exemplo: NomeM etodo(const Tipo& obj); Desempenho par ametros passados por refer encia aumentam a eci encia, pois os valores n ao s ao copiados. Voc e pode passar informa co es de uma classe para outra ou para objetos por meio de atributos est aticos da classe. Um objeto e criado por c opia quando: um par 1. E ametro de um m etodo. um retorno de um m 2. E etodo. lan 3. E cado como uma exce ca o (veja Cap tulo 26 Exce co es). Use inline somente quando houver ganho efetivo de desempenho. M etodos inline devem ter exatamente a mesma deni ca o em todos os arquivos. 2 Se voc e criar um ponteiro para uma fun ca o inline, o compilador criar a uma c opia n ao inline da fun ca o, e o ponteiro apontar a para esta c opia. 2 Na linkagem, os m etodos inline devem estar acess veis a todas as unidades de tradu ca o. 2 A lista de exce co es que um m etodo pode lan car n ao faz parte de sua assinatura. 2 Uma fun ca o friend denida dentro de uma classe e uma fun ca o inline impl cita. 2 Um m etodo est atico (static) n ao recebe um ponteiro this e, portanto, n ao pode ser utilizado para acessar os atributos e m etodos da classe. 2 Devo usar m etodos com par ametros predenidos ou sobrecarga de operador? De modo geral, usamos sobrecarga quando os par ametros s ao complexos (evitando a c opia desnecess aria dos par ametros). Se os par ametros s ao simples e o c odigo e complexo, prera par ametros predenidos, assim, o c odigo e escrito uma u nica vez [Lischner, 2003]. 2 Na chamada a uma fun ca o ou m etodo: i) primeiro e feita uma pesquisa pelos nomes, isto e, procura-se por m etodos com aquele nome; ii) em seguida e vericada a sobrecarga, isto e, qual m etodo atende melhor a assinatura do m etodo chamado; iii) nalmente, e vericada a acessibilidade. Na pr atica isso signica que um m etodo que tem uma assinatura mais conhecidente nem sempre e chamado, pois a sobrecarga e vericada antes. Veja Se ca o 14.3.1. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
292
3 Outro aspecto interessante, relatado por [Sutter, 2006], e que a substitui ca o do c odigo dos m etodos inline pode ser feita a qualquer tempo, ou seja, na compila ca o, na linkagem, na instala ca o e at e na execu ca o. Tudo depende do compilador e de op co es de otimiza ca o. 3 Lembre-se que o uso de inline n ao garante que o m etodo/fun ca o seja efetivamente inline. Na pr atica, o compilador pode colocar um m etodo como sendo inline em uma parte do c odigo e n ao inline em outra parte. A decis ao e sempre do compilador, e n ao podemos fazer nenhuma suposi ca o sobre o que ser a feito. 3 Para ter maior robustez no seu c odigo, deixe os m etodos virtuais como privados ou protegidos. Monte a interface com m etodos normais. Veja Se ca o 11.5.3. Esta t ecnica e conhecida como NVI NonVirtual Interface [Sutter, 2006].
13.13
Neste cap tulo vimos o prot otipo para declarar, denir e utilizar os m etodos de uma classe. Vimos em detalhes como funciona a declara ca o a deni ca o e o retorno dos m etodos. Aprendemos que o retorno 0 ou EXIT SUCESS indica sucesso e EXIT FAILURE ou != 0 indica fracasso. Aprendemos a utilizar os diferentes tipos de passagem de par ametros (c opia, refer encia, ponteiro). Entendemos o uso dos par ametros predenidos. Depois aprendemos a declarar e implementar os m etodos normais, os m etodos constantes, os m etodos est aticos e os m etodos em linha. Vimos que os m etodos est aticos s ao criados para manipular os atributos est aticos (de classe). Lembre-se que um atributo static faz parte da classe e n ao do objeto, sendo compartilhado como uma vari por todos os objetos. E avel global para os objetos daquela classe. Observe que a necessidade de atributos static e bastante real. Nota: os m etodos construtores ser ao apresentados no Cap tulo 16 M etodos construtores e destrutores. Veremos o uso avan cado da fun ca o main() e a entrada na linha de comando na Se ca o E.1 e fun co es recursivas na Se ca o E.3.
13.14
Exerc cios
1. Modique a Listagem 13.1, acrescentando um m etodo que recebe par ametros por c opia, refer encia, ponteiro e refer encia de ponteiro. 2. Monte um exemplo que use par ametros predenidos (Se ca o 13.6.4). 3. Monte uma classe CTriangulo que tenha um m etodo normal, um m etodo const, um m etodo static e um m etodo inline. 4. Reveja o exemplo da Listagem 13.1, prestando aten ca o na forma como os m etodos s ao declarados, denidos e usados. 5. Modique a Listagem 13.2, deixando os atributos nome e matr cula como privados. 6. Modique a Listagem 13.4. Crie duas classes, uma para o professor e outra para os alunos. 7. 2 Modique a Listagem 13.3 acrescentando sobrecarga para o operator(), isto e, substitua Random() pelo operator(). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
293
8. Implemente o exemplo da classe CRetangulo da Se ca o 13.10. Que tal criar as classes CQuadrado, CCirculo, CElipse? Coloque os atributos da Listagem 13.2 como private: e, em seguida, veja o que acontece na compila ca o. Modique a fun ca o main() de forma que o exemplo funcione mesmo com os atributos sendo privados.
294
Cap tulo 14
Sobrecarga de M etodos
Neste cap tulo apresentaremos a sobrecarga de m etodos, ou seja, a utiliza ca o de m etodos com o mesmo nome mas com n umero ou tipo de par ametros diferentes. Veremos o que e a sobrecarga de m etodos (Se ca o 14.1) e como implement a-la (Se ca o 14.2). Na Se ca o Sobrecarga de m etodos uso avan cado (Se ca o 14.3) veremos a rela c ao entre acessibilidade e visibilidade (Se ca o 14.3.1). Finalmente, veremos algumas senten cas para sobrecarga de m etodos (Se ca o 14.4).
14.1
Sobrecarga de m etodos se refere ` a utiliza ca o de m etodos com o mesmo nome, mas com tipos ou n umero de par ametros diferentes. Veja o prot otipo a seguir. Observe que a ordem dos par ametros e importante. De modo geral, como os m etodos sobrecarregados t em o mesmo nome, devem ser utilizados para realizar tarefas semelhantes. Prot otipo: Retorno Retorno Retorno ... Retorno M etodo(Tipo1 p1); M etodo(Tipo1 p1, Tipo2 p2); M etodo(Tipo1 p1, Tipo2 p2, Tipo3 p3); M etodo(Tipo1 p1, Tipo2 p2, Tipo3 p3, ...,TipoN pn);
Observe que, como usaremos um mesmo nome para todos os m etodos que realizam coisas semelhantes, e muito importante escolher com cuidado o nome do m etodo. Adicionalmente, o nome deve indicar de forma clara o que vai ser realizado.
14.2
O exemplo a seguir declara m etodos com o mesmo nome, m etodos sobrecarregados. Exemplo: void M etodo(int x, int y); // Declara c~ ao (1)- par^ ametros int, int void M etodo(float x, float y); // Declara c~ ao (2)par^ ametros float, float void M etodo(int x, float y); // Declara c~ ao (3)par^ ametros int, float 295
296
O exemplo a seguir usa o m etodo acima declarado. O compilador identica que xx e yy s ao do tipo int e chama o primeiro m etodo declarado, ou seja, o compilador reconhece qual m etodo voc e quer acessar, vericando o tipo e o n umero de par ametros. Exemplo: int xx = 3; int yy = 4; M etodo( xx , yy );
Observe que mudar o nome dos par ametros n ao e uma sobrecarga; o compilador diferencia o tipo, e n ao o nome. No exemplo a seguir ocorre um erro na compila ca o do m etodo, pois este tem como par ametros dois inteiros, repetindo a declara c ao (1) void M etodo(int x,int y);. Exemplo int M etodo(int z, int r); // Declara c~ ao (4)- Erro repete (1)
Enm, voc e deve estar atento ` as convers oes de tipo quando declara m etodos sobrecarregados. Tome os seguintes cuidados: O tipo e a refer encia para o tipo. void M etodo(int a); void M etodo(int & a); // Erro, redeclara c~ ao
Somente a diferencia ca o do nome dos par ametros n ao e sobrecarga. void M etodo(int a, int b); void M etodo(int c, int d); // Erro, redeclara c~ ao
Um m etodo com par ametros predenidos e uma sobrecarga: void M etodo(int a, int b, int c = 1); como se voc E e criasse os m etodos seguintes: void M etodo(int a, int b, int c); void M etodo(int a, int b); Na Se ca o 13.3, declara ca o de um m etodo, montamos uma classe CSoma com dois m etodos, SomaInt() e SomaFloat(). Veja a seguir como a classe CSoma pode car considerando-se o uso de m etodos sobrecarregados. A grande vantagem e o uso do mesmo nome, Soma(), pois isso facilita a memoriza ca o dos objetos e suas funcionalidades. Exemplo: // Arquivo CSoma.h class CSoma { public: // Declara c~ ao do m etodo Soma, par^ ametro do tipo int, sem nome int Soma( int , int ); // Declara c~ ao do m etodo Soma, par^ ametro do tipo float, com nomes a e b float Soma( float a, float b ); }; Reveja a listagem 13.5, observe que o m etodo Set() e sobrecarregado. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
297
14.3
14.3.1
Quando um m etodo e chamado, a seq u encia que envolve a deni ca o de qual m etodo vai ser executado passa por tr es etapas: 1. O compilador pesquisa por m etodos com mesmo nome e verica seu escopo, montando uma lista com os poss veis candidatos. Note que m etodos privados e protegidos far ao parte desta lista. 2. Em seguida o compilador verica a presen ca de sobrecarga e a assinatura dos m etodos. O objetivo e identicar qual m etodo se encaixa melhor (tem maior correspond encia), seguindo a seguinte ordem: (a) A assinatura do m etodo e totalmente coincidente. necess (b) E ario realizar promo co es integrais (exemplo: convers ao de um n umero unsigned int em int). necess (c) E ario usar convers oes-padr ao de C++. necess (d) E ario usar convers oes denidas pelo usu ario (veja Cap tulo 25 Convers oes). 3. O terceiro passo do compilador e fazer a verica ca o de acesso (public, protected e private). Um estudo detalhado dessa seq u encia deixa claro que nem sempre o m etodo com maior correspond encia e chamado, pois a verica ca o da acessibilidade eou ltimo item a ser considerado. Ou seja, se um m etodo com maior correspond encia for inacess vel, ent ao um m etodo com menor correspond encia ser a chamado. Se o que temos n ao e uma fun ca o, e um ponteiro, um template ou um objeto, ent ao a resolu ca o da chamada segue a seguinte ordem: 1. m etodo/fun ca o f(), 2. um ponteiro para m etodo/fun ca o f(), 3. uma fun ca o template f(), 4. a constru ca o de um objeto do tipo f(), ou a chamada do operador() de um objeto f(). Nota: para maiores detalhes consulte [Sutter, 2006, Meyers, 2005]. As convers oes ser ao discutidas no Cap tulo 25 Convers oes.
14.4
Os valores de retorno n ao s ao avaliados em uma sobrecarga. Um m etodo com par ametros predenidos e uma sobrecarga. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
298
Se o m etodo sobrecarregado recebe int, fa ca uma an alise das poss veis convers oes autom aticas, ou seja, se for passado um tipo integral diferente de int, analise como este vai ser tratado. 2 Um conjunto de m etodos/fun co es sobrecarregados que executam os mesmos procedimentos, mas sobre tipos diferentes, podem ser substitu dos por m etodos/fun co es gabaritos. Veja Cap tulo 27 Templates (ou gabaritos).
14.5
Neste cap tulo aprendemos o que e e como implementar a sobrecarga de m etodos em C++. A grande vantagem da sobrecarga e o uso do mesmo nome para fun co es/m etodos que ir ao receber como par ametros objetos de tipos diferentes. Vimos que a sobrecarga ocorre quando os par ametros t em tipo diferente ou n umero de par ametros diferente. Em alguns casos a sobrecarga pode apresentar ambig uidade; normalmente isto ocorre em fun ca o das convers oes impl citas de tipo.
14.6
Exerc cios
1. Fa ca as modica co es necess arias para que o programa da listagem 13.1 tenha todos os m etodos com o mesmo nome (e funcione). 2. Implemente a classe CRetangulo descrita na Se ca o 13.10. N ao se esque ca de fazer o diagrama de classes no umbrello. Inclua o uso de m etodos sobrecarregados.
Cap tulo 15
15.1
Ponteiros s ao objetos cujo conte udo e o endere co de outros objetos. Para declarar ponteiros, precedemos o nome do objeto pelo asterisco *, ou seja, para um tipo T, T* e um ponteiro. Uma refer encia pode ser encarada como um outro nome para um objeto, um apelido. Para declararmos uma refer encia colocamos Tipo& nomeDaRefer^ encia. Note que toda refer encia precisa ser inicializada na sua declara ca o. O operador &, como em &objeto, retorna o endere co do objeto, uma refer encia para o objeto. Veja o prot otipo a seguir. Observe que e boa pr atica de programa ca o inicializar todo ponteiro com o valor 0 (zero) ou com NULL. Note ainda que algo deve ser do tipo Tipo: 299
300
15.2. PONTEIROS
Ponteiro
Objeto
&obj ptr
3 obj
int main() { int obj = 3; int* ptr; // (P1) ptr = &obj; // (P2) cout << obj << endl; cout << *ptr << endl; // P(3) return 0; }
Figura 15.1: Ilustra ca o da cria ca o e uso de ponteiros. Prot otipo: Tipo * ponteiro = 0; // Cria o ponteiro (1) Tipo objeto; // Cria o objeto ponteiro = &objeto; // Coloca o endere co do objeto no ponteiro (2) *ponteiro = algo; // Usa o ponteiro armazenando algo no objeto (3) // Cria uma refer encia para o objeto Tipo & nomeRefer encia = &objeto;
15.2
Ponteiros
O procedimento de cria ca o e uso de um ponteiro tem tr es etapas (veja Figura 15.1). Primeiro, cria-se o ponteiro (P1). Em seguida, coloca-se no ponteiro o endere co do objeto para o qual ele vai apontar, usando o operador endere co de & (P2). Finalmente, utiliza-se o ponteiro, usando o operador desreferencia * (P3). Na pr atica, os ponteiros s ao utilizados para substituir os objetos originais. Sua vantagem est a associada ao seu pequeno tamanho. Assim, passar um ponteiro como par ametro de um m etodo e mais r apido e econ omico que passar uma c opia do objeto (veja Se ca o 13.6). Vamos explicar o funcionamento e a utiliza ca o dos ponteiros por meio de um exemplo hipot etico. Digamos que o sistema de armazenamento de objetos em um programa funcione como o correio. A entrega de um pacote precisa do endere co de destino e de um carteiro, isto e, o carteiro deve pegar um valor e armazen a-lo no objeto. Para realizar este trabalho, o carteiro precisa do valor (ou seja, um pacote para entregar) e do endere co do objeto onde o valor deve ser armazenado (endere co de entrega). Quando voc e faz x = 3, est a dizendo para o carteiro pegar o valor 3 e levar at e a casa de x. Um ponteiro pode ser imaginado como um endere cador indireto para o objeto. Veja o exemplo a seguir, o qual e ilustrado na Figura 15.2. Cria objeto do tipo int, com nome x. O endere co de x e sua posi ca o na mem oria do computador; admita que o endere co de x e 1503. Exemplo: int x; // Figura 15.2 (a)
Diz para o carteiro levar o valor 3 at e a casa de x (no n umero 1503). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
E USO DE OBJETOS DINAMICOS 15.3. CRIAC AO COM PONTEIROS x = 3; // Figura 15.2 (b)
301
Constr oi um objeto ponteiro, do tipo int*, com nome ptr. Conte udo de ptr = NULL. int* ptr = NULL; // Figura 15.2 (P1) (c)
Pega o endere co de x (1503) e o armazena na casa de ptr, o mesmo que ptr = 1503. ptr = & x ; // Figura 15.2 (P2) (d)
O carteiro pega o valor 7, vai at e a casa de ptr, chegando a , ele encontra o endere co de x e recebe instru ca o para levar o pacote at e x. Em seguida, ele leva o valor 7 at e x. *ptr = 7; // Figura 15.2 (P3)
Memria do seu computador Memria do seu programa Memria de outro programa ....
x = lixo
....
x = 3 ptr=NULL
....
....
x = 3 ptr=1503
....
....
x = 7 ptr=1503
....
int main() { int x; // (a) x = 3; // (b) int * ptr = NULL;// (c) ptr = &x; // (d) *ptr = 7; // (e) std::cout << *ptr; return 0; }
Figura 15.2: Como declarar e usar um ponteiro. Note que para obter o endere co do objeto x, utiliza-se o operador de endere co (&), tamb em chamado operador refer encia. Para utilizar o ponteiro para acessar o objeto x, utiliza-se o operador desrefer encia (*ptr). A constante NULL e predenida com o valor 0. NULL e 0 s ao utilizados para zerar os ponteiros. Veremos a seguir como os ponteiros s ao usados para criar e manipular objetos criados em tempo de execu ca o (objetos din amicos).
15.3
Os ponteiros s ao utilizados na sua ess encia para criar, usar e apagar objetos dinamicamente. Mas por que devo usar objetos din amicos? A utiliza ca o de objetos din amicos possibilita ao programador ter um controle mais eciente e ex vel da mem oria utilizada. Quando os objetos s ao alocados durante a compila ca o, o programador deve denir previamente o tamanho deles. No exemplo a seguir e criado um vetor de C para armazenar uma string com 50 caracteres. char nome[50]; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
302
Mas o que acontece se o nome tiver mais de 50 caracteres? Ocorrer a um estouro de pilha (acesso a mem ` oria inv alida) e o seu programa ir a travar. E se o nome tiver apenas 20 caracteres? Ent ao voc e estar a desperdi cando 30 caracteres. Para evitar o estouro de pilha e o desperd cio de mem oria utilizam-se os objetos din amicos. Os objetos din amicos s ao alocados (criados) com o operador new (Se ca o 15.3.1) e usam o bloco de mem oria disponibilizado pelo sistema operacional (pilha ou heap ). Em seguida, s ao usados e, ent ao, devem ser destru dos utilizando-se o operador delete (Se ca o 15.3.2).
15.3.1
O operador new
O operador new e utilizado para alocar dinamicamente um bloco de mem oria. Primeiro new solicita ao sistema operacional um bloco de mem oria. Ap os alocar o bloco de mem oria, new retorna um ponteiro para o bloco alocado. Se new falhar, retorna um bad_aloc (veja Cap tulo 26 Exce co es). Veja a seguir o prot otipo para usar new. Observe que new Tipo cria um objeto do tipo Tipo, e new Tipo [dimens~ ao] cria um vetor de objetos. Prot otipo: Tipo* ptrObjeto = new Tipo ; Tipo* ptrVetor = new Tipo [dimens ao]; No exemplo que segue criamos um objeto inteiro com new e armazenamos o endere co em ptrInt. Exemplo: int * ptrInt = NULL; // Cria o ponteiro ptrInt = new int; // Aloca bloco de mem oria e cria objeto if( ptrInt == NULL ) // Se ocorreu erro na aloca c~ ao sai do programa cerr < < "Erro aloca c~ ao ptrInt" < < endl; ... usa ptrInt ... Neste outro exemplo criamos um vetor de caracteres e armazenamos o endere co em nomePessoa. Exemplo: char * nomePessoa = NULL; nomePessoa = new char [tamanhoNecess ario + 1]; if( nomePessoa == NULL ) cerr < < "Erro aloca c~ ao nomePessoa" < < endl; ... usa nomePessoa ... Nota: a macro NULL e denida no arquivo de cabe calho <cstdlib> e em outros cabe calhos de C. Nota: veremos na Se ca o 26.8.1 o uso de new (nothrow) e sua rela ca o com exce co es.
15.3.2
O operador delete
Para destruir o objeto e devolver a mem oria para o sistema operacional, utiliza-se o operador delete. Para deletar um vetor use delete [] ptrVetor;. Observe que apenas o bloco de mem oria e destru do. O ponteiro continua existindo e apontando para o bloco de mem oria que agora n ao existe mais, ou seja, depois de usar delete ptrObjeto, o ponteiro aponta para um monte de lixo e n ao deve ser utilizado. Depois de deletar o objeto e boa pr atica de programa ca o atribuir o valor NULL para o ponteiro. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
303
Se zermos uma analogia com vari aveis comuns, inicializar ou setar o conte udo do ponteiro com NULL equivale a denir um valor inicial para uma variv avel qualquer (como um int), ou seja, n ao existe muito sentido em termos vari aveis em nosso programa cujo conte udo e um monte de lixo. Prot otipo: delete ptrObjeto; ptrObjeto = NULL; delete [] ptrVetor; ptrVetor = NULL; No exemplo a seguir os ponteiros criados na Se ca o 15.3.1 s ao destru dos. Exemplo: delete ptrInt; delete [] nomePessoa; Veja no exemplo da listagem 15.1 a utiliza ca o de objetos din amicos com ponteiros. A listagem inicia-se com a inclus ao da biblioteca <iostream> para entrada e sa da de dados, incluindo ainda a classe CPonto (listagem 13.5). Observe que arquivos da biblioteca s ao inclu dos usando-se <> (est ao dentro do diret orio-padr ao para arquivos de inclus ao; exemplo, /usr/include), e arquivos do programador s ao inclu dos usando-se (est ao no diret orio de trabalho). Na linha 9 criamos um ponteiro para CPonto (CPonto*), e o igualamos a NULL. Na linha 11 o objeto e alocado com new CPonto, note que new retorna o endere co do objeto criado para o ponteiro (agora o ponteiro aponta para o objeto criado). Na linha 12 vericamos a aloca ca o com if(ptr == NULL). Depois de criado o objeto din amico, o objeto e utilizado, ptr->Set(x, y);, ptr->Desenha();. Compare este exemplo com o apresentado na listagem 13.7; naquele utiliz avamos mecanismos est aticos para criar o objeto CPonto; neste usamos mecanismos din amicos. Listing 15.1: Usando ponteiros para criar e usar objetos din amicos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # include < iostream > # include " CPonto . h " using namespace std ; // E x e m p l o de c r i a c~ a o e uso do objeto CPonto int main () { int x = 6; int y = 7; CPonto * ptr = NULL ; ptr = new CPonto ; if ( ptr == NULL ) { cout << " Falha aloca ca ~o . " return 1; } ptr - > Set (x , y ) ; ptr - > Desenha () ; int xx = ptr - > X () ; delete ptr ; return 0; }
// // // //
Cria p o n t e i r o para objeto do tipo CPonto Cria objeto do tipo CPonto e coloca e n d e r e c o em ptr . Testa a l o c a c~ ao
<< endl ;
// // // // // //
Chama m e todo Set () do objeto ptr Chama m e todo D e s e n h a () Chama m e todo X () que r e t o r n a x Destr~ o e o objeto a p o n t a d o por ptr Encerra o programa ptr sai de escopo e e destru do
[ b u e n o @ l d s c 0 5 Cap -15] $ make P r o g C P o n t o D i n a m i c o g ++ -g - O2 -o P r o g C P o n t o D i n a m i c o P r o g C P o n t o D i n a m i c o . o CPonto . o [ b u e n o @ l d s c 0 5 Cap -15] $ ./ P r o g C P o n t o D i n a m i c o TPonto : Coordenada x =6 TPonto : Coordenada y =7
304
Observe que com objetos est aticos usa-se nomeobjeto.atributo, e com objeto din amicos, troca-se o ponto (.) pela seta (->) nomeobjeto->atributo. Se voc e deseja acessar um m etodo de um objeto din amico, pode usar uma das duas op co es que seguem: Exemplo: ptr->M etodo(); *ptr.M etodo(); Otimiza c ao: toda opera ca o de aloca ca o com new e desaloca ca o com delete tem um custo em termos de tempo de processamento. Se o desempenho do programa e importante, ent ao deve ser feita uma otimiza ca o do programa com o objetivo de reduzir as o n umero de opera co es com new e delete.
15.4
Ponteiro this
Na parte de an alise orientada a objeto (Cap tulo 3 Conceitos B asicos de POO), vimos que a classe e denida como uma f abrica de objetos e que e a classe que dene a forma do objeto. Vimos ainda que, quando se cria um objeto, e reservado espa co na mem oria para inclus ao de todos os atributos n ao est aticos do objeto e n ao e reservado espa co para os m etodos. Assim, um objeto na mem oria do computador cont em somente atributos (veja as Figuras 12.1 e 12.2). Os m etodos n ao s ao criados para cada objeto; eles cam armazenados na classe. Isto faz sentido, pois dois objetos da mesma classe ter ao atributos diferentes, mas os m etodos ser ao os mesmos. Quando um objeto acessa um de seus m etodos, ele est a acessando os m etodos da classe. Como os m etodos s ao os mesmos para todos os objetos da classe e necess ario um dispositivo de identica ca o de qual objeto est a acessando o m etodo. Esse dispositivo e implementado por meio do ponteiro this. Por meio deste, o m etodo da classe sabe qual objeto o est a acessando. Veja a seguir um exemplo de m etodo que usa o ponteiro impl cito this para acessar o atributo x. Exemplo: class CPonto { int x, y; public: int X(int _x) { x = _x ; } int X() { return this->x; } }; int main() { CPonto objeto; int vx = 4; objeto.X(vx); cout < < objeto.X(); return 0; }
// Cria objeto // Acessa m etodo int X(int) da classe CPonto // Acessa m etodo int X() da classe CPonto
O compilador traduz a sua chamada ao m etodo X(int) da seguinte forma: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
15.5. PONTEIROS CONST E PONTEIROS PARA CONST Exemplo: X(const Tipo* this = &objeto, vx);
305
// Tradu c~ ao para C
Ou seja, this e um ponteiro para o objeto que e passado implicitamente para o m etodo. Exemplo: this = &objeto;
Observe que, quando um objeto chama um m etodo da classe, ele passa para o m etodo o seu endere co por meio do ponteiro this. Dessa forma, ao utilizar um atributo x, na realidade o m etodo est a utilizando this->x. Assim, this e um ponteiro que e passado implicitamente a um m etodo da classe, informando qual objeto o est a acessando. Um ponteiro this da classe T e do tipo T* const, isto e, aponta sempre para o mesmo objeto. Um m etodo est atico n ao recebe um ponteiro this, ou seja, n ao sabe qual objeto est a acessando. Este e o motivo pelo qual um m etodo est atico s o pode acessar atributos est aticos. Se um m etodo e const, seu ponteiro this e do tipo const T* const, isto e, aponta sempre para o mesmo objeto, e este n ao pode ser alterado. Exemplo com uso de this e apresentado na listagem 17.2.
15.5
A palavra-chave const e utilizada para informar que o objeto e constante, n ao muda. Pode ser utilizada com ponteiros, signicando que o ponteiro aponta sempre para o mesmo local de mem oria ou que o objeto apontado n ao muda, ou ambos. Entenda a seguir as diferentes formas de uso de const com ponteiros.
15.5.1
O conte udo do objeto apontado e constante, mas o ponteiro pode ser utilizado para apontar para outros objetos. Exemplo: int a = 1; int b; const int *ptrC = &a; b = *ptrC; *ptrC = 6; ado e const ptrC = &b;
&a ptrC b =1 a=1
// // // //
Cria ponteiro para const int que aponta para a. Ok, b recebe o conte udo de a Erro, ptrC n~ ao pode ser desreferenci-
306
15.5.2
Ponteiro constante
Quando o ponteiro aponta para o mesmo local da mem oria, o objeto apontado pode ser alterado. Exemplo: int a = 3; int b = 4; int* const cPtr = &a; b = *cPtr; *cPtr = 5; cPtr = &b; jeto.
&a cPtr b =4 a=3
// // // //
Ok, cria o ponteiro e inicializa Ok, b recebe o conte udo de a (b = 3) Ok, a recebe o valor 5 (a = 5) Erro, cPtr aponta sempre para o mesmo ob-
&a cPtr
a=5
b =4
15.5.3
Neste caso tanto o ponteiro como o objeto apontado n ao podem ser alterados. Exemplo: double a = 3.1415; const double * const cPtrC = &a; double b = 7.2; *cPtrC = 6.2; // Erro, o conte udo do objeto apontado n~ ao pode mudar cPtrC = &b; // Erro, cPtrC aponta sempre para o mesmo endere co
&a cPtrC b =7.2 a = 3,1415 &a cPtrC b =4 a=5 cPtrC no pode apontar para b, nem mudar o contedo de a.
15.6
Uma refer encia pode ser encarada como um outro nome para um objeto, um apelido. Ela deve ser denida uma u nica vez, dessa forma apontar a sempre para o mesmo local da mem oria (para o mesmo objeto). Na pr atica refer encias s ao utilizadas como par ametros de m etodos e fun co es. Veja Se ca o 13.6. Refer encias para ponteiros costumam ser utilizadas como par ametros de m etodos. Uma refer encia n ao pode ser alterada para referenciar outro objeto ap os sua inicializa ca o (ou seja, uma refer encia se comporta como um ponteiro constante). Como as refer encias n ao s ao objetos, n ao podem existir matrizes de refer encias. Com rela ca o ` as refer encias n ao podemos: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
15.6. REFERENCIAS (&) N ao podemos declarar refer encias de refer encias. N ao podemos declarar refer encias para membros de classe. N ao podemos declarar um ponteiro para uma refer encia. N ao podemos declarar um array de refer encias. Veja a seguir o prot otipo e um exemplo de uso de refer encias. Prot otipo: Tipo & nomeRefer encia = &objeto; Exemplo: int v1 = 5; int algo = 3; int v2; // Declara uma refer^ encia a v1, ou seja, refV1 e o mesmo que v1 int& refV1 = v1; // Para armazenar v1 em v2 v2 = refV1; // Para armazenar algo em v1 usando a refer^ encia refV1 = algo; // O endere co da refer^ encia e igual ao endere co do objeto referenciado. // Armazena endere co de v1 em ptr int* ptr = &refV1; A listagem 15.2 mostra o uso de refer encias. Listing 15.2: Usando refer encias.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # include < iostream > using namespace std ; int main () { int x = 3; // tipo = int , nome =x , valor =3 int & ref = x ; // tipo = r e f e r ^ e n c i a para inteiro , nome = ref , valor = x // Daqui para frente , ref e a mesma coisa que x . cout << " Valor de x = " << x << " \ tValor da ref = " << ref << endl ; ref = 156; cout << " Mudou ref " << endl ; cout << " Valor de x = " << x << " \ tValor da ref = " << ref << endl ; x = 6; cout << " Mudou x " << endl ; cout << " Valor de x = " << x << " \ tValor da ref = " << ref << endl ; return 0; } bash -3.00 $ Valor de x Mudou ref Valor de x Mudou x Valor de x ./ a . out = 3 = 156 = 6
307
Vimos na Se ca o 13.6 a passagem de par ametros em m etodos, incluindo o uso de refer encias. Reveja a listagem 13.2. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
308
15.6.1
Uma refer encia n ao reserva espa co na mem oria para si pr opria, ao contr ario dos ponteiros, que reservam um espa co na mem oria. Observe que existe ponteiro de ponteiro (veja Se ca o F.3), mas n ao existe refer encia de refer encia.
15.6.2
Voc e pode declarar uma refer encia para um ponteiro, ou seja, um outro nome para um ponteiro. Veja o exemplo que segue e a listagem 13.2. Exemplo: int x = 3; int * ponteiro = &x; Tipo * & referenciaDePonteiro = ponteiro;
15.7
O desenvolvimento de softwares avan cados, principalmente o de softwares cient cos, requer um controle mais renado da mem oria utilizada pelo programa. Um dos pontos cr ticos em programa ca o cient ca e o eciente controle da rela c ao mem oria consumida versus tempo de processamento. Veremos nesta se ca o alguns conceitos b asicos de gerenciamento de mem oria. Nota: veremos na Se ca o 21.8 como sobrecarregar o operador new de C++.
15.7.1
Quando uso int* v = new int[n]; aloco um vetor de inteiros de tamanho n. Posteriormente deleto o bloco de mem oria com delete [] v. A pergunta e: como o compilador sabe o tamanho do bloco a ser deletado? A maioria dos compiladores coloca, imediatamente antes da casa v[0], um espa co para um unsigned int (ou similar), no qual o tamanho n e armazenado. Note que se o vetor armazenar objetos grandes, o espa co consumido para armazenar a dimens ao do vetor continuar a sendo provavelmente do tamanho de um unsigned int. Veja Figura 15.3.
15.7.2
Alinhamento
Vamos iniciar nossa discuss ao apresentando um exemplo e uma pergunta. Na listagem 15.3, por que o sizeof(C1) e diferente de sizeof(C2)? Listing 15.3: Entendendo o alinhamento.
1 2 3 4 5 6 7 8 9 # include < iostream > using namespace std ; class C1 { char ca ; int x ; char cb ;}; class C2 { char ca ; char cb ; int x ;}; class C3 { char ca ; char cb ; char cc ; char cd ; int x ;}; int main () {
309
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
C1 vC1 [10]; C2 vC2 [10]; C3 vC3 [10]; cout << " Consumo individual de C1 -> sizeof ( char ) *2 + sizeof ( int ) = " << sizeof ( char ) *2 + sizeof ( int ) << " \ nsizeof ( C1 ) = " << sizeof ( C1 ) << " \ tsizeof ( vC1 ) = " << sizeof ( vC1 ) << " \ n \ nConsumo individual de C2 -> sizeof ( char ) *2 + sizeof ( int ) = " << sizeof ( char ) *2 + sizeof ( int ) << " \ nsizeof ( C2 ) = " << sizeof ( C2 ) << " \ tsizeof ( vC2 ) = " << sizeof ( vC2 ) << " \ n \ nConsumo individual de C3 -> sizeof ( char ) *4 + sizeof ( int ) = " << sizeof ( char ) *4 + sizeof ( int ) << " \ nsizeof ( C3 ) = " << sizeof ( C3 ) << " \ tsizeof ( vC3 ) = " << sizeof ( vC3 ) << endl ; return 0; } Consumo individual de C1 -> sizeof ( char ) *2 + sizeof ( int ) = sizeof ( C1 ) = 12 sizeof ( vC1 ) = 120 Consumo individual de C2 -> sizeof ( char ) *2 + sizeof ( int ) = sizeof ( C2 ) = 8 sizeof ( vC2 ) = 80 Consumo individual de C3 -> sizeof ( char ) *4 + sizeof ( int ) = sizeof ( C3 ) = 8 sizeof ( vC3 ) = 80 6
A resposta e o alinhamento, um dos conceitos b asicos associados ao gerenciamento do consumo de mem oria. A id eia e simples: quando um bloco de mem oria e alocado, o mesmo e feito sempre em peda cos m nimos de bytes de tamanho m. Isto signica que, se alocamos um bloco de tamanho n, sendo n<m, o bloco que vai ser efetivamente alocado ter a tamanho m. O desperd cio ser a de m-n bytes. Observe na Figura 15.4(a) que cada objeto apresenta um desperd cio de mem oria em fun ca o do alinhamento de seus atributos. Note que o desperd cio com a cria ca o de C1 e maior do que com a cria ca o de C2, porque C2 tem um layout mais otimizado. A classe C3 tem o melhor aproveitamento da mem oria; n ao ocorre desperd cio com alinhamento. Lembre-se de que um char consome 1 byte, e um int, 4 bytes (na minha plataforma de 64 bits, processador AMD Opteron 64). Na sa da da listagem 15.3, vericamos que o consumo individual total dos atributos de C1 e de 6 bytes. J a o consumo da classe C1 e de 12 bytes e da classe C2 de 8 bytes. Ou seja, a Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
310
(a)
(b)
Objeto[1] atributos
Objeto[2] atributos
.....
declara ca o da classe C2 e mais econ omica, pois a ordem utilizada reduz a perda de mem oria provocada pelo alinhamento. Note que a classe C3 tem o melhor aproveitamento da mem oria. importante entender que podemos diminuir este desperd E cio mas n ao o evitar totalmente. A dica e simples: declare atributos do mesmo tipo em seq u encia. Em seguida, use o operador sizeof() para ver o tamanho efetivo da classe criada. Voc e pode reorganizar a ordem dos atribudos at e encontrar o menor sizeof() poss vel. Se tivermos um vetor de objetos, Figura 15.4(b), teremos um desperd cio maior, associado ao alinhamento entre os objetos. Isso tamb em depende do tamanho do objeto.
15.7.3
Veremos a seguir algumas d uvidas comuns associadas ao uso dos operadores new e delete e ao gerenciamento de mem oria, al em de algumas respostas curtas e diretas. D uvidas b asicas Se um ponteiro ptr tem valor NULL, qual o efeito de delete ptr? delete ptr n ao faz nada quando ptr == NULL. O comando delete ptr exclui o ponteiro ptr ou o dado apontado por *ptr? Exclui o dado; o ponteiro continua existindo. Posso deletar um bloco de mem oria alocado com new usando free? N ao. N ao podemos misturar o uso dos operadores de C++ new/delete com as fun co es de aloca ca o de C malloc() e free(). Veja a listagem ??. Um vetor de tamanho n e tipo T consome quanto bytes? Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
311
Provavelmente n*sizeof(T) + sizeof(unsigned int), ou seja, o tamanho do bloco a ser utilizado mais o tamanho de um inteiro em que e armazenado o tamanho n do vetor criado. Veja Figura 15.3. 2 Ap os usar new, preciso realmente testar a aloca ca o com if(ptr != NULL)? N ao. Como visto no Cap tulo 26 Exce co es, quando new falha, ele lan ca exce co es que podem ser tratadas externamente (fora do bloco try). 2 Veremos como sobrecarregar o operador new na Se ca o 21.8. 2 Posso evitar que um objeto seja est atico? Sim, mas neste caso todos os construtores da classe CNome devem ser privados e voc e deve fornecer m etodos p ublicos e est aticos que criam objetos do tipo CNome usando new. Veja o exemplo a seguir; observe, dentro de main(), que precisamos chamar os m etodos p ublicos. Exemplo: class CNome { public: // M etodos p ublicos static CNome* New() { return new CNome(); } static CNome* New(int n) { return new CNome[n]; } static CNome* New(const CNome& obj) { return new CNome(obj); } // Construtores privados (n~ ao podem ser chamados) private: CNome(); CNome(const CNome& obj); }; int main() { CNome* p = CNome::New(); // Cria um objeto CNome* ptrV = CNome::New(10); // Cria um vetor de objetos delete p; delete ptrV; return 0; } D uvidas associadas ao uso de exce co es2 O que acontece se um construtor lan car uma exce ca o? O objeto e destru do, e a mem oria e devolvida para o sistemas operacional. O uso de set_new_handler(f)garante que a fun ca o denida f sempre ser a utilizada? N ao. Vimos na Se ca o 16.6.3 que objetos globais est aticos s ao constru dos antes da execu ca o de main(), ou seja, antes de executar set_new_handler(f). Isto signica que, se um objeto est atico chamar uma determinada fun ca o, que usa new, ser a utilizada a fun ca o new_handler padr ao do sistema e n ao a que denimos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
15.8. SENTENCAS PARA PONTEIROS, REFERENCIAS E GERENCIAMENTO DE 312 MEMORIA D uvidas associadas ao uso da STL21 O que s ao os gerenciadores de mem oria (ou alocadores) da STL? s ao objetos da STL utilizados para construir os containers. De modo geral, cada container tem um gerenciador de mem oria padr ao. Um container de tamanho n e tipo T consome quanto bytes? Depende do tipo de container e de informa co es associadas ao alinhamento dos atributos. A dica e simples: construa o container usando diferentes tipos de container e fa ca testes para ver qual consome menos mem oria. Qual container da STL e mais econ omico? O container mais econ omico e vector. Basicamente vector consome n*sizeof(T) + sizeof(int). N ao existe overhead em um vector. Em um container deque s ao criados diversos blocos de dados. O gerenciamento desses blocos implica em um pequeno aumento do consumo de mem oria (da ordem de 4%). Para saber o valor exato, construa um vector, um deque e veja a diferen ca no consumo de mem oria. Em uma lista <list>, veja Se ca o 32.2, cada elemento deve armazenar dois iteradores extras (veja Figura 32.3), ou seja, cada elemento da lista vai consumir pelo menos o tamanho do objeto armazenado mais o tamanho de dois iteradores. Os containers <set> e <multiset> trabalham com tr es ponteiros extras, ou seja, cada elemento do <set> vai consumir pelo menos o tamanho do objeto armazenado mais o tamanho de tr es iteradores. Os containers <map> e <multimap> tamb em trabalham com tr es ponteiros extras, mas neste caso s ao tr es pairs, de modo que first e a chave e second o valor, ou seja, cada elemento do <map> vai consumir pelo menos o tamanho do objeto armazenado mais o tamanho de tr es iteradores para pares pair<const key, T>. A dica de otimiza ca o de mem oria e: construa seu programa utilizando diferentes tipos de containers e verique qual o mais econ omico.
15.8
Se o ponteiro aponta para NULL, o uso de delete ptr; n ao tem efeito. Se uma fun ca o retorna uma refer encia para um objeto, ela pode aparecer ` a esquerda do operador =. Exemplo: // Declara c~ ao e defini c~ ao de m etodo int & Valor(int &i){ return i; }; int x; Valor(x) = 234;
1 Veremos
313
Evite retornar refer encias, ponteiros ou iteradores para atributos internos do objeto. Isto deixa o c odigo mais encapsulado. Em C a chamada a f(a,b) passa para f uma c opia de a e de b (a e b n ao ser ao alterados); a chamada a f2(&a,&b), por sua vez, passa para f2 ponteiros para a e b, indicando que a e b poder ao ser alterados. Em C++, a chamada a f(a,b) n ao informa se a e b ser ao necess passados por c opia ou por refer encia. E ario conferir isso no arquivo de declara ca o da classe. Se o par ametro de um m etodo/fun ca o e do tipo integral e n ao pode ser alterado, ele pode ser passado por c opia. Isto se justica porque os tipos integrais s ao copiados de forma muito r apida, sendo inclusive mais r apidos que o uso de refer encias. Ao criar objetos locais, usando new, verique se eles s ao destru dos. Para possibilitar a chamada de m etodos encadeados, o m etodo deve retornar um objeto (um lvalue). No exemplo a seguir o m etodo retorna uma refer encia ao pr oprio objeto. Exemplo: Tipo& CNomeClasse::M1() { return *this; } // Uso ( (obj.M1() ).M2() ).M3(); Em linguagens como Smalltalk e Java todos os objetos s ao acessados com ponteiros. Somente sobrecarregue new e delete como m etodos est aticos. 2 Lembre-se de que delete ptr executa operator delete(void*); j a delete[] ptr chama operator delete[] (void*). 3 Bugs : Digamos que voc e deseja passar um objeto como par ametro para um m etodo M etodo(nomeclasse obj). Como voc e est a passando o objeto por c opia, vai criar uma c opia do objeto. Depois vai usar o objeto dentro do m etodo e, ao encerrar o m etodo, o objeto ser a deletado. Se o objeto original tinha algum ponteiro com aloca ca o din amica, esse ponteiro ser a deletado, sendo deletado o bloco de mem oria por ele acessado. Assim, o ponteiro do objeto original aponta agora para um monte de lixo. Para que isso n ao ocorra, voc e deve passar uma refer encia do objeto, de forma que e passado o pr oprio objeto e n ao uma c opia deste, e, quando sair de escopo, o objeto n ao ser a eliminado. Outra solu ca o e sempre implementar o construtor de c opia (veja Se ca o 16.5.1).
15.9
Normalmente o aprendizado de ponteiros em C e confuso e complicado. Isto ocorre porque C n ao tem o conceito de refer encias, e, portanto, tem-se de usar em demasia os ponteiros. Mais do que isto, e normal em C o uso excessivamente elaborado de ponteiros. Programadores experientes abusam dos ponteiros e deixam o c odigo ileg vel para os programadores comuns. A dica e: use e abuse dos ponteiros, mas n ao deixe o c odigo rebuscado demais isto atrapalha mais do que ajuda. Neste cap tulo aprendemos que um ponteiro e um objeto pequeno que armazena o endere co de outro objeto. Aprendemos a criar e usar objetos din amicos usando o operador new e a delet a-los usando o operador delete. A grande vantagem e que temos um controle renado Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
314
do uso da mem oria. Vimos ainda que o ponteiro oculto this e um ponteiro para o objeto que chamou o m etodo. Aprendemos a usar as diferentes varia co es de ponteiros com const. Aprendemos a utilizar as refer encias de C++ e suas diferen cas em rela ca o aos ponteiros. No nal do cap tulo, vimos os conceitos b asicos de gerenciamento de mem oria. Nota: o uso de vetores no estilo de C e apresentado no Ap endice H Vetores e Matrizes Arrays.
15.10
Exerc cios
1. Qual a vantagem do uso de ponteiros e aloca ca o din amica de mem oria? 2. Releia a listagem 13.1. 3. Explique com suas palavras o funcionamento de new e delete. 4. Explique com suas palavras o funcionamento de this. 5. Comece modicando a listagem 15.1. Acrescente objeto com uso normal de CPonto e compare os c odigos. 6. Monte um exemplo que use os conceitos apresentados na Se ca o 15.2. Justique a vantagem do uso de ponteiros const. 7. Crie um exemplo que utilize ponteiros normais, ponteiros para objetos que n ao podem mudar, e ponteiros que n ao podem ser usados para apontar outros objetos. 8. Para que servem as refer encias? 9. Monte um exemplo que inclua o uso de refer encias. 10. Quando o uso de refer encias para ponteiros e interessante? Monte um exemplo. 11. Crie exemplo que inclua o uso de um vetor de bool com n elementos. Um ponteiro deve ser utilizado para alocar dinamicamente o vetor, e para acessar seus elementos. O usu ario deve poder visualizar e modicar cada bit, tendo como base perguntas simples cuja resposta seja sempre verdadeiro/falso. 12. Crie exemplo que tenha a seguinte congura ca o: duas fun co es globais que incluam a cria ca o de objetos est aticos com valores predenidos (inicializados com 0). A cada vez que uma fun ca o e chamada, seus valores s ao atualizados (por exemplo contadores). Crie uma classe com um m etodo normal, mas que tenha par ametros predenidos, os quais devem ser inicializados com os valores das fun co es globais. Comente o exerc cio.
Cap tulo 16
16.1
Veremos nesta se ca o uma introdu ca o aos m etodos construtores e destrutores, isto e, suas caracter sticas. Caracter sticas dos m etodos construtores Nas listagens apresentadas at e aqui, ap os construir um objeto precis avamos iniciar os atributos; m etodo Entrada() na listagem 13.2, m etodo Inicializa() na listagem 13.3, m etodo Set() na listagem 13.5. N ao seria interessante se pud essemos ter m etodos especiais para iniciar os objetos automa exatamente isso o que fazem os construtores. ticamente quando os mesmos s ao constru dos? E Veja a seguir algumas caracter sticas dos construtores: Um m etodo construtor e um m etodo como outro qualquer; a diferen ca e que esse e automaticamente executado quando o objeto e criado. O objetivo b asico dos construtores e inicializar os atributos do objeto. Al em de inicializar os atributos do objeto, podemos realizar outras tarefas. Por exemplo: se sua classe representa uma impressora, voc e pode vericar se existe uma impressora conectada ao sistema. 315
316
Um m etodo construtor tem o mesmo nome da classe e n ao retorna nada, nem mesmo void. Por padr ao da linguagem, os m etodos construtores n ao podem ser const nem volatile. ca o Crie vari aveis din amicas no construtor com new e apague no destrutor com delete (Se 15.3). 2 Um construtor n ao pode ser virtual, mas pode ser sobrecarregado (veja Cap tulo 14 Sobrecarga de M etodos). Quando criamos um objeto (exemplo: CNome objeto;), a seq u encia de constru ca o e dada por: Solicita ca o de mem oria para o sistema operacional (para armazenar os atributos do objeto). Cria ca o dos atributos do objetos. Execu ca o do c odigo do construtor da classe. Caracter sticas dos m etodos destrutores Os m etodos destrutores t em o objetivo de destruir o objeto e devolver para o sistema operacional a mem oria alocada, fazendo o trabalho inverso do construtor. Veja a seguir algumas caracter sticas do destrutor: Tem o mesmo nome da classe antecedido pelo til (~). N ao retorna nada, nem mesmo void. N ao pode ter par ametros. N ao pode ser sobrecarregado. N ao pode ser static, const nem volatile. Em cada classe, devemos ter um u nico destrutor. Faz o trabalho inverso do construtor. Deve liberar a mem oria alocada no construtor e destruir os objetos din amicos. O destrutor e automaticamente executado quando o objeto sai de escopo.
16.2
Veja a seguir o prot otipo para declara ca o dos m etodos construtores e destrutores. Ao lado do prot otipo est a o n umero da se ca o em que o mesmo ser a discutido. Observe que o m etodo construtor tem o mesmo nome da classe e n ao retorna nada, nem mesmo void. O m etodo destrutor tamb em n ao retorna nada e tem o mesmo nome da classe precedido do til (~). Prot otipo: class CNome { CNome(); Programa ca o Orientada a Objeto com C++
317
CNome(par ametros); // Construtor sobrecarregado, veja se ca o 16.3 CNome(const CNome & obj); // Construtor de c opia, veja se ca o 16.5 CNome(const CNome & obj, int=0); // Construtor de c opia, veja se ca o 16.5 Tipo(); // Construtor de convers ao, veja se ca o 25.3 CNome(); // Destrutor , veja se ca o 16.1 virtual CNome(); // Destrutor virtual, veja se ca o 19.2 }; // Implementa ca o dos construtores CNome::CNome(par ametros) : atributo1(valorInicial), atributo2(valorInicial),... // veja se ca o 16.4 {....c odigo do construtor.... } // Implementa ca o dos destrutores CNome::CNome() {....c odigo do destrutor.... }
16.3
Se voc e n ao criar um m etodo construtor, o compilador cria automaticamente um construtor vazio, que n ao recebe nenhum par ametro e e chamado de construtor default. Veja o prot otipo na Se ca o 16.2. No exemplo a seguir, o compilador cria um m etodo construtor default para a classe CNomeClasse. Exemplo: class CNomeClasse { int a; // O compilador cria automaticamente o construtor // a seguir, sem par^ ametros e vazio // CNomeClasse(){}; }; int main() { CNomeClasse obj2(); // ok, usa o construtor default. } Caso seja de seu interesse, voc e pode implementar o construtor default. class CNomeClasse { int a; public: CNomeClasse(){ a = 0; }; };
// (1)
Observe que, se voc e criar um construtor com par ametros, deixa de existir o construtor default. Exemplo: class CNomeClasse Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
318
DOS ATRIBUTOS DA CLASSE NOS CONTRUTORES 16.4. INICIALIZAC AO { int a; public: // Construtor criado CNomeClasse(int _a){ }; int main() { CNomeClasse obj1(5); CNomeClasse obj2(); }
Se na classe existirem atributos refer encias ou atributos const, o compilador n ao criar a o construtor default. Neste caso, voc e ter a de implementar o construtor default (sem par ametros). Isto ocorre porque voc e precisa inicializar os atributos const e as refer encias. Exemplo: class CNomeClasse { public: int a, b; const int c;
// Atributos normais // Atributo const // Construtor com par^ ametros CNomeClasse(int _a,int _b,int _c) : a(_a),b(_b),c(_c) {}; };
Um vetor no estilo de C s o pode ser contru do se a classe tiver um construtor default. Veja o exemplo: int main() { // Cria vetor de objetos do tipo CNomeClasse, com 30 elementos CNomeClasse vetorEstatico [30]; // ok, usa (1) return 0; } Se um atributo CX da classe CNomeClasse for um tipo do usu ario que n ao tem um construtor default, ent ao o construtor de CX deve ser explicitamente chamado. Crie sempre um construtor default, assim voc e evita problemas.
16.4
Os atributos do objeto podem (e devem) ser inicializados no construtor, o prot otipo de inicializa ca o dos atributos da classe no construtor e dado a seguir. Depois do nome do construtor e de seus par ametros, observe o uso de : e, em seguida, a lista de atributos com seus valores separados por v rgula. Observe que, ao inicializar o atributo ap os :, este e inicializado na sua constru ca o, o que e mais r apido do que atribuir um valor ao atributo dentro do construtor. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
16.5. CONSTRUTOR DE COPIA T(CONST T& OBJ) Prot otipo: CNomeClasse(T1 v1, T2 v2,..,TN vn) :atributo1(v1),atributo2(v2),...,atributon(vn) { ..deni ca o do construtor.. };
319
No exemplo a seguir a op ca o (1) constr oe a e b e j a inicializa com _a e _b. A op ca o (2) e mais lenta primeiro constr oe a e b e depois atribue valores a = _a; b = _b;. Exemplo: class CNomeClasse { public: int a, b; const int c; // Atributos // Op c~ ao 1: Inicializa atributos ap os : CNomeClasse(int _a,int _b,int _c) : a(_a),b(_b),c(_c) {}; // Op c~ ao 2: Inicializa dentro do construtor CNomeClasse(int _a, int _b, int _c) :c(_c) { a = _a; b = _b; }; };
16.5
Outro construtor bastante utilizado e o construtor de c opia, o qual e utilizado para criar uma c opia de um objeto existente (veja o prot otipo e o exemplo). Se voc e n ao criar um construtor de c opia e utilizar o operador de atribui ca o (=), ent ao o compilador ir a construir automaticamente o construtor de c opia. Veja no prot otipo a seguir que o par ametro recebido pelo construtor de c opia e um objeto da pr opria classe; o const informa que o objeto recebido n ao pode ser alterado, o que faz sentido pois estamos criando um objeto novo e nosso interesse e apenas copiar os atributos do objeto antigo para o novo. Prot otipo: CNomeClasse(const CNomeClasse & obj); No exemplo a seguir, o construtor de c opia e utilizado para construir os objetos p2 e p3 a partir de p1. Exemplo: CPonto p1;
Cria objeto do tipo CPonto com nome p1, utiliza o construtor default. Cria objeto do tipo CPonto com nome p2, utiliza o construtor de c opia, os atributos de p2 ser~ ao iguais aos de p1. Cria objeto p3, utiliza o construtor de c opia, os atributos de p3 ser~ ao iguais aos de p1 Cria objeto p4, utiliza o construtor default. Utiliza o operador =, igualando p4 a p3. Utiliza o operador ==, comparando p4 e p2.
Na listagem 16.1, mostra-se a utiliza ca o do construtor default e do construtor de c opia. Note que, tanto no construtor default como no de c opia, inicializamos os valores de nome, matricula Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
320
e iaa e enviamos uma mensagem para tela. Note que o construtor de c opia copia um a um os atributos do objeto. No destrutor decrementamos o n umero de objetos e enviamos mensagem para tela; o objetivo das mensagens e acompanhar os processos de constru ca o e destrui ca o (did atico). Observe que, para cada atributo, criamos dois m etodos um para deni ca o e outro para leitura do valor do atributo. Os m etodos de Entrada() e Saida() s ao utilizados para entrada e sa da de todos os dados do objeto. Outros coment arios s ao embutidos no texto. Observe na sa da que <vector> cria um objeto usando o construtor default : Criou objeto 2 construtor default . Em seguida, ele cria os objetos 3, 4 usando o construtor de c opia. Posteriormente, apaga o objeto criado com o construtor default Destruiu o objeto 4. Na pr atica, isso signica que voc e deve sempre criar um construtor de c opia. Observe que os atributos nome, matricula e iaa ( ndice de aproveitamento acumulado) s ao inicializados no construtor. ao criados utilizando o construtor de Note que, tanto o professor2 quanto o professor3, s c opia. Listing 16.1: Usando construtor default e de c opia.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 # include < iostream > # include < string > # include < vector > using namespace std ; class CPessoa { private : string nome ; string matricula ; double iaa ; static int n u m e r o A l u n o s ; public : // C o n s t r u t o r default , c h a m a d o a u t o m a t i c a m e n t e // na c o n t r u c~ a o do objeto CPessoa () : nome ( " " ) , matricula ( " " ) , iaa (0) { n u m e r o A l u n o s ++; cout << " Criou objeto " << n u m e r o A l u n o s << " construto r default " << endl ; } // C o n s t r u t o r de c o pia , cria uma c o pia de um objeto e x i s t e n t e CPessoa ( const CPessoa & obj ) { nome = obj . nome ; matricula = obj . matricula ; iaa = obj . iaa ; n u m e r o A l u n o s ++; cout << " Criou objeto " << n u m e r o A l u n o s << " construto r de c o pia " << endl ; } ~ CPessoa () // M e todo Destrutor , c h a m a d a a u t o m a t i c a m e n t e { // na d e s t r u i c~ a o do objeto cout << " Destruiu objeto " << n u m e r o A l u n o s << endl ; numeroAlunos - -; } void void void void Entrada () ; Nome ( string _nome ) { Matricula ( string _m ) { Iaa ( double _iaa ) {
} } }
{ {
} }
321
return n u m e r o A l u n o s ;};
void CPessoa :: Entrada () { cout << " Entre com o nome : " ; getline ( cin , nome ) ; cout << " Entre com a matr cula : " ; getline ( cin , matricula ) ; cout << " Entre com o iaa : " ; cin >> iaa ; cin . get () ; } void CPessoa :: Saida () const { cout << " Nome do aluno : " << nome << " Matr cula : " << matricula << " iaa : " << iaa << endl ; } int main () { string linha = " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\ n " ; CPessoa professor ; // Usa c o n s t r u t o r d e f a u l t cout << " Entre com o nome do professor : " ; string nome ; getline ( cin , nome ) ; professor . Nome ( nome ) ; cout << " Entre com a matr cula do professor : " ; string matricula ; getline ( cin , matricula ) ; professor . Matricula ( matricula ) ; cout << " Entre com o n u mero de alunos da disciplina ( ex : 3) : " ; int n u m e r o A l u n o s ; cin >> n u m e r o A l u n o s ; cin . get () ; // Cria vetor do tipo C P e s s o a com nome aluno , usa c o n s t r u t o r d e f a u l t vector < CPessoa > aluno ( n u m e r o A l u n o s ) ; for ( int contador = 0; contador < aluno . size () ; contador ++) { cout << " Aluno " << contador << endl ; aluno [ contador ]. Entrada () ; } cout << linha << " RELA C~ A O DE PROFESSOR ES E ALUNOS : \ n " << linha ; cout << " Nome do professor : " << professor . Nome () << endl ; cout << " Matr cula : " << professor . Matricula () << endl ; for ( int contador = 0; contador < aluno . size () ; contador ++) { cout << linha << " Aluno " << contador << endl ; aluno [ contador ]. Saida () ; }
322
106 107 108 109 110 111 112 113 114 115 116 117 118
cout << linha << " N u mero de alunos = " << CPessoa :: N u m e r o A l u n o s () << endl ; cout << linha << " chamando : CPessoa professor2 ( professor ) ; " << endl ; CPessoa professor2 ( professor ) ; // Usa c o n s t r u t o r de c o pia professor2 . Saida ( cout ) ; { cout << linha << " chamando : CPessoa professor 3 = professor2 ; " << endl ; CPessoa professor 3 = professor2 ; // Usa c o n s t r u t o r de c o pia professor3 . Saida ( cout ) ; } // <- D e s t r o i professor3 , professor2 , alunos e p r o f e s s o r return 0; } Criou objeto 1 construto r default Entre com o nome do professor : Andr e Duarte Bueno Entre com a matr cula do professor : 123 Entre com o n u mero de alunos da disciplina ( ex : 3) : 2 Criou objeto 2 construto r default Criou objeto 3 construto r de c o pia Criou objeto 4 construto r de c o pia Destruiu objeto 4 Aluno 0 Entre com o nome do aluno : Danilo Marques Entre com a matr cula do aluno : 343 Entre com o IAA do aluno : 8 Aluno 1 Entre com o nome do aluno : Tiago Schaewer Entre com a matr cula do aluno : 123 Entre com o IAA do aluno : 9 ------------------------------------------------------RELA C~ A O DE PROFESSOR E S E ALUNOS : ------------------------------------------------------Nome do professor : Andr e Duarte Bueno Matr cula : 123 ------------------------------------------------------Aluno 0 Nome do aluno : Danilo Marques Matr cula : 343 IAA : 8 ------------------------------------------------------Aluno 1 Nome do aluno : Tiago Schaewer Matr cula : 123 IAA : 9 ------------------------------------------------------N u mero de alunos = 3 ------------------------------------------------------chamando : TPessoa professor2 ( professor ) ; Criou objeto 4 construto r de c o pia Nome do aluno : Andr e Duarte Bueno Matr cula : 123 IAA : 0 ------------------------------------------------------chamando : TPessoa professor 3 = professor2 ; Criou objeto 5 construto r de c o pia Nome do aluno : Andr e Duarte Bueno Matr cula : 123 IAA : 0 Destruiu objeto 5 Destruiu objeto 4 Destruiu objeto 3 Destruiu objeto 2
323
v1 ptr v1.Saida() acessa o vetor que foi destrudo! v1 tenta destruir novamente o bloco CRASH! (c)
Destruiu objeto 1
Nota: a listagem F.2 apresenta um problema que est a associado ` a falta do construtor de c opia.
16.5.1
A Figura 16.1 mostra um problema t pico quando utilizamos atributos din amicos e esquecemos de implementar o construtor de c opia. O objeto v1 tem um ponteiro ptr que aponta para um bloco de mem oria que e alocado no construtor com new. Se criarmos um objeto v2 utilizando o construtor de c opia, o ponteiro v2.ptr vai apontar para o mesmo bloco de mem oria de v1.ptr (Figura 16.1(a)). O exemplo da listagem 16.2 mostra o problema. O exemplo e auto-explicativo. Na linha CVetor v1 (5); cria objeto do tipo CVetor, com nome v1 (Figura 16.1(a)), e, em seguida, mostra o vetor na tela. Na linha CVetor v2 = v1; cria o vetor v2, uma c opia de v1. Observe que v2.ptrV e v1.ptrV apontam para o mesmo bloco de mem oria (Figura 16.1(a)). Ap os executar v2.Saida(); o bloco em que v2 foi criado e destru do, e o destrutor de v2 e chamado. Note que o destrutor ir a deletar o bloco de mem oria (compartilhado) (Figura 16.1(b)). At e aqui nenhum problema. O problema ocorre quando chamamos v1.Saida(); O m etodo Saida() tenta acessar um bloco de mem oria que n ao existe mais; v1.ptrV aponta para um monte de lixo (Figura 16.1(c)). O que ocorre e indenido, provavelmente um bug a qualquer momento. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
324
Na mensagem de erro apresentada na sa da, o bug ocorre quando o destrutor de v1 e executado. O mesmo tenta destruir o bloco de mem oria compartilhado novamente. Listing 16.2: Problemas com a falta do construtor de c opia em objetos com atributos din amicos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 # include < iostream > using namespace std ; class CVetor { private : int dimensao ; int * ptrV ; public : void Saida () ; // Cria classe CVetor
// C o n s t r u t o r d e f a u l t e ao mesmo tempo com par^ a metros , // aloca o vetor d i n a m i c a m e n t e . CVetor ( int n = 10) : dimensao ( n ) { cout << " Construtor default de CVetor : " << endl ; ptrV = NULL ; ptrV = new int ( dimensao ) ; if ( ptrV == NULL ) { cerr << " \ nFalha aloca ca ~ o " << ends ; exit (0) ; // E n c e r r a o p r o g r a m a } for ( int i = 0; i < dimensao ; i ++) ptrV [ i ] = i ; // P r e e n c h e v a l o r e s do vetor } virtual ~ CVetor () // D e s t r u t o r { cout << " Destrutor do vetor : " << endl ; delete [] ptrV ; } }; void CVetor :: Saida () { for ( int i = 0; i < dimensao ; i ++) cout << " " << ptrV [ i ] << " " ; cout << endl ; } int main () { CVetor v1 (5) ; // Cria objeto do tipo CVetor , com nome v1 cout << " Sa da de v1 . Saida () " << endl ; v1 . Saida () ; // Mostra o vetor na tela { CVetor v2 = v1 ; // Cria v2 , uma c o pia de v1 cout << " Sa da de v2 . Saida () ap o s CVetor v2 = v1 " << endl ; v2 . Saida () ; } // v2 sai de escopo e e deletado cout << " Sa da de v1 . Saida () ap o s dele ca ~ o de v2 " << endl ; v1 . Saida () ; // Efeito i n e s p e r a d o return 0; } // v1 sai de escopo e e d e l e t a d o ( BUG ) Construto r do vetor : Sa da de v1 . Saida ()
325
A solu ca o para este problema e implementar manualmente o construtor de c opia, alocando a mem oria com new para os objetos din amicos (Figura 16.1(d)). Acrescente na classe CVetor (da listagem 16.2) o construtor de c opia apresentado a seguir. Observe que o novo objeto vai ter um vetor com a mesma dimens ao e os mesmos valores. Exemplo: CVetor::CVetor(const CVetor& obj) { // obj e this ter~ ao a mesma dimens~ ao this->dimensao = obj.dimensao; this->ptrV = NULL; // Cria um novo vetor para this this->ptrV = new int (this->dimensao); if(this->ptrV == NULL) { cerr < < "\nFalha aloca c~ ao" < < ends; exit(0);} // Copia os valores de v1 para this for(int i = 0; i < dimensao; i++) this->ptrV[i] = obj.ptrV[i]; } Nota: o objeto cerr e utilizado para enviar mensagens de erro para a tela, da mesma forma que cout. A diferen ca e que cerr n ao tem buer, sendo o texto enviado imediatamente para tela. A fun ca o exit(0) encerra a execu ca o do programa.
16.6
Vimos ao longo deste cap tulo uma s erie de m etodos construtores e destrutores. Uma pergunta que pode ser feita e: quando um objeto e criado e quando um objeto e destru do? Segundo [Lischner, 2003], as possibilidades s ao: Quando criamos um objeto autom atico. Exemplo: int x; CEndereco endereco; CAluno aluno; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
326
Quando criamos um objeto est atico. Exemplo: static int x; static CEndereco endereco; Quando criamos um objeto dinamicamente. Exemplo: const int dimensao = 10; int * ptrVetor = new int[dimensao]; Quando criamos objetos tempor arios. No exemplo a seguir a soma de 4+5 e armazenada em um objeto tempor ario, que e criado, usado para armazenar o valor 9, e, em seguida, usado para copiar o valor 9 para x. Vale lembrar que a cria ca o do objeto tempor ario e interna, transparente. Exemplo: int x = 4 + 5; Quando usamos retorno e par ametros de um m etodo. No exemplo a seguir quando entra no m etodo Metodo() o par ametro int x e criado. Quando o m etodo e encerrado, uma c opia de x e retornada. Exemplo: int CNomeClasse::Metodo(int x) {... return x; } Quando usamos convers oes impl citas. No exemplo a seguir, um n umero tempor ario do tipo int e criado e usado para armazenar o n umero 3 (o n umero utuante 3.1415 e truncado para 3); depois, este n umero tempor ario e copiado para x. Exemplo: int x = 3.1415; Quando usamos construtores com inicializadores. Exemplo: CCirculo::CCirculo(int _r,int _x,int _y): CPonto(_x,_y), r(_r){...} Todos os objetos anteriormente constru dos s ao destru dos quando os mesmos saem de escopo. A exce ca o ocorre quando usamos constru ca o din amica. Neste caso o objeto deve ser explicitamente destru do com delete.
16.6.1
A ordem de constru ca o dos atributos de uma classe e dada pela ordem em que os mesmos foram declarados, e n ao pela ordem passada para o construtor. Veja exemplo na listagem 16.3. Observe que a classe Y tem tr es atributos agregados do tipo X, e que os mesmos s ao declarados na ordem x1, x2, x3. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
327
A lista passada para o construtor da classe Y e dada por Y() : x2(2), x3(3), x1(1), mas observe na sa da que os objetos foram criados na ordem em que foram declarados; ou seja, vai criar x1 depois x2 e depois x3, mesmo que no construtor tenhamos colocado x2, x3, x1. Depois de construir seus atributos o construtor do objeto obj_y e executado. Listing 16.3: Ordem de constru ca o dos atributos de um objeto.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # include < iostream > using namespace std ; class X { public : X ( int n ) { cout << " Criou X : " << n << endl ; }; }; class Y { public : Y () : x2 (2) , x3 (3) , x1 (1) { cout << " Criou Y . " << endl ; }; private : X x1 , x2 , x3 ; // D e c l a r a os a t r i b u t o s na ordem x1 , x2 , x3 }; int main () { Y obj_y ; return 0; } Criou Criou Criou Criou X :1 X :2 X :3 Y.
16.6.2
Quando um objeto e criado, s ao criados os atributos internos e depois e executado o corpo do construtor. Os atributos internos s ao criados na ordem em que foram declarados (veja Se ca o 16.6.1). A seq u encia de destrui ca o e inversa ` a da cria ca o, isto e, primeiro e executado o m etodo destrutor e depois s ao eliminados os objetos internos da classe, na ordem inversa a que foram declarados. Se for criado um vetor de objetos de tamanho n, a seq u encia de cria ca o e obj[0], obj[1], obj[2],..., obj[n-1] e a seq u encia de destrui ca o obj[n-1], obj[n-2], obj[n-3],..., obj[1], obj[0]. Exemplo: class V { int n; int * ptr; V(int _n = 30):n(_n),ptr(0) { ptr = new int (n); }; ~V() { delete [] ptr; };
// Construtor // Destrutor
No exemplo anterior, dentro da fun ca o main() e criado um objeto do tipo V. Primeiro cria o atributo n e inicializa com 30 e, em seguida, cria o ponteiro ptr e inicializa com NULL. Depois e executado o corpo do construtor, que aloca mem oria para um vetor de 30 inteiros e armazena o endere co do bloco alocado em ptr. Quando o bloco de main() termina os objetos criados s ao destru dos, logo, o destrutor do objeto e executado. Na seq u encia de destrui ca o, primeiro e executado o corpo do destrutor, que deleta o conte udo do ponteiro; em seguida e eliminado o atributo ptr e posteriormente o atributo n. Observe que a ordem de destrui ca o e inversa a de constru ca o. A melhor maneira de entender a seq u encia de cria ca o e destrui ca o dos objetos e acompanhar a execu ca o passo a passo do programa em um debugger. No Dev-C++ (veja Figura 6.27), usa-se tulo ?? Como Evitar Bugs e Utilizar o Debuger da GNU (gdb), a fun ca o f7. Veja, no Cap como usar o debugger da GNU.
16.6.3
Lembre-se de que um objeto global e um objeto criado fora do escopo das classes e fun co es globais. Exemplo: ..escopo global.. Retorno FuncaoGlobal(parametros){..escopo da fun c~ ao global..} ..escopo global.. class CNomeClasse{...escopo da classe..}; ..escopo global.. Retorno CNomeClasse::Metodo(parametros){..escopo do m etodo..} ..escopo global.. int main() {..escopo de main()..} Objetos globais est aticos s ao criados quando o programa e carregado (antes de main()) e destru dos quando o programa e encerrado. Isto signica que podemos criar uma fun ca o global e execut a-la antes de main() para iniciar um objeto est atico. Veja exemplo na listagem 16.4. Listing 16.4: Objetos est aticos globais.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # include < iostream > int f () // Fun c~ a o Global { std :: cout << " Executada antes de main () . " << std :: endl ; return 0; } // x e uma v a r i a v e l global e s t atica static int x = f () ; // que e i n i c i a l i z a d a com o r e t o r n o de f () int main () { std :: cout << " Ol a " << std :: endl ; return 0; }
329
16.7
Uma ambig uidade ocorre quando o compilador n ao consegue identicar qual atributo ou m etodo deve ser acessado. O exemplo a seguir mostra uma ambig uidade hipot etica do dia-adia. Exemplo: /* Al o, com quem deseja falar? Com o Fernando. Mas qual Fernando, o Henrique ou o Collor?. */ De modo geral ocorrer a ambig uidade quando, no mesmo escopo, tivermos atributos ou m etodos com o mesmo nome. A verica ca o de ambig uidade e feita antes do controle de acesso, assim, o compilador primeiro verica se o objeto n ao e amb g uo e depois se pode ser acessado (Se ca o 14.3.1). As ambig uidades podem ser resolvidas explicitamente com o operador de resolu ca o de escopo (::) ou com o uso da palavra-chave using (Se ca o 10.3). Ao tentar compilar o exemplo da listagem 16.5, aparece uma mensagem de erro. Na linha (11) "X obj1(5);" o compilador cria o objeto obj1 usando o construtor sobrecarregado. Na linha (12) "X obj2;" o compilador ca em d uvida deve usar o construtor default ou o construtor sobrecarregado? A solu ca o deste problema e um dos exerc cios deste cap tulo. Listing 16.5: Erro ao denir o construtor default e um construtor sobrecarregado com inicializadores.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class X { int x ; public : // Sejam os c o n s t r u t o r e s : X () { }; // C o n s t r u t o r _ 1 ( d e f a u l t ) X ( int _x = 0) { x = _x ; }; // C o n s t r u t o r _ 2 ( s o b r e c a r r e g a d o ) }; int main () { X obj1 (5) ; X obj2 ; return 0; }; : In :14: :8: :7: function int main () : error : call of overloade d X () is ambiguous note : candidates are : X :: X ( int ) note : X :: X ()
// // // //
Se na t e n t a t i v a de criar um objeto voc^ e faz : Cria objeto 1 , usa c o n s t r u t o r _ 2 Ambig u idade , qual c o n s t r u t o r ? X () ou X ( int _x =0)
16.8
Nesta se ca o veremos alguns conceitos avan cados de construtores e destrutores. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
330
16.8.1
Por deni ca o do comite ANSI C++, quando o compilador ca em d uvida se uma determinada linha de c odigo signica a declara ca o de uma nova fun ca o ou a cria ca o de um objeto, por padr ao, assume que o programador est a declarando uma nova fun ca o e n ao criando um novo objeto. A listagem 16.6 mostra um exemplo. O programa inicia denindo uma classe T (observe que, quando o construtor e executado, ele envia uma sa da para tela). Em seguida mostra o problema das ambig uidades. A linha (18) T f1(); declara uma fun ca o f1() que n ao recebe nada e retorna T ou cria um objeto f1 do tipo T? Obedecendo o padr ao, estamos declarando uma fun ca o f1() que retorna T. A linha (21) T (obj1); cria um novo objeto, do tipo T, com nome obj1. A linha (26) T obj2(1); cria um novo objeto, do tipo T, com nome obj2, e usa construtor que recebe um int. A linha (34) T f3(T(x)); declara uma fun ca o f3(). Observe que podemos informar que queremos criar um objeto usando o cast (T obj3(static_cast<T>(x));). Listing 16.6: Construindo objetos ou declarando fun co es?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 // A m b i g u i d a d e : C o n s t r u i n d o o b j e t o s ou d e c l a r a n d o f u n c~ o e s? # include < iostream > class T // Cria uma classe T { // Acesso p ublico public : // C o n s t r u t o r e s T () { std :: cout << " \ tConstrut or T () \ n " ; } T ( int ) { std :: cout << " \ tConstrut or T ( int ) \ n " ; } }; int main () { int x ; // Fun c~ ao principal // Cria objeto do tipo int , com nome x
// A m b i g u i d a d e ? // D e c l a r a fun c~ a o f1 () , que n~ a o recebe nada e r e t o r n a T ? ou // Cria objeto f1 do tipo T ? std :: cout << " T f1 () ; -> Declara ca ~ o de fun ca ~ o . " << std :: endl ; T f1 () ; std :: cout << " T ( obj1 ) ; -> Cria obj1 , usa construtor T () " << std :: endl ; T ( obj1 ) ; // A m b i g u i d a d e ? std :: cout << " T obj2 (1) ; -> Cria objeto obj2 , do tipo T , " << " usa construtor T ( int ) " << std :: endl ; T obj2 (1) ; std :: cout << " T f2 ( int ) ; -> Declara fun ca ~ o f2 , retorna T , " << " argumento int sem nome " << std :: endl ; T f2 ( int ) ; // A m b i g u i d a d e ? std :: cout << " T f3 ( T ( x ) ) ; - > Declara fun ca ~ o f3 , retorna T , " << " e recebe T " << std :: endl ; T f3 ( T ( x ) ) ; std :: cout << " T obj3 ( static_cast <T >( x ) ) ; " << " -> Cria objeto obj3 , do tipo T " << std :: endl ; T obj3 ( static_cast <T >( x ) ) ; std :: cout << std :: endl ; return 0; }
331
T f1 () ; -> Declara ca ~ o de fun ca ~o . T ( obj1 ) ; -> Cria obj1 , usa construtor T () Construtor T () T obj2 (1) ; -> Cria objeto obj2 , do tipo T , usa construtor T ( int ) Construtor T ( int ) T f2 ( int ) ; -> Declara fun ca ~ o f2 , retorna T , argumento int sem nome T f3 ( T ( x ) ) ; - > Declara fun ca ~ o f3 , retorna T , e recebe T T obj3 ( static_cast <T >( x ) ) ; -> Cria objeto obj3 , do tipo T Construtor T ( int )
16.8.2
Construtor e interface
Em alguns casos a classe e denida corretamente, mas um usu ario distra do pode criar o objeto de forma incorreta. Veja exemplo na listagem 16.7. Observe que o objeto e criado com o nome da cidade e da pessoa trocados. Um erro n ao detectado pelo compilador, porque nome e cidade s ao do tipo string, e o compilador diferencia os tipos e n ao os nomes. Este erro ocorre porque a interface (ou protocolo) de acesso ao construtor n ao impede que o usu ario entre com dados trocados. Listing 16.7: Construtor e interface: erro na passagem de par ametros.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # include < iostream > # include < string > using namespace std ; class CPessoa { int idade ; string nome ; string cidade ; public : CPessoa ( int i , string n , string c ) : idade ( i ) , nome ( n ) , cidade ( c ) {} }; int main () { // Erro na ordem de p a s s a g e m dos p a r ^ ametros CPessoa joao (32 , " Rio de Janeiro " , " Jo~ a o da Silva " ) ; return 0; }
Pode-se contornar este problema usando classes ou estruturas auxiliares. Veja o exemplo da listagem 16.8. Usamos struct porque SNome e SCidade n ao representam conceitos; s ao apenas estruturas auxiliares utilizadas para eliminar o problema. O uso de explicit ser a apresentado na Se ca o 25.5. Basicamente explicit garante que o construtor s o seja chamado explicitamente. Listing 16.8: Construtor e interface: erro na passagem de par ametros corrigidos.
1 2 3 4 5 6 7 8 9 10 # include < iostream > # include < string > using namespace std ; struct SNome { explicit SNome ( string n ) : nome ( n ) {}; string nome ; };
332
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
struct SCidade { explicit SCidade ( string c ) : cidade ( c ) {}; string cidade ; }; class CPessoa { int idade ; string nome ; string cidade ; public : CPessoa ( int i , SNome n , SCidade c ) : idade ( i ) , nome ( n . nome ) , cidade ( c . cidade ) {} }; int main () { // Erro na p a s s a g e m de p a r ^ ametros corrigida // agora a p a s s a g e m dos p a r ^ a m e t r o s ficou mais clara CPessoa joao (32 , SNome ( " Jo~ a o da Silva " ) , SCidade ( " Rio de Janeiro " ) ) ; return 0; }
Veja a seguir outras dicas para classes de interface (reveja Se ca o 11.5.2): A interface de acesso a classe deve ser simples, pr atica e l ogica. Deve ter um controle rigoroso da entrada e sa da de dados (limites m nimos e m aximos de cada atributo). Os operadores-padr ao devem ser sobrecarregados (veja Cap tulo 21 Sobrecarga de Operador). As classes derivadas devem ter uma interface com a mesma l ogica da classe-base.
16.9
Um objeto autom atico e constru do na sua deni ca o e destru do quando sai de escopo. // Objeto x e constru do // Objeto x sai de escopo e e destru do
Ao criar um vetor est atico de objetos, voc e e obrigado a utilizar o construtor default. Para utilizar um outro construtor, voc e ter a de criar os objetos um a um dinamicamente. No exemplo a seguir, utiliza-se um construtor sobrecarregado, que recebe uma lista de par ametros. Observe que os objetos s ao criados um a um, dinamicamente, dentro do for. Exemplo: CNomeClasse { public: CNomeClasse(){}; // Construtor default }; // Cria vetor est atico, com 30 objetos CNomeClasse vObjetos[30]; // Cria vetor com 50 ponteiros Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
16.9. SENTENCAS PARA CONSTRUTORES E DESTRUTORES CNomeClasse* vptrObj[50]; for ( int i = 0 ; i < 50 ; i++ ) vptrObj[i] = new CNomeClasse (parametros);
333
Em determinados casos e conveniente termos um m etodo de inicializa ca o, um m etodo utilizado para inicializar os atributos da classe e que pode ser chamado a qualquer momento para reinicializar os atributos com valores-padr ao, exemplo: Init();. Atributos est aticos da classe devem ser denidos fora da classe. Bugs um objeto autom atico, criado na avalia ca o de uma express ao, e destru do no m do bloco (ou do m etodo). Assim, n ao armazene nenhuma informa ca o (ponteiro, refer encia) em objetos autom aticos. O exemplo a seguir mostra um erro comum. Exemplo: int* f() { int x = 3; int * ptrX = &x; return ptrX; } // Aqui x e destru do e ptrX aponta para o lixo (um bug). Todos os atributos do objeto devem ser copiados um a um no construtor de c opia. Se um novo atributo for adicionado ` a classe, n ao esque ca de incluir sua c opia no construtor de c opia. A utiliza ca o de uma lista de inicializa ca o como no exemplo que segue n ao e permitida se voc e criou um construtor com par ametros e n ao existe um construtor default . Exemplo: Tipo a[] = { v1, v2, ..., vn }; Lembre-se de que o operador delete primeiro chama o m etodo destrutor do objeto e, em seguida, devolve a mem oria para o sistema operacional. Um objeto criado com new deve ser apagado com delete. N ao destruir um objeto alocado dinamicamente n ao causa um erro (bug ), mas e um desperd cio de mem oria. 2 O construtor de c opia e o operador de atribui ca o da classe derivada devem chamar o m etodo equivalente da classe-base. Veja o exemplo: Exemplo: Derivada& operator=( const Derivada& d ) { Base::operator=(d); this->atributo = d.atributo; } 2 O construtor de uma classe-derivada chama automaticamente o destrutor da classe-base. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
334
2 O corpo de um destrutor e executado antes dos destrutores para os objetos membros. De maneira geral, a ordem de destrui ca o dos objetos e inversa ` a ordem de constru ca o (veja Se co es 16.6.2). 2 Como regra b asica, sempre declare o destrutor como virtual (veja Se ca o 19.2). 2 Se durante a execu ca o do programa e chamada a fun ca o exit(), os destrutores locais n ao ser ao executados e os globais sim. Se for chamada a fun ca o abort(), nenhum destrutor ser a executado. 2 Destrutores n ao devem lan car exce co es. Se um m etodo chamado pelo destrutor pode chamar uma exce ca o, o tratamento deve ser feito no destrutor. 2 O destrutor, assim como o construtor, n ao deve chamar m etodos virtuais. 2 Como vimos, quando n ao criamos um construtor, o compilador cria um. O mesmo ocorre para o construtor de c opia, o operador de atribui ca o e o destrutor. Todos esses m etodos, quando criados pelo compilador, s ao m etodos inline [Lischner, 2003]. 2 Se voc e criou um construtor de c opia, um operador de atribui ca o, ou um destrutor, ent ao voc e provavelmente precisa criar todos os tr es [Lischner, 2003]. Isto ocorre normalmente quando a classe tem membros de dados din amicos. 2 As classes containers da STL e a classe string n ao t em um destrutor virtual. Assim, tome cuidado no uso de heran ca dessas classes. No exemplo a seguir, delete ptr invoca o destrutor de string e n ao de MinhaString. Exemplo: class MinhaString: public std::string {...}; string * ptr = new MinhaString(); delete ptr; 2 Por default, se um construtor de uma classe X recebe um u nico argumento do tipo Y, este tamb em dene uma convers ao de Y para X. Para evitar a convers ao autom atica, use a palavra-chave explicit (veja Se ca o 25.5).
16.10
Vimos que o m etodo construtor e utilizado para inicializar os atributos do objeto, podendo ainda realizar alguma atividade extra. Quando n ao criamos um construtor, o compilador cria um construtor vazio chamado construtor default, o qual n ao recebe nenhum par ametro. Vimos ainda que o construtor pode ser sobrecarregado, isto e, podemos ter mais de um construtor. Vimos que a implementa ca o do construtor de c opia, T(const T& obj), e importante principalmente quando o objeto tem atributos din amicos. Aprendemos a inicializar os atributos do objeto no construtor. A inicializa ca o dos atributos ap os : e mais r apido que a inicializa ca o dentro do bloco do construtor. Aprendemos ainda que a ordem de constru ca o dos atributos e a ordem em que os mesmos foram declarados. O destrutor faz o trabalho inverso, destr oi o objeto. Aprendemos que o m etodo destrutor deve ser u nico, de prefer encia virtual, e deve ser utilizado para destruir os atributos e nalizar o objeto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
335
Aprendemos que a ordem de destrui ca o dos atributos de um objeto e inversa ` a ordem de constru ca o. Finalmente, aprendemos conceitos como ambig uidade e interface. Vimos que podemos eliminar problemas com a passagem dos par ametros do construtor usando estruturas de interface.
16.11
Exerc cios
1. Na listagem 16.1 acrescente um construtor que recebe todos os atributos do objeto. Com ele elimina-se a necessidade de se chamar os m etodos Set(). 2. Modique a listagem 16.1 acrescentando novos atributos. Por exemplo, acrescente o uso de CEndereco. 3. Comente em detalhes a listagem 16.2. 4. Acrescente a listagem 16.2 as corre co es indicadas na Se ca o 16.5.1. 5. Releia a listagem 13.3. 6. Releia a Se ca o 16.7 e corrija o problema da listagem 16.5. 7. Indique duas op co es para eliminar a ambig uidade na listagem 16.5. A seguir, implemente as modica co es sugeridas. 8. Modique a listagem 13.3 substituindo Inicializa() por um construtor. 9. Arrume a listagem 16.3 chamando os objetos na ordem em que s ao declarados. Em seguida, veja a sa da gerada. 10. Como os construtores podem ser sobrecarregados, podemos ter v arias formas para construir um objeto. Alguns programadores gostam de fornecer uma alternativa que passa pela deni ca o de todos os construtores como privados e o acesso a cada um deles usando um m etodo est atico e p ublico com nome diferente. Este m etodo e conhecido como Named Constructor Idiom. Como exerc cio, fa ca uma pesquisa por Named Constructor Idiom no Google. 11. Se um objeto do tipo CNome e constru do estaticamente no escopo global, ent ao ele e executado antes de main(). Isto deve ser evitado, pois se o construtor de CNome criar outros objetos est aticos, ent ao n ao existe garantia de que a seq u encia de cria ca o seja correta. Como exerc cio, fa ca uma pesquisa por Construct on First Use Idiom no Google.
336
Cap tulo 17
Heran ca
Vimos nas se co es 3.6 e 6.4.10 o conceito de heran ca; na Se ca o 6.4.10, vimos como identicar heran cas e na Se ca o 6.4.11, como descrever a heran ca usando UML. Neste cap tulo veremos como implementar heran cas em C++. Veremos o prot otipo para heran ca (Se ca o 17.1), o uso de heran ca simples (Se ca o 17.2) e o uso do especicador de heran ca (Se ca o 17.3). Ademais, veremos as diferen cas entre heran ca p ublica e heran ca privada (Se ca o 17.4); como usar using em heran cas (Se ca o 17.5); como chamar os construtores das classes-base explicitamente (Se ca o 17.6); a redeclara ca o de m etodo ou atributo na classe-derivada (Se ca o 17.7) e algumas senten cas para heran ca (Se ca o 17.8). No Cap tulo 18 Heran ca M ultipla, veremos como implementar o conceito de heran ca m ultipla.
17.1
O conceito de heran ca permite a cria ca o de uma classe-derivada a partir de uma classebase. A classe-derivada herda todos os atributos e m etodos da classe-base. Neste cap tulo vamos apresentar a utiliza ca o do conceito de heran ca em C++. Veja a seguir o prot otipo para implementar heran ca em C++: Nota: seria interessante neste momento voc e reler a Se ca o 3.6. Prot otipo: // Arquivo Base.h class Base { // Deni ca o dos atributos e m etodos da classe-base }; // Arquivo Derivada.h #include Base.h class Derivada: especicadorDeHeran ca Base // veja se co es 17.2 e 17.3 { // Deni ca o dos atributos e m etodos da classe-derivada }; 337
338
17.2
Observe no prot otipo anterior a linha, class Derivada: especificadorDeHeran ca Base Nessa linha, informa-se que a classe-derivada e herdeira da classe-base. Como s o temos uma classe-base temos uma heran ca simples. O especicador de heran ca dene a forma como a classe-derivada pode acessar os atributos e m etodos da classe-base. O uso do especicador de heran ca e detalhado na Se ca o 17.3. Veja na Figura 17.1 o diagrama UML da classe CCirculo e, na listagem 17.1, seu c odigo. A classe CCirculo e herdeira da classe CPonto.
CPonto
+x: int +y: int +contador: static int +Desenha(): virtual void
CCirculo
+r1: int +Desenha(): virtual void
Figura 17.1: Heran ca simples: CPonto e CCirculo. Observe a forma como e declarada a heran ca da classe CCirculo com a classe CPonto. class CCirculo : public CPonto A classe CCirculo cria o atributo r1 e inclui o m etodo R1(). Agora preste aten ca o no construtor da classe CCirculo e observe a chamada do construtor da classe-base CPonto. A classe CCirculo chama explicitamente o construtor da classe CPonto para passar os atributos x e y. CCirculo(int _x,int _y, int _raio) : CPonto(_x,_y), r1(_raio) {}; Alguns m etodos Set() de CPonto s ao sobrecarregados (mesmo nome, mas par ametros diferentes). Observe no m etodo CCirculo::Set(CCirculo& C) que a classe CCirculo pode acessar os atributos x e y diretamente, pois esses foram herdados da classe CPonto. Note no m etodo inline void Set (int _x, int _y, int raio); que podemos chamar CPonto::Set ( x, y); da classe-base. Observe que o m etodo Desenha() e declarado como sendo virtual. Veremos os m etodos virtuais na Se ca o 19.2. Listing 17.1: A classe CCirculo.
1 2 3 4 # ifndef CCirculo_h # define CCirculo_h # include " CPonto . h " // C o m p i l a c~ ao condicional // Inclui classe - base
339
public : // Construtor , o b s e r v e que p r i m e i r o passa para o c o n s t r u t o r da classe - base // os a t r i b u t o s x e y , e a seguir define r1 . CCirculo ( int _x , int _y , int _raio ) : CPonto ( _x , _y ) , r1 ( _raio ) { }; // M e todo Set () Seta a t r i b u t o s do c i r c u l o x , y e raio inline void Set ( int _x , int _y , int raio ) { CPonto :: Set ( _x , _y ) ; // Chama Set () da classe - base this - > r1 = raio ; // Uso de this e opcional } // Seta a t r i b u t o s do c i r c u l o a partir de um ponto e um raio . inline void Set ( CPonto & p , int _raio ) { x = p . X () ; y = p . Y () ; r1 = _raio ; } // Seta a t r i b u t o s do c i r c u l o a partir de outro c i r c u l o inline void Set ( CCirculo & c ) { this - > x = c . x ; this - > y = c . y ; this - > r1 = c . r1 ; } int R1 () const { return r1 ; }; virtual void Desenha () ; }; # endif
Veja na listagem 17.2 a implementa ca o da classe CCirculo, a qual redene o m etodo Desenha(). Note que na implementa ca o de Desenha() chamamos o m etodo Desenha() da classebase CPonto::Desenha() e fazemos mais alguma coisa, ou seja, CCirculo vai executar Desenha() de uma forma diferente. Listing 17.2: Implementa ca o da classe CCirculo.
1 2 3 4 5 6 7 8 9 # include < iostream > # include " CCirculo . h " // U t i l i z a o m e todo D e s e n h a da classe - base e a c r e s c e n t a o d e s e n h o do c rculo void CCirculo :: Desenha () { CPonto :: Desenha () ; // Chama m e todo da classe - base std :: cout << " \ nTCirculo : Coordenada r1 = " << r1 << std :: endl ; }
17.3
Especicador de heran ca
O especicador de heran ca altera a forma como se processa a heran ca, alterando o tipo de acesso herdado. Pode-se utilizar os especicadores public, protected e private. Veja o Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
340 prot otipo a seguir. Prot otipo: class Derivada: public Base {}; class Derivada: protected Base {}; class Derivada: private Base {};
O acesso aos membros da classe-base ir a depender do especicador de heran ca (public, protect e private) e dos especicadores de acesso na classe-base (public, protect e private). A Tabela 17.1 mostra o acesso herdado. Na primeira coluna, o especicador de acesso utilizado na classe-base; na segunda, o especicador de heran ca; e na terceira, o acesso efetivamente herdado. Observe na primeira linha da Tabela que, se o atributo e public e o especicador de heran ca tamb em, o acesso herdado e public; e se o atributo e protected e o especicador de heran ca e private, o acesso herdado ser a private. Observe que C++ utiliza as palavras-chave public, protected e private com dois objetivos: o primeiro, especicar a forma de encapsulamento dos atributos do objeto (veja Se ca o 11.2); o segundo, especicar a forma da heran ca. Tabela 17.1: Acesso herdado Especicador de acesso na classe-base public protected private public protected private public protected private Especicador de heran ca public public public protected protected protected private private private Acesso herdado public protected inacess vel protected protected inacess vel private private inacess vel
Vamos esclarecer a utiliza ca o do especicador de acesso na classe-base e do especicador de heran ca por meio da listagem 17.3. Este exemplo cont em erros, os quais s ao detectados pelo compilador. Veja a sa da. Listing 17.3: Usando especicador de acesso e de heran ca.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # include < iostream > using namespace std ; class Base { public : int x ; protected : int y ; private : int z ; }; class DerivadaA : public Base { public : int X () { return x ; }; int Y () { return y ; }; int Z () { return z ; };
341
}; }; };
especificador - heranca . cpp : In member function int DerivadaA :: Z () : especificador - heranca . cpp :8: error : int Base :: z is private especificador - heranca . cpp :16: error : within this context especificador - heranca . cpp : In member function int DerivadaB :: Z () : especificador - heranca . cpp :8: error : int Base :: z is private especificador - heranca . cpp :24: error : within this context make : ** [ especificador - heranca . o ] Erro 1
17.4
Se a heran ca e p ublica, um objeto D da classe-derivada e um tipo de objeto da classe-base, ou seja, quando necess ario, o compilador converte o objeto D em um objeto do tipo B. Quando a heran ca e privada, tal convers ao n ao e realizada [Meyers, 2005]. Logo, se voc e quer implementar uma rela ca o do tipo e um, a heran ca deve ser p ublica. A heran ca privada e usada ent ao para reaproveitamento de c odigo; por exemplo, use heran ca privada se precisar reaproveitar membros protegidos ou renar m etodos virtuais [Meyers, 2005]. Na maioria dos casos a heran ca privada pode ser substitu da por uma composi ca o. O uso de heran ca privada ou sua substitui ca o por composi ca o e uma decis ao de projeto.
17.5
Vimos o uso da palavra-chave using na Se ca o 10.3. Podemos utilizar a palavra-chave using para mudar a visibilidade (p ublica, protegida) dos membros de uma classe em heran cas. Veja o exemplo da listagem 17.4. Observe na sa da que podemos transformar um membro protected em public, mas n ao podemos mudar um membro private. Para que a mensagem de erro apare ca, voc e deve tirar o coment ario da linha // private. Listing 17.4: Usando using em heran cas.
1 2 3 4 5 6 7 8 9 10 11 12 # include < iostream > class Base { protected : const static int x = 123456; // p r i v a t e: const static int y = 789; }; class Derivada : public Base { public :
342
13 14 15 16 17 18 19 20 21 22 23
int main () { Derivada d ; std :: cout << " d . x = " << d . x << std :: endl ; // ok std :: cout << " d . y = " << d . y << std :: endl ; // Erro return 0; } d . x = 123456 d . y = 789 [ b u e n o @ l d s c 0 5 ] $ g ++ U s a n d o U s i n g E m H e r a n c a s . cpp U s a n d o U s i n g E m H e r a n c a s . cpp :7: error : const int Base :: y is private U s a n d o U s i n g E m H e r a n c a s . cpp :11: error : within this context
17.6
Se a classe-base B s o tem construtores com par ametros (n ao tem o construtor default , Se ca o 16.3), a classe-derivada D deve chamar explicitamente um dos construtores de B. Veja o exemplo: Exemplo: class B { int a1, a2; public: // Declara c~ ao do construtor (n~ ao tem construtor default ) B(int a1, int a2); }; // Defini c~ ao do construtor da classe B B::B(int _a1, int _a2): a1(_a1), a2(_a2){}; class D: public B { int a3; public: D(int a1,int a2,int a3); }; // Defini c~ ao do construtor da classe D. // Observe a chamada do construtor de B passando os par^ ametros _a1 e _a2 D::D(int _a1,int _a2,int _a3):B(_a1,_a2),a3(_a3) {};
17.7
No Cap tulo 3 Conceitos B asicos de POO, vimos que uma classe-derivada herda os atributos e os m etodos da classe-base, e que a forma como tudo acontece na classe-derivada e um pouco diferente da que ocorre na classe-base. Para que os objetos derivados sejam efetivamente diferentes, por em, voc e precisa redeclarar e redenir alguns m etodos da classe-base ou acrescentar novos m etodos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
343
A classe-derivada pode acrescentar novos m etodos ou alterar os m etodos da classe-base. Podemos ter dois casos: no primeiro, a classe-derivada realiza a mesma opera ca o que a classe-base, mas de uma outra forma. No segundo, a classe-derivada realiza a mesma opera ca o da classe-base e algo mais. Isto signica que a classe-derivada pode reescrever totalmente o m etodo herdado ou pode chamar o m etodo da classe-base e depois acrescentar algo mais (veja m etodo Set(int,int,int) da listagem 17.1). Se voc e criar um atributo na classe-derivada com o mesmo nome de um atributo da classe-base, o atributo da classe-base continuar a existindo, mas para acess a-lo, voc e dever a utilizar o operador de resolu ca o de escopo (::). Veja listagem 17.5. Exemplo: NomeClasseBase::nomeAtributoRedeclarado; Se voc e redeclarar um m etodo na classe-derivada, este oculta o m etodo de mesmo nome da classe-base. O m etodo da classe-base pode ser acessado utilizando-se o operador de resolu ca o de escopo. Exemplo: NomeClasseBase::nomeM etodoRedeclarado(); 2 N ao confundir redeclara ca o (m etodo com mesmo nome e par ametros na classe-derivada) com utiliza ca o de sobrecarga de m etodos (m etodos com mesmo nome, mas com n umero ou tipos dos par ametros diferentes) ou com a utiliza ca o de m etodos virtuais (m etodo com mesmo nome e par ametros, mas com especicador virtual). Listing 17.5: Redeclara ca o de m etodo ou atributo na classe-derivada.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # include < iostream > int x = 0; // V a r i a v e l global - escopo global class B { public : const int x ; B () : x (1) { std :: cout << << << << } }; class D : public B { public : const int x ; D () : x (2) { std :: cout << << << << } }; int main () {
// Escopo da classe B " \ n \ tIn cio do construtor de B ( escopo de B ) : " " \ n \ t :: x = " << :: x " \ n \ tx = " << x " \ n \ tFim do construtor " << std :: endl ;
// Escopo da classe D // Oculta x da classe - base " \ n \ tIn cio do construtor de D ( escopo de D ) : " " \ n \ t :: x = " << :: x " \ n \ tx = " << x " \ n \ tB :: x = " << B :: x << std :: endl ;
344
30 31 32 33 34 35 36 37 38 std :: cout B obj_b ; std :: cout D obj_d ; std :: cout return 0; } Fun ca ~ o main () ( escopo de main () ) : :: x =0
std :: endl ;
In cio do construto r de B ( escopo de B ) : :: x =0 x =1 Fim do construto r obj_b . x =1 In cio do construto r de B ( escopo de B ) : :: x =0 x =1 Fim do construto r In cio do construto r de D ( escopo de D ) : :: x =0 x =2 B :: x =1 obj_d . x =2
17.8
A classe-base de uma hierarquia tamb em e chamada de classe-pai ou de superclasse. As demais classes s ao denominadas classes-derivadas, subclasses ou classes-lho. A maior diculdade em uma hierarquia e modelar com clareza as classes e seus relacionamentos. Observe que a classe-derivada n ao altera em nada a classe-base, de forma que, se a classederivada for alterada, somente ela precisar a ser recompiladaA utiliza ca o de protected e private deixa o c odigo mais encapsulado e, portanto, mais facilmente depurado. Uma classe vazia pode ser utilizada temporariamente quando o programador quer criar uma classe-base, mas ainda n ao identicou as rela co es entre as classes-derivadas. Uma classe vazia pode criar objetos. Note que, nestes casos, voc e tamb em pode criar uma classe de interface (Se ca o 11.5.2). Em uma heran ca e aconselh avel que um m etodo construtor chame os m etodos construtores ancestrais para a declara ca o dos atributos ancestrais, em vez de atribuir ele mesmo esses atributos (Se ca o 17.6). Se a heran ca e publica voc e tem um tipo de, ou seja, a classe-derivada cria um tipo de objeto que pode ser utilizado no lugar de um objeto da classe-base. M etodos da hierarquia podem ser desabilitados colocando-os como private. Ao colocar o m etodo como private, ele n ao poder a mais ser acessado (sendo desabilitado o acesso ao mesmo). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
345
Objetos (nomes) criados em um escopo local, de fun ca o ou m etodo, ocultam objetos com mesmo nome criados no escopo global ou de classe, mesmo sendo de tipos diferentes. Em heran cas isto tamb em ocorre. Um atributo ou m etodo com mesmo nome em uma classe-derivada oculta o atributo/m etodo da classe-base (Se ca o 17.7). Em uma hierarquia as classes devem ter operadores de convers ao (veja Cap tulo 25 Convers oes). Segundo [Parga, 2006], heran ca e um tipo de relacionamento de alto acoplamento, posto que altera co es realizadas na superclasse s ao reetidas em toda hierarquia abaixo dela. Sendo assim, a cria ca o de uma hierarquia de classes muito profunda torna o sistema extremamente sens vel a altera co es, fazendo com que sua manuten ca o que dif cil. 2 Em uma hierarquia, se um m etodo e reescrito nas classes-derivadas, ele deve ser virtual. 2 O operador de atribui ca o e os construtores da classe-base n ao s ao herdados pelas classesderivadas, ou seja, todas as classes devem ter construtores default e de c opia, destrutores virtuais e operadores sobrecarregados. 2 A utiliza ca o de classes, heran ca e m etodos virtuais e a base para o polimorsmo, que possibilita o desenvolvimento de sistemas complexos (veja Cap tulo 19 Polimorsmo). 2 Em uma hierarquia de classes, os destrutores devem ser virtuais. Se voc e tiver heran ca e destrutores n ao virtuais, na destrui ca o de um objeto din amico o destrutor que ser a executado e o denido pelo tipo do ponteiro utilizado.
2
Um ponteiro para classe-derivada pode acessar um m etodo da classe-base [Meyers, 2005]. Derivada* ptr = new Derivada(); ptr->Base::Desenhar();
3 Em uma heran ca, se os m etodos virtuais t em par ametros predenidos, eles devem ser iguais em toda hierarquia, pois os argumentos predenidos s ao denidos em tempo de compila ca o. 3 Atributos, m etodos privados e m etodos n ao virtuais s ao invariantes para as classesderivadas [Meyers, 2005]. 3 Em heran cas, m etodos virtuais podem ser substitu dos por m etodos que recebem ponteiros para fun co es. Voc e tamb em pode utilizar a classe utilit aria da biblioteca boost (std::tr1::function). Veja Cap tulo ??.
17.9
Nesce cap tulo aprendemos a implementar o conceito de heran ca simples em C++. Basicamente, basta incluir, ap os o nome da classe, o trecho de c odigo : public Base. Vimos que podemos ter heran ca p ublica, protegida ou privada. Lembre-se de que, para ser um tipo de, a heran ca deve ser p ublica. Isto signica que heran cas protegidas e privadas s ao pouco utilizadas. Aprendemos que quando a classe-base n ao tem um construtor default, o construtor existente deve ser explicitamente chamado. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
346
Aprendemos que a redeclara ca o de atributos na classe-derivada deve ser evitada, pois teremos dois atributos com o mesmo nome, mas em escopos diferentes. J a a redeclara ca o de m etodos e normal quando o m etodo e virtual. No Cap tulo 18 Heran ca M ultipla, veremos como implementar o conceito de heran ca m ultipla em C++.
17.10
Exerc cios
1. Use o debuger da GNU (gdb ou ddd) para rodar passo a passo as listagens com heran ca simples e heran ca m ultipla. Veremos os depuradores nos cap tulos ?? Uma Introdu ca o aos Bugs e a Debugagem de Programas e ?? Os Programas gdb, ddd e o bugzilla. 2. Corrija a listagem 17.3, incluindo m etodos X()/X(int), Y()/Y(int), Z()/Z(int) para os atributos x, y, z. 3. Comente a listagem 17.5 4. Desenhe e implemente uma hierarquia com as classes CQuadrado, CRetangulo, CTriangulo, CTrapezio utilizando o conceito de heran ca.
Cap tulo 18
Heran ca M ultipla
Na Se ca o 3.6, vimos a deni ca o de heran ca e heran ca m ultipla, e na Se ca o 6.4.11, como UML modela o conceito de heran ca m ultipla. No Cap tulo 17 Heran ca, vimos como implementar o conceito de heran ca em C++. Veremos neste cap tulo uma introdu ca o e o prot otipo para implementar heran ca m ultipla (Se ca o 18.1), al em de uma introdu ca o ao conceito de heran ca m ultipla em C++ (Se ca o 18.2). Veremos tamb em como resolver os problemas de ambig uidade em heran ca m ultipla (Se ca o 18.3), o uso de heran ca m ultipla com base comum (Se ca o 18.4), a ordem de cria ca o e destrui ca o dos objetos em uma heran ca (Se ca o 18.5) e a heran ca m ultipla virtual (Se ca o 18.6).
18.1
Vimos na Se ca o 3.6 o conceito de heran ca e heran ca m ultipla. Neste cap tulo veremos como implementar heran ca m ultipla em C++. A heran ca m ultipla ocorre quando uma classe tem mais de um pai, isto e, quando uma classe-derivada e herdeira de mais de uma classe-base; ocorre em muitos casos reais, quando um objeto n ao e composto de outros objetos, mas de uma evolu ca o de outros objetos, ou seja, dois ou mais objetos foram unidos para criar um novo, e o objeto novo n ao pode ser identicado como sendo uma agrega ca o de B1 ou B2. Veja a seguir o prot otipo para os diferentes tipos de heran ca m ultipla. Prot otipo: class Derivada : especicadorHeran ca Base1, especicadorHeran ca Base2,... {}; // Heran ca m ultipla (veja se ca o 18.2) class Derivada : virtual especicadorHeran ca Base1, virtual especicadorHeran ca Base2 {}; // Heran ca m ultipla virtual (veja se ca o 18.6)
18.2
Veja no exemplo a seguir como implementar a heran ca m ultipla apresentada na Figura 18.1. Observe que a classe D e herdeira das classes B1 e B2. Note ainda que a heran ca se d a da esquerda para a direita; primeiro herda os atributos e m etodos de B1, depois de B2. 347
348
B1
+atr_b1 +atr_b +f1() +f2() Herana
B2
+atr_b2 +atr_b +f1() +f2() A classe D herdeira de B1 e de B2.
D
+atr_d
Exemplo: class B1 { public: int atr_b1; int atr_b; }; class B2 { public: int atr_b2; int atr_b; }; class D: public B1, public B2 { public: int atr_d; }; int main() { B1 b1; B2 b2; D d; return 0; }
// Heran ca m ultipla
Observe na Figura 18.2 como cam os objetos b1, b2 e d na mem oria de seu computador. O objeto b1 tem os atributos atr_b1 e atr_b; o objeto b2 tem os atributos atr_b2 e atr_b; e o objeto d, os atributos atr_b1 e atr_b (herdados da classe B1), atr_b2 e atr_b (herdados da classe B2) e atr_d (da pr opria classe D).
atr_b1 atr_b
Objeto b2 na memria
atr_b2 atr_b
349
18.3
Quando voc e utiliza heran ca m ultipla, pode ocorrer que as classes B1 e B2 tenham um atributo com o mesmo nome (veja na Figura 18.1 o atributo atr_b); esse atributo ser a criado duas vezes, uma pelo caminho D-B1 e outra pelo caminho D-B2. Quando voc e tentar acessar esse atributo em um m etodo da classe D, o compilador exibir a uma mensagem de erro por ambig uidade, ou seja, quando voc e acessa atr_b, voc e quer acessar atr_b herdado da classe B1 ou atr_b herdado da classe B2? Para contornar esse problema voc e deve utilizar o operador de resolu ca o de escopo (::). Veja o prot otipo a seguir:
Alternativamente, pode-se eliminar o problema da ambig uidade utilizando-se a palavra-chave using. Com as declara co es using, voc e pode selecionar, em uma classe-derivada, os m etodos e atributos a serem utilizados. Veja o exemplo:
Exemplo: class D: public B1, public B2 { public: int atr_d; using B1::atr_b; // Quando chamar atr_b usar atr_b da classe B1 };
18.4
O diagrama UML ilustrado na Figura 18.3 mostra uma heran ca m ultipla com base comum. A classe D e herdeira das classes B1 e B2 e estas s ao herdeiras de B0. A classe B0 e uma classe-base comum (uma superclasse). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
350
B0
+atr_b0 O atributo atr_b0 vai ser criado duas vezes, uma pelo caminho D->B1->B0, e outra pelo caminho D->B2->B0.
Herana
B1
+atr_b1
B2
+atr_b2
Herana
D
+atr_d
Exemplo: class B0 { public: int atr_b0; }; class B1: public B0 { public: int atr_b1; }; class B2: public B0 { public: int atr_b2; }; class D: public B1, public B2 { public: int atr_d;}; int main() { B0 b0; B1 b1; B2 b2; D d;
return 0;
Quando voc e tem heran ca m ultipla com D herdando de B1 e B2, a classe D ir a percorrer os construtores das classes B1 e B0 e, em seguida, os contrutores de B2 e B0, criando duas vezes o atributo atr_b0. Observe na Figura 18.4 que o atributo atr_b0 e criado duas vezes, uma pelo caminho D::B1::B0 e outra pelo caminho D::B2::B0. Novamente, o acesso em D ao atributo atr_b0 e ambiguo e precisa ser resolvido com o operador de resolu ca o de escopo (::) ou usando a palavra-chave using. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
351
Figura 18.4: Como cam os objetos b0, b1, b2 e d em uma heran ca m ultipla com base comum.
Objeto b0 na memria Objeto b1 na memria Objeto d na memria
atr_b0
18.5
Em uma heran ca m ultipla (veja Figura 18.3), a seq u encia de cria ca o dos objetos ocorre da esquerda para a direita. A Figura 18.5 ilustra a seq u encia de cria ca o dos objetos b0, b1, b2 e d. Para o objeto d, primeiro executa o construtor de B0, depois o construtor de B1, novamente o construtor B0, o construtor B2 e nalmente o construtor de D. A seq u encia de destrui ca o e inversa ` a da cria ca o. Primeiro executa o destrutor de D depois o destrutor de B2, B0, e nalmente o destrutor de B1 e B0.
Figura 18.5: Seq u encia de constru ca o e destrui ca o dos objetos em uma heran ca.
int main() { B0 b0;
B0() B0() B0() B0() B1() B2() B1() B0() B2() D()
Sequncia de criao dos objetos b0,b1,b2,d.
B1 b1;
B2 b2;
D d;
return 0; }
~B0()
~B1()
~B0()
352
18.6
Vimos na Se ca o 18.3 que, ao criar uma classe-derivada de mais de uma classe-base (heran ca m ultipla), o compilador cria todos os atributos da classe-base B1 e depois todos os atributos da classe-base B2 (veja guras 18.1 e 18.2). Vimos na Se ca o 18.4 que, se as classes B1 e B2 s ao herdeiras da classe B0, ent ao o compilador ir a criar os atributos de B0 e B1 e, em seguida, os atributos de B0 e B2, de forma que o atributo de B0 (atr_b0) ser a criado duas vezes (veja guras 18.3 e 18.4). Se voc e deseja ter o atributo repetido, tudo bem (veja exemplo em nota no nal da se ca o). Por em, se voc e deseja ter apenas uma c opia dele, voc e precisar a denir a heran ca como virtual. O prot otipo a seguir mostra a sintaxe da heran ca virtual. Prot otipo: class Derivada: virtual especicadorDeHeran caBase1, virtual especicadorDeHeran ca Base2, ... {.... }; Veja na Figura 18.6 o diagrama UML de uma heran ca m ultipla virtual. Neste caso, como a heran ca e declarada como virtual, s o ser a criada uma c opia do atributo da classe-base, ou seja, atr_b0 s o e criado uma vez pelo caminho D-B1-B0. Veja no exemplo a seguir como implementar a hierarquia da Figura 18.6. Observe a utiliza ca o da palavra-chave virtual. Veja na Figura 18.7 que o atributo atr_b0 e criado apenas uma vez, pelo caminho D::B1::B0. Compare com a Figura 18.4. Figura 18.6: Heran ca m ultipla virtual.
B0
+atr_b0 O atributo atr_b0 vai ser criado apenas uma vez, pelo caminho D->B1->B0.
<<virtual>>
<<virtual>>
B1
+atr_b1
B2
+atr_b2
D
+atr_d
Exemplo: class B0 { public: class B1: { public: class B2: { public: class D:
int atr_b0; }; virtual public B0 int atr_b1; }; virtual public B0 int atr_b2; }; public B1, public B2 Andr e Duarte Bueno
E DESTRUIC DOS OBJETOS EM HERANCA 18.7. ORDEM DE CRIAC AO AO MULTIPLA VIRTUAL { public: int atr_d; }; int main() { B0 b0; B1 b1; B2 b2; D d; return 0; }
353
Figura 18.7: Como cam os objetos b0, b1, B2 e d em uma heran ca m ultipla com base virtual.
Objeto b0 na memria Objeto b1 na memria Objeto d na memria
atr_b0
atr_b0 atr_b1
atr_b0 atr_d
Objeto b2 na memria
atr_b2
Nota: vamos a um exemplo em que a repeti ca o do atr_b0 e u til. Imagine que a classe D precisa herdar informa co es de acesso a sites de internet. No caso, dois sites de pesquisa, B1 e B2. A informa ca o do endere co de internet e armazenada em atr_b0. Neste caso, atr_b0 pelo caminho D::B1 vai retornar o endere co do site B1, e atr_b0 pelo caminho D::B2 vai retornar o endere co do site B1.
18.7
Em uma hierarquia com classes virtuais, a ordem de cria ca o dos atributos e dada por: primeiro s ao inicializadas as classes-base virtuais, depois as classes normais (da esquerda para direita), depois os atributos n ao-est aticos e, nalmente, o corpo do construtor. No exemplo a seguir, uma classe X tem heran ca normal de Y e virtual de Z. A seq u encia de cria ca o do objeto x e dada por Z(), Y(), X(), ou seja, primeiro s ao percorridas as heran cas virtuais (da esquerda para a direita) e depois as heran cas normais. Exemplo: // Classe X com heran ca virtual de Z class X: public Y, virtual public Z {}; int main() { // Cria objeto do tipo X com nome x X x; return 0; } Veja na Figura 18.8 uma hierarquia de classes com heran cas normais e virtuais (B1, B2, D1, D2 e Top). As classes-base s ao B1 e B2. A classe D1 tem deriva ca o normal de B2 e virtual de B1. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
354
A classe D2 tem deriva ca o normal de B2 e virtual de B1. A classe Top tem deriva ca o normal de D1 e virtual de D2. Figura 18.8: Heran ca m ultipla normal e virtual.
B1
+atr_b1 virtual virtual
B2
+atr_b2
D1
D2
virtual
Top
A hierarquia da Figura 18.8 e implementada na listagem 18.1. Observe na sa da a seq u encia de constru ca o e destrui ca o de um objeto do tipo Top. Listing 18.1: Seq u encia de constru ca o e destrui ca o em heran ca m ultipla virtual.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # include < iostream > class B1 { int atr_b1 ; public : B1 () { std :: cout << " Construtor de B1 - " ; ~ B1 () { std :: cout << " Destrutor de B1 - " ; }; class B2 { int atr_b2 ; public : B2 () { std :: cout << " Construtor de B2 - " ; ~ B2 () { std :: cout << " Destrutor de B2 - " ; }; class D1 : public B2 , virtual public B1 { public : D1 () { std :: cout << " Construtor de D1 - " ; ~ D1 () { std :: cout << " Destrutor de D1 - " ; };
}; };
}; };
}; };
355
class D2 : public B2 , virtual public B1 { public : D2 () { std :: cout << " Construtor de D2 -" ; ~ D2 () { std :: cout << " Destrutor de D2 -" ; };
}; };
class Top : public D1 , virtual public D2 { public : Top () { std :: cout << " Construtor de Top -" ; }; ~ Top () { std :: cout << " Destrutor de Top -" ; }; }; int main () { Top p ; return 0; } [bueno@ldsc05 Construtor de Construtor Destrutor Parte - II ] $ ./ a . out B1 - Construtor de B2 - Construtor de D2 - Construtor de B2 de D1 - Construtor de Top - Destrutor de Top - Destrutor de D1 de B2 - Destrutor de D2 - Destrutor de B2 - Destrutor de B1 -
A seq u encia de cria ca o do objeto p e dada por: Primeiro a seq u encia de D2 que e virtual: cria B1, que e virtual, cria B2 e, ent ao, cria D2. Depois a seq u encia de D1 que e normal:como a classe B1 e virtual, e a mesma j a foi criada pelo caminho Top::D2::B1, n ao precisa ser criado novamente. A seguir cria B2 e, depois cria D1. Finalmente cria Top. Assim, os construtores default das classes virtuais s ao chamados antes dos construtores das classes n ao virtuais. Releia a frase anterior; veja que escrevemos os construtores default das classes virtuais. Se a classe-base virtual n ao tem um construtor default (sem par ametros), um dos construtores com par ametros deve ser explicitamente chamado. Lembre-se de que toda classe tem um construtor, sem par ametros, que e criado automaticamente pelo compilador. Vimos que voc e pode reescrever o construtor da forma que quiser, e que, se criar qualquer construtor com par ametros, o construtor default deixa de ser criado pelo compilador. Como o construtor default deixa de ser criado, o construtor existente precisa ser explicitamente chamado (Se ca o 16.3).
18.8
Observe que a chamada do construtor da classe-base s o ser a importante se ele for efetivamente implementado e contiver, por exemplo, a cria ca o de objetos din amicos. Uma classe D n ao pode ter deriva ca o m ultipla de uma classe B. Este procedimento n ao e permitido por ser amb guo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
356
18.8. SENTENCAS PARA HERANCA MULTIPLA Exemplo: class B { }; class D : public B, public B {}; // Erro de ambig uidade
Voc e pode criar um m etodo de inicializa ca o (Inicializa()), que pode ser utilizado para inicializa ca o dos atributos do objeto. Voc e pode chamar Inicializa() no construtor da classe-derivada. A utiliza ca o de heran ca virtual e interessante, permitindo construir classes mais complexas a partir da montagem de classes mais simples, com economia de mem oria e de implementa ca o. A heran ca virtual deve ser utilizada com crit erio e com cuidado. O uso excessivo de heran ca virtual deixa o c odigo mais lento. O acesso a atributos em classes com heran ca virtual e mais lento que em classes com heran ca comum. Se em uma heran ca virtual a classe-base n ao tiver um construtor default (pois foi denido um construtor com par ametros), o construtor da classe-base virtual deve ser explicitamente chamado. Veja o exemplo: Exemplo: // Arquivo CMinhaJanela.h class CFrameWindow: virtual public CWindow {...}; class CMinhaJanela: public CFrameWindow { // Construtor CMinhaJanela(string titulo); }; // Arquivo CMinhaJanela.cpp - Defini c~ ao do construtor // Chama construtor da classe-base e o // construtor da classe-base virtual explicitamente CMinhaJanela::CMinhaJanela(string titulo) :CFrameWindow(titulo),Window(titulo) {} A dica para simplicar o uso de classes com heran ca virtual e sempre incluir um construtor default. Se a classe-base e declarada como virtual, inclua um construtor default. Isto e necess ario para a cria ca o de uma matriz de objetos, pois quando esta e criada, o construtor executado e o construtor default. Se voc e deseja ter um mecanismo para identicar de que classe e um objeto (dado que voc e tem apenas um ponteiro para a classe-base), voc e deve incluir um m etodo que retorne o nome da classe. Isto e utilizado na programa ca o em ambientes de janela (como Windows, Mac OS X, Gnome, KDE), em que cada classe tem um m etodo que retorna o nome da classe. Esse m etodo e chamado GetClassName(). Mais recentemente, C++ incluiu a palavra-chave typeid que retorna dinamicamente o tipo de um objeto (veja Se ca o 9.5.4). Procure criar uma classe-base que tenha somente m etodos virtuais e p ublicos, uma classe de interface (veja Se ca o 11.5.2). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
357
Note que uma hierarquia com heran cas simples e uma arvore (tree ). Se a hierarquia inclui heran cas m ultiplas, ent ao ela gera um grafo e n ao uma arvore. No exemplo a seguir usamos sizeof() para vericar o tamanho da classe-base e da classederivada. Exemplo: NomeClasseBase *ptr = new CNomeClasseDerivada; sizeof(CNomeClasseBase); // Retorna o tamanho da classe-base sizeof(CNomeClasseDerivada);// Retorna o tamanho da classederivada sizeof(ptr); // Retorna o tamanho da classe-base 2 Nunca redena um m etodo n ao virtual. Isto elimina o conceito de invari ancia de m etodos n ao virtuais [Meyers, 2005]. 2 Quando se utiliza o mecanismo do polimorsmo e fundamental que o destrutor da classebase seja virtual. Do contr ario, o destrutor da classe-derivada n ao ser a executado.
18.9
Observe na Figura 18.9 a hierarquia de classes CPonto. A classe CCirculo e herdeira de CPonto e a classe CElipse e herdeira de CCirculo. A classe CCirculoElipse e herdeira de CCirculo e de CElipse. As classes CPonto e CCirculo foram apresentadas nas listagens 13.5 e 17.1, respectivamente. Veja na listagem 18.2 a classe CElipse e, na listagem 18.4, um programa que utiliza as classes denidas. Figura 18.9: Hierarquia de classes CPonto, CCirculo, CElipse, CCirculoElipse.
CPonto
+x +y +Desenha() Hierarquia de classes CPonto.
CCirculo
+r1 +Desenha() CCirculoElipse tem Herana mltipla
CElipse
+r2 +Desenha()
CCirculoElipse
+Desenha()
358
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# define CElipse_h # include " CCirculo . h " class CElipse : public CCirculo // H e r a n ca simples { protected : int r2 ; public : // C o n s t r u t o r CElipse ( int x , int y , int raio1 , int raio2 ) ; // Seta a t r i b u t o s do objeto void Set ( int x , int y , int raio1 , int raio2 ) ; virtual void Desenha () ; // R e d e c l a r a d a }; # endif
Observe na listagem 18.3 que o m etodo Desenha() de CElipse chama Desenha() de CCirculo e, depois, acrescenta coisas novas. Isto e, o m etodo Desenha() da classe-base e redenido na classe-derivada, fazendo o que CCirculo::Desenha fazia e algo mais. Listing 18.3: Implementa ca o da classe CElipse.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # include < iostream > # include " CElipse . h " // O b s e r v e que a c h a m a d a e x p l c i t a do c o n s t r u t o r da classe - base C C i r c u l o // e necess a r i a porque C C i r c u l o n~ a o tem um c o n s t r u t o r d e f a u l t e // quero passar os a t r i b u t o s x , y e raio1 CElipse :: CElipse ( int x , int y , int raio1 , int raio2 ) : CCirculo (x , y , raio1 ) , r2 ( raio2 ) {} void CElipse :: Set ( int x , int y , int raio1 , int raio2 ) { // Herdou x e y de CPonto this - > x = x ; this - > y = y ; r1 = raio1 ; // Herdou r1 de C C i r c u l o r2 = raio2 ; // Criou o a t r i b u t o r2 na classe C E l i p s e } void CElipse :: Desenha () { CCirculo :: Desenha () ;
// I n s t r u c~ a o para d e s e n h a r o c rculo;
// Aqui voc^ e pode a c r e s c e n t a r i n s t r u c~ o e s r e f e r e n t e s ao d e s e n h o da elipse std :: cout << " \ nCElipse : Coordenada r2 = " << r2 << std :: endl ; }
Veja na listagem 18.4 um programa que utiliza as classes denidas. Listing 18.4: Usando as classes CPonto, CCirculo e CElipse.
1 2 3 4 5 6 7 8 9 10 11 12 # include < iostream > using namespace std ; # include " CElipse . h " int main () { int x = 5; int y = 4; { cout << " \n - - - - - - - - - - - - - - - - Testando CPonto : " << endl ; CPonto ponto ; // Cria objeto do tipo CPonto com nome ponto ponto . Set (x , y ) ; // Chama m e todo Set () do objeto ponto
359
cout << " \n - - - - - - - - - - - - - - - - Testando CPonto din^ a mico : " << endl ; CPonto * ptr = NULL ; // Cria p o n t e i r o para CPonto ptr = new CPonto ; // Cria objeto do tipo CPonto x = 6; y = 7; ptr - > Set (x , y ) ; // Chama m e todo Set () do objeto usando ptr ptr - > Desenha () ; int xx = ptr - > X () ; delete ptr ; // Chama m e todo e s t a t i c o da classe CPonto , // o b s e r v e que n~ a o p r e c i s a de um objeto // U t i l i z a o nome da classe s e g u i d o do o p e r a d o r de r e s o l u c~ a o de escopo . cout << " Contador = " << CPonto :: Contador () << endl ; cout << " \n - - - - - - - - - - - - - - - - Testando CCirculo : " << endl ; CCirculo c (55 , 44 , 33) ; c . Desenha () ; cout << " \n - - - - - - - - - - - - - - - - Testando CElipse : " << endl ; CElipse e (555 , 444 , 333 , 222) ; e . Desenha () ; return 0; } - - - - - - - - - - - - - - - - Testando CPonto : CPonto : Coordenada x = 5 CPonto : Coordenada y = 4 - - - - - - - - - - - - - - - - Testando CPonto din^ a mico : CPonto : Coordenada x = 6 CPonto : Coordenada y = 7 Contador = 2 - - - - - - - - - - - - - - - - Testando CCirculo : CPonto : Coordenada x = 55 CPonto : Coordenada y = 44 CCirculo : Coordenada r1 =33 - - - - - - - - - - - - - - - - Testando CElipse : CPonto : Coordenada x = 555 CPonto : Coordenada y = 444 CCirculo : Coordenada r1 =333 CElipse : Coordenada r2 =222
18.10
No exemplo da listagem 18.5, dene-se a classe CCirculoElipse. Esta representa um c rculo dentro de uma elipse (um olho). Na listagem 18.6 apresenta-se a implementa ca o da classe CCirculoElipse. Observe que o processo de compila ca o de CCirculoElipse falha, e o compilador apresenta erros que ser ao discutidos a seguir. Listing 18.5: A classe CCirculoElipse.
1 2 3 4 5 6 7 8 # ifndef C C i r c u l o E l i p s e _ h # define C C i r c u l o E l i p s e _ h # include < iostream > using namespace std ; # include " CCirculo . h " # include " CElipse . h " // Quero um c i r c u l o e uma elipse ( um olho ) , as c o o r d e n a d a s do ponto c e n t r a l
360
9 10 11 12 13 14 15 16 17 18
// s~ a o as mesmas . H e r a n c a m u ltipla , herda de C C i r c u l o e de C E l i p s e class C C i r c u l o E l i p s e : public CCirculo , public CElipse { public : C C i r c u l o E l i p s e ( int xc , int yc , int rc , int r1e , int r2e ) ; C C i r c u l o E l i p s e ( CCirculo & circulo ) ; // C o n s t r u t o r de c o n v e r s ~ ao void Set ( int xc , int yc , int rc , int r1e , int r2e ) ; virtual void Desenha () ; // R e d e c l a r a d a }; # endif
361
C C i r c u l o E l i p s e . cpp :12: error : cannot call member function void CCirculo :: Set ( int , int , int ) without object C C i r c u l o E l i p s e . cpp : At global scope : C C i r c u l o E l i p s e . cpp :19: error : expected ) before & token C C i r c u l o E l i p s e . cpp :29: error : C C i r c u l o E P o n t o has not been declared C C i r c u l o E l i p s e . cpp : In function void Desenha () : C C i r c u l o E l i p s e . cpp :31: error : cannot call member function virtual void CElipse :: Desenha () without object C C i r c u l o E l i p s e . cpp :32: error : cannot call member function virtual void CCirculo :: Desenha () without object make : ** [ C C i r c u l o E l i p s e . o ] Erro 1
A classe CCirculoElipse n ao compila em virtude da presen ca de alguns erros. O primeiro erro est a na ambig uidade no acesso ` a classe CCirculo. Isto ocorre porque esta classepode ser acessada pelo caminho CCirculo e pelo caminho CElipse::CCirculo. Outro erro apresentado e a falta da chamada expl cita dos construtores de CCirculo. Como CCirculo n ao tem um construtor default, o construtor de CCirculo precisa ser explicitamente chamado. O erro se repete para CElipse. Ocorre novo erro ao tentar converter CCirculoElipse para CCirculo, pois existem dois CCirculo e a base e amb gua. Existe um erro na deni ca o do m etodo construtor de CCirculoElipse: est a faltando o nome da classe e ::, isto e, CCirculoElipse::CCirculoElipse(...). Como voc e pode ver, a sa da gerada pelo compilador pode ser muito grande. De modo geral, um pequeno erro de digita ca o (de sintaxe) pode gerar v arias mensagens de erro. Um exemplo cl assico de erro de digita ca o e que gera uma sa da confusa e a falta ou excesso de colchetes {}. Com isso, voc e conclui que e necess ario compreender bem a sintaxe de C++ e digitar o programa com cuidado. Dica: veremos o uso do compilador da GNU, o g++ no Cap tulo ?? Compilando com gcc e g++, e a debugagem de programas no Cap tulo ?? Uma Introdu ca o aos Bugs e a Debugagem de Programas.
18.11
Vimos uma pequena introdu ca o e o prot otipo para implementar heran ca m ultipla. Aprendemos a implementar heran ca m ultipla em C++ e, ainda, como cam os objetos na mem oria do computador. Em seguida, aprendemos a resolver os problemas de ambig uidade em heran ca m ultipla e o uso de heran ca m ultipla com base comum. Tamb em vimos o conceito de heran ca m ultipla virtual e a ordem de cria ca o e destrui ca o dos objetos em uma heran ca. Finalmente, aprendemos a analisar os erros emitidos pelo compilador. Dica: este e um dos cap tulos mais complexos de C++. N ao se preocupe se n ao entendeu tudo em uma primeira leitura. Esses conceitos ser ao assimilados ap os um certo per odo de uso de C++.
18.12
Exerc cios
1. Comente as listagens apresentadas. 2. Implemente as classes B1, B2 e D, descritas na Se ca o 18.2. 3. Implemente as classes B0, B1, B2 e D descritas na Se ca o 18.4. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
362
4. Monte o programa main() descrito na Figura 18.5. Rode o programa e veja se a ordem de constru ca o e destrui ca o descrita est a correta (voc e pode rodar o programa de dentro do debuger ddd; Veja Se ca o ??). 5. Modique a listagem 18.1 acrescentando um par ametro no construtor de B1. Veja a sa da gerada. Em seguida, adicione a chamada ao construtor de B1. 6. Fa ca as corre co es necess arias no c odigo das listagens 18.5 e 18.6, de forma que a classe CCirculoElipse funcione e possa ser inclu da no c odigo do programa da listagem 18.4. 7. Na Se ca o 18.9 apresentamos uma hierarquia de classes gen ericas. A pergunta e,: um c rculo e um tipo de ponto? Corrija a hierarquia. 8. Acrescente a hierarquia as classes CQuadrado, CRetangulo, CTriangulo e CTrapezio.
Cap tulo 19
Polimorsmo
Veremos neste cap tulo como implementar o conceito de polimorsmo apresentado na Se ca o 3.7. Iniciamos explicando, na Se ca o 19.1, o funcionamento dos m etodos n ao virtuais (m etodos normais e m etodos est aticos). Em seguida apresentaremos os m etodos virtuais, Se ca o 19.2, os quais s ao a base para implementar o polimorsmo, descrito na Se ca o 19.3. Os m etodos virtuais puros, utilizados para implementar classes abstratas ou de interface, s ao descritos na Se ca o 19.4 e os m etodos virtuais sobrecarregados na Se ca o 19.5. Finalmente, apresentaremos um exemplo cobrindo o uso pr atico de polimorsmo na Se ca o 19.6.
19.1
M etodos n ao virtuais
Os m etodos de uma classe podem ser normais, inline, est aticos ou virtuais. Os m etodos normais, os m etodos est aticos e os m etodos em linha t em seu endere co denido a priori, na compila ca o, tendo uma liga ca o est atica. O termo liga ca o est atica signica que quando o compilador encontra uma chamada do m etodo, ele substitui esta pelo endere co de mem oria onde o m etodo est a localizado. J a os m etodos com liga ca o din amica t em seu endere co denido durante a execu ca o. Veja na Tabela 19.1 exemplos de m etodos com liga ca o est atica. Observe que m etodos sem a palavra-chave virtual s ao m etodos com liga ca o est atica. Tabela 19.1: M etodos com liga ca o est atica Prexo __ inline static inline static __ inline Retorno Tipo Tipo Tipo Tipo Tipo Tipo NomeM etodo NomeM etodo NomeM etodo NomeM etodo NomeM etodo NomeM etodo NomeM etodo Par ametro ( Tipo p ) ( Tipo p ) ( Tipo p ) ( Tipo p ) ( Tipo p ) ( Tipo p ) Suxo __ __ __ __ const const
A Tabela 19.2 mostra m etodos com liga ca o din amica. Observe o uso da palavra-chave virtual como prexo. Note ainda que um m etodo virtual pode ser const, mas n ao pode ser static nem inline. 363
364
Tabela 19.2: M etodos com liga ca o din amica Prexo virtual virtual Retorno Tipo Tipo Nome Nome Nome Par ametro ( Tipo p ) ( Tipo p ) Suxo __ const
Vamos tentar esclarecer o funcionamento da liga ca o est atica com um exemplo. Seja a classe B, com os m etodos M1(), M2(), M3(). Verique que M3() chama M1() e M2(). A classe D e derivada de B e redene os m etodos M1() e M2(). Na fun ca o main(), cria um objeto do tipo D com nome d e chama os m etodos M1(), M2(), e M3(). Exemplo: class B { public: void M1(){...}; void M2(){...}; void M3(){ M1(); }; class D: public B { public: void M1() {...}; void M2() {...}; }; int main() { D d; d.M1(); d.M2(); d.M3(); return 0; } Como os m etodos M1() e M2() t em liga ca o est atica, o m etodo M3() denido apenas na classe B vai chamar os m etodos M1() e M2() da classe B e n ao da classe D, ou seja, como a liga ca o e est atica, o compilador traduz a fun ca o main() da seguinte forma: Exemplo: int main() { D d; D::M1(&d); // Chama M1() da classe D D::M2(&d); // Chama M2() da classe D B::M3(&d); // Chama M3() da classe B // O comando B::M3(&d); vai ser traduzido por // B::M1(&d); B::M2(&d); return 0; } Observe no exemplo anterior que foi criado um objeto do tipo D e que o m etodo M3() est a executando os m etodos M1() e M2() da classe B. Por em, se criamos uma classe D e redenimos Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
M2(); };
// // // //
365
M1() e M2(), normalmente iremos querer que os m etodos M1() e M2() sejam sempre usados, mesmo quando chamamos M3(). Para que o m etodo M3() chame os m etodos M1() e M2() da classe D, os m etodos M1() e M2() devem ser declaradas como m etodos virtuais. Veremos a seguir como funcionam os m etodos virtuais.
19.2
M etodos virtuais
Os m etodos virtuais t em seu endere co denido dinamicamente, ou seja, durante a execu ca o do programa. Nesta se ca o, vamos discutir como isso funciona. Veja a seguir o prot otipo de declara ca o dos m etodos virtuais. A u nica diferen ca em rela ca o aos m etodos normais e a inclus ao da palavra-chave virtual. Veja na Tabela 19.2 exemplos de m etodos com liga ca o din amica. Prot otipo: class B { // Declara m etodo virtual virtual Tipo M etodoA(); // Declara m etodo virtual com par ametros virtual Tipo M etodoB(par ametros); // Declara m etodo virtual com par ametros e const virtual Tipo M etodoC(par ametros) const; }; class D: public B { // Redeclara m etodo virtual virtual Tipo M etodoA(); // Redeclara m etodo virtual com par ametros virtual Tipo M etodoB(par ametros); // Redeclara m etodo virtual com par ametros e const virtual Tipo M etodoC(par ametros) const; }; Toda classe que possui m etodos virtuais cont em uma tabela chamada VMT - Virtual Memory Table ou Tabela de M etodos Virtuais. Essa tabela cont em o endere co em tempo de execu ca o dos m etodos virtuais. Assim, quando o programa est a rodando, a deni ca o de qual m etodo vai ser executado e dada pela tabela VMT. Como funciona? A classe-base tem o endere co de seus m etodos virtuais na sua tabela VMT e acessa-os vericando seus endere cos na tabela. A classe-derivada tamb em tem uma VMT, onde h a o endere co de seus m etodos virtuais. Desta forma, quando um objeto da classe-derivada chama um m etodo, o endere co e obtido durante a execu ca o da sua VMT. Por meio desse mecanismo, a identica ca o de qual m etodo ser a executado e realizada dinamicamente atrav es da verica ca o do endere co dos m etodos na tabela VMT. Esse mecanismo tamb em recebe o nome de liga ca o din amica, pois o m etodo que ser a executado, ser a denido durante a execu ca o. A Figura 19.1 ilustra o funcionamento da liga ca o din amica. Toda chamada a M1() e M2() passa pela VMT. Quando voc e cria um objeto do tipo B, este utiliza a VMT da classe B e sempre acessa os m etodos M1() e M2() da classe B. Isso tamb em e v alido para a classe D. Quando voc e Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
366
cria um objeto do tipo D, este utiliza a VMT da classe D e sempre acessa os m etodos M1() e M2() da classe D. Observe que quando um objeto da classe D acessa o m etodo M3(), acessa o m etodo M3() da classe B porque este n ao foi redenido na classe D. Mas quando M3() acessa M1() e M2(), est a acessando os m etodos M1() e M2() da classe D porque passa pela VMT da classe D. Veremos a seguir senten cas para m etodos virtuais e logo ap os, como usar os m etodos virtuais para implementar o polimorsmo. Figura 19.1: Ilustra ca o do funcionamento da liga ca o din amica.
Classe B
+M1(): virtual +M2(): virtual +M3() VMT_CLASSE_B M1 M2 M3() { M1(); M2(); }
Herana
void main() { D* ptr = new D(); ptr->M1(); ptr->M2(); ptr->M3(); delete ptr; }
Classe D
+M1(): virtual +M2(): virtual VMT_CLASSE_D M1 M2
19.2.1
N ao devemos chamar m etodos virtuais de dentro do construtor, pois o construtor da classe sempre ir a chamar os m etodos da pr opria classe. Isto ocorre porque a tabela VMT da classe derivada ainda n ao foi criada. Uma vez que um m etodo e declarado como virtual, este o ser a para sempre e em todas as classes derivadas. Se um m etodo M() e declarado como virtual na classe-base B, e, em uma classe-derivada D, o programador omite a palavra chave virtual, ent ao ele est a indicando que este m etodo n ao deve ser redenido nas classes derivadas de D. Os m etodos virtuais devem ter exatamente o mesmo prot otipo; se o nome for igual e os par ametros diferentes, teremos sobrecarga de m etodos. Veja o Cap tulo 14 Sobrecarga de M etodos e a Se ca o 19.5. Retorno diferente n ao diferencia m etodos; o que diferencia os m etodos e o seu nome e os seus par ametros. Note que um m etodo virtual pode ser const, mas n ao pode ser static (porque m etodos static n ao recebem o ponteiro this) nem inline (porque m etodos inline s ao substitu dos/resolvidos em tempo de compila ca o). A utiliza ca o de m etodos virtuais em heran cas permite a implementa ca o do conceito de polimorsmo e elimina muitas das estruturas switch (veja Se ca o 19.3). Quando voc e cria classes com m etodos virtuais voc e deve declarar o destrutor como sendo virtual, garantindo, desta forma, a execu ca o do destrutor correto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
367
Cuidado com par ametros predenidos em m etodos virtuais. Embora o m etodo a ser executado seja denido em tempo de execu ca o, os par ametros s ao denidos em tempo de compila ca o, tendo como base o tipo do ponteiro utilizado. Este problema e facilmente contornado. As assinaturas de todos os m etodos virtuais devem ser exatamente iguais. Se o m etodo e virtual, voc e deve evitar o uso de par ametros predenidos ou ter certeza de que todas as declara co es e deni co es de um m etodo virtual t em exatamente os mesmos valores predenidos (veja Se ca o 13.6.4). 2 Em uma hierarquia de classes, um m etodo virtual deve ter o mesmo tipo de retorno. Se o tipo de retorno for diferente, ent ao temos um retorno covariante. Este caso e poss vel somente se o retorno for um ponteiro ou refer encia para um tipo derivado da classe-base. No exemplo a seguir o retorno do m etodo M(); e covariante: Exemplo: class Base { virtual Base* M();}; class Derivada1: public Base { virtual Derivada1* M();}; class Derivada2: public Derivada1 { virtual Derivada2* M();};
19.3
Vimos anteriormente que polimorsmo signica muitas formas (Se ca o 3.7), ou seja, para cada classe-derivada o m etodo virtual ser a redenido, mas de forma diferente. Vimos ainda que o m etodo virtual que vai ser efetivamente executado e endere cado pela VMT. Para implementar o polimorsmo e necess ario uma hierarquia de classes com m etodos virtuais e a cria ca o dos objetos de forma din amica (com o uso de um ponteiro para a classe-base). Veja na listagem 19.1 um exemplo que esclarece a utiliza ca o do polimorsmo. O programa Polimorfismo.cpp utiliza as classes CPonto, CCirculo e CElipse denidas anteriormente (veja Figura 18.9). O programa inicia-se criando um ponteiro para a classebase da hierarquia, a classe CPonto. Dentro do la co do..while() (veja Se ca o D.3.3), o usu ario seleciona qual objeto deve ser criado, isto e, CPonto, CCirculo ou CElipse. Em seguida, dentro do switch (veja Se ca o D.2.4), cria o objeto selecionado. ao existe nenhuma refer encia ou informa ca o Observe que na chamada a ptr->Desenha();; n sobre qual foi o objeto criado. Por em, com a utiliza ca o do mecanismo de polimorsmo, o m etodo Desenha() que ser a executado e aquele do objeto que foi criado (usa a VMT do objeto criado). Observe que, depois que o objeto foi criado, pode-se utilizar os m etodos p ublicos da classe CPonto. Se o usu ario solicitar a cria ca o de um objeto CPonto o programa ir a executar o m etodo Desenha() de CPonto;; se o usu ario criar um objeto CCirculo, o programa ir a executar o m etodo Desenha() de CCirculo; e se criar um objeto CElipse, o programa ir a executar o m etodo Desenha() de CElipse. Isso quer dizer que o m etodo executado depender a do objeto criado. Veja no nal da listagem como car a a sa da do programa, selecionando-se os diferentes tipos de objetos. Para compilar a listagem Polimorfismo.cpp, digite: g++ Polimorsmo.cpp CCirculo.cpp CElipse.cpp CPonto.cpp Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
368
Nota: o la co do..while() e descrito na Se ca o D.3.3, e o uso de switch na Se ca o D.2.4. As listagens utilizadas s ao: 13.5, 17.1, 18.2.
Releia o exemplo com cuidado e observe que depois que o objeto e criado dentro do switch, este pode ser utilizado (chamada a ptr->desenhar()), mas voc e n ao saber a qual foi o objeto que o usu ario criou. Trata-se de um mecanismo de programa ca o incomum e muito inteligente. Voc e escreve boa parte do c odigo de forma gen erica, sem se preocupar se foi criado um ponto, um c rculo ou uma elipse. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
369
19.3.1
Todo objeto criado sabe a qual classe pertence e utiliza a tabela VMT da sua classe. O mecanismo virtual existe para permitir que as opera co es sobre um objeto sejam realizadas sem o conhecimento do tipo do objeto que ser a criado. O polimorsmo deixa o programa mais simples e gen erico, pois seu desenvolvimento e simplicado. Toda classe com m etodos virtuais tem uma tabela VMT, e todo objeto de uma classe com m etodos virtuais tem oculto um ponteiro para esta tabela (virtual pointer ). Como conseq u encia da implementa ca o da hereditariedade e do polimorsmo, quando um programa orientado a objeto e executado, as mensagens s ao recebidas por objetos. Normalmente, o m etodo para manipula ca o de uma mensagem e armazenado no alto de uma biblioteca de classes ( e uma classe de Interface). O m etodo e localizado dinamicamente, quando necess ario, e a liga ca o ocorre no u ltimo momento poss vel (utilizando a VMT).
19.4
M etodos virtuais puros s ao m etodos que s ao declarados como virtuais na classe-base e que n ao s ao implementados (n ao s ao denidos). Eles s ao utilizados para criar uma classe de Interface. Veja no prot otipo que o m etodo e igualado ao valor 0. Como o m etodo s o foi declarado e n ao denido, n ao posso criar um objeto da classe-base abstrata porque ele poderia chamar um m etodo que n ao existe. Prot otipo: class Base { virtual Tipo M etodoA() =0; virtual Tipo M etodoB(par ametros)=0; virtual Tipo M etodoC(par ametros) const =0; }; Se a classe-derivada n ao implementa o m etodo virtual puro, ela tamb em e uma classe abstrata, que n ao pode criar objetos. Se voc e tiver uma classe com um ou mais m etodos virtuais puros, ter a uma classe abstrata, uma classe que n ao poder a criar objetos (mas pode ser usada para criar ponteiros). Uma classe de interface normalmente e uma classe-base ou superclasse, podendo ser utilizada como uma interface para acessar, por meio de um ponteiro, as classes derivadas. Uma classe de interface e uma classe que n ao tem atributos, e todos os seus m etodos s ao p ublicos.
19.5
M etodos virtuais podem ser sobrecarregados, mas a redeclara ca o de um destes m etodos na classe-derivada oculta todos os m etodos com mesmo nome na classe-base. Veja o exemplo: class Base { virtual Area(); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
370
19.6. EXEMPLO COMPLETO COM POLIMORFISMO }; class Derivada : public Base { virtual Area(Funcao* f); // Sobrecarga, oculta Area(). };
No exemplo anterior, se criarmos um objeto do tipo da classe-derivada, s o poderemos acessar o m etodo virtual Area(Funcao* f); // Sobrecarga
pois o mesmo ocultou o m etodo Area() da classe-base. A id eia de ocultar os m etodos da classe-base teve como motiva ca o a preocupa ca o em se evitar que heran cas com sobrecarga sejam realizadas acidentalmente, sobretudo em programas e bibliotecas grandes [Meyers, 2005]. Esse problema pode ser contornado de duas formas: usando a palavra-chave using ou redenindo todos os m etodos na classe-derivada e chamando os m etodos da classe-base. Veja a seguir a solu ca o usando using. class Derivada : public Base { virtual Area(Funcao* f);// Sobrecarga using Base::Area; // Informa que esta usando m etodo da classe-base }; A segunda solu ca o consiste em redenir os m etodos na classe-derivada. class Derivada : public Base { virtual Area(Funcao* f); // Sobrecarga virtual Area() // Redefinida { Base::Area(); } }; Observe que a solu ca o usando using e mais simples.
19.6
O diagrama UML da hierarquia de classes que ser a implementado e ilustrado na Figura 19.2. Note que a classe CAlunoFuncionario tem heran ca m ultipla. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
371
CPessoa
+nome: string +matricula: string +Entrada(): void +Saida(): void
CAluno
+iaa: float +numeroAlunos: static int +universidade: static string +Entrada(): virtual +Saida(): virtual
CFuncionario
+indiceProdutividade: float +Entrada(): virtual +Saida(): virtual
CAlunoFuncionario
+indicePobreza: double +Entrada(): virtual +Saida(): virtual
Figura 19.2: Hierarquia CPessoa, CAluno, CFuncionario, CAlunoFuncionario. Veja na listagem 19.2 a classe CPessoa. Listing 19.2: A classe CPessoa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # ifndef CPessoa_h # define CPessoa_h # include < string > // U t i l i z a r e i o b j e t o s string s
/* A classe C P e s s o a r e p r e s e n t a uma pessoa . Tem um nome , e m etodos b asicos para e n t r a d a e sa da de dados . Tem alguns c o n s t r u t o r e s e um d e s t r u t o r. A m a t r i c u l a foi a c r e s c e n t a d a na etapa de p r o j e t o . */ class CPessoa { private : std :: string nome ; std :: string matricula ;
public : // Acesso p ublico CPessoa () ; // C o n s t r u t o r CPessoa ( const CPessoa & obj ) ; // C o n s t r u t o r de c o pia // C o n s t r u t o r s o b r e c a r r e g a d o CPessoa ( std :: string _nome , std :: string _matricula ) ; virtual ~ CPessoa () ; // D e s t r u t o r virtual void Entrada () ; // E n t r a d a e sa da de dados virtual void Saida () const ; std :: string Nome () const { return nome ; }; std :: string Matricula () const { return matricula ;}; void Nome ( std :: string _nome ) { nome = _nome ; }; void Matricula ( std :: string _m ) { matricula = _m ; }; }; # endif
372
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 # include " CPessoa . h " using namespace std ;
// C o n s t r u t o r d e f a u l t ( sem p a r ^ ametros) CPessoa :: CPessoa () : nome ( " " ) , matricula ( " " ) { cout << " Criou objeto CPessoa construtor default " << endl ; } // C o n s t r u t o r de c o pia CPessoa :: CPessoa ( const CPessoa & obj ) { nome = obj . nome ; matricula = obj . matricula ; cout << " Criou objeto CPessoa construtor de c o pia " << endl ; } CPessoa :: CPessoa ( string _nome , string _matricula ) : nome ( _nome ) , matricula ( _matricula ) { cout << " Criou objeto CPessoa construtor s o b r e c a r r e g a d o " << endl ; } // D e s t r u t o r CPessoa ::~ CPessoa () { cout << " destruiu objeto CPessoa " << endl ; } // E n t r a d a de dados void CPessoa :: Entrada () { cout << " Entre com o nome : " ; getline ( cin , nome ) ; cout << " Entre com a matricula : " ; getline ( cin , matricula ) ; } // Sa da de dados void CPessoa :: Saida () const { cout << " Nome : " << nome << " Matricula : " << matricula << endl ; }
373
374
45 46 47 48 49 50 51 }
void CAluno :: Saida () const { CPessoa :: Saida () ; cout << " iaa : " << iaa << endl ; }
375
Veja na listagem ?? a implementa ca o da classe CAlunoFuncionario. Listing 19.9: Implementa ca o da classe CAlunoFuncionario.
# include < iostream > using namespace std ; # include " C A l u n o F u n c i o n a r i o . h " C A l u n o F u n c i o n a r i o :: C A l u n o F u n c i o n a r i o () { cout << " Criou objeto C A l u n o F u n c i o n a r i o construto r default " << endl ; } C A l u n o F u n c i o n a r i o ::~ C A l u n o F u n c i o n a r i o () { cout << " Destruiu objeto C A l u n o F u n c i o n a r i o " << endl ; } // A seguir c o digo o p c i o n a l /* void C A l u n o F u n c i o n a r i o :: E n t r a d a ()
376
{
CAluno :: E n t r a d a () ; T F u n c i o n a r i o :: E n t r a d a () ; cout << " Entre com o ndice de p o b r e z a : "; cin >> i n d i c e P o b r e z a ; cin . get () ; } */ // S o l u c~ a o para n~ a o chamar nome e m a t r c u l a 2 vezes . void C A l u n o F u n c i o n a r i o :: Entrada () { CAluno :: Entrada () ; // E n t r a d a de nome , matr cula , iaa // E n t r a d a do i n d i c e P r o d u t i v i d a d e cout << " Entre com o n d i c e P r o d u t i v i d a d e do funcionar i o : " ; cin >> i n d i c e P r o d u t i v i d a d e ; cin . get () ; cout << " Entre com o ndice de pobreza : " ; cin >> i n d i c e P o b r e z a ; cin . get () ; // E n t r a d a do i n d i c e P o b r e z a } // Sa da de dados void C A l u n o F u n c i o n a r i o :: Saida () const { CAluno :: Saida () ; // Se chamar T F u n c i o n a r i o :: Saida ( os ) ; vai r e p e t i r os dados na tela cout << " n d i c e P r o d u t i v i d a d e : " << i n d i c e P r o d u t i v i d a d e << " ndice pobreza = : " << i n d i c e P o b r e z a << endl ; }
Veja na listagem 19.10 a implementa ca o do programa que utiliza as classes anteriormente denidas. Observe o uso de instru co es #ifndef, para inclus ao dos arquivos de cabe calho. Note ainda que utilizamos o conceito de polimorsmo. Listing 19.10: Testando a heran ca m ultipla.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # include < iostream > # include < fstream > # include < string > // I n c l u s ~ a o de todos os a r q u i v o s de c a b e c a l h o *. h # ifndef CPessoa_h # include " CPessoa . h " # endif # ifndef CAluno_h # include " CAluno . h " # endif # ifndef C F u n c i o n a r i o _ h # include " C F u n c i o n a r i o . h " # endif # ifndef C A l u n o F u n c i o n a r i o _ h # include " C A l u n o F u n c i o n a r i o . h " # endif using namespace std ; int main () { string linha = " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\ n " ; int resp = 0; do { cout << linha << " Selecao do tipo de objeto ( -1 para sair ) \ n \ a "
377
378
CAluno . . . . . . . . . . . . . . . . . . . . . 1 CFuncionario ...............2 CAlunoFuncionario ..........3: -------------------------------------------------------------1 criou objeto CPessoa construto r default criou objeto CAluno (1) construtor default Entre com o nome : Viatchsla v a I . Priimenko Entre com a matricula : 68 Entre com o IAA do aluno : 10 Nome : Viatchsla va I . Priimenko Matricula : 68 iaa : 10 destruiu objeto CAluno :1 destruiu objeto CPessoa -------------------------------------------------------------Selecao do tipo de objeto ( -1 para sair ) CPessoa . . . . . . . . . . . . . . . . . . . . 0 CAluno . . . . . . . . . . . . . . . . . . . . . 1 CFuncionario ...............2 CAlunoFuncionario ..........3: -------------------------------------------------------------3 criou objeto CPessoa construto r default criou objeto CAluno (1) construtor default criou objeto C F u n c i o n a r i o construtor default criou objeto C A l u n o F u n c i o n a r i o construtor default Entre com o nome : Cintia Matsumura Entre com a matricula : 546 Entre com o IAA do aluno : 9 Entre com o i n d i c e P r o d u t i v i d a d e do funcionar io : 9 Entre com o indice de pobreza : .8 Nome : Cintia Matsumura Matricula : 546 iaa : 9 indiceProdutividade : 9 indice pobreza = : 0.8 destruiu objeto C A l u n o F u n c i o n a r i o destruiu objeto C F u n c i o n a r i o : destruiu objeto CAluno :1 destruiu objeto CPessoa -------------------------------------------------------------Selecao do tipo de objeto ( -1 para sair ) CPessoa . . . . . . . . . . . . . . . . . . . . 0 CAluno . . . . . . . . . . . . . . . . . . . . . 1 CFuncionario ...............2 CAlunoFuncionario ..........3: --------------------------------------------------------------1 Sair .
19.7
Vimos na Se ca o 3.7 que polimorsmo signica muitas formas. Neste cap tulo aprendemos que C++ utiliza m etodos virtuais para implementar o conceito de polimorsmo. Vimos que os m etodos virtuais t em uma tabela VMT que cont em, em tempo de execu ca o, o endere co dos m etodos da classe. Note que para implementar o polimorsmo e necess ario uma hierarquia de classes com m etodos virtuais, e a cria ca o dos objetos deve ser feita de forma din amica, isto e, usando um ponteiro para a classe-base e o operador new. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
379
Aprendemos que os m etodos virtuais puros s ao utilizados para implementar o conceito de classes abstratas e classes de interface. Finalmente, vimos um exemplo completo com uso de polimorsmo.
19.8
Exerc cios
1. Por que um m etodo static n ao pode ser const? 2. Modique as listagens da Se ca o 19.6 de forma que na entrada e sa da de dados n ao apare cam repeti co es. 3. Para as listagens da Se ca o 19.6, crie uma classe de interface (com m etodos p ublicos e puros). 4. Observe que a modelagem da Figura 19.2 n ao e perfeita, anal, uma pessoa tem um nome, mas n ao tem uma matr cula. O atributo matr cula foi movido para CPessoa na etapa de projeto. Da mesma forma, o atributo string universidade n ao est a bem colocado. Como exerc cio voc e deve melhorar essa hierarquia e implementar no c odigo as modica co es que considerar pertinentes. 5. Monte o c odigo em C++ para o diagrama de classes a seguir (arquivos .h e .cpp)
Polinomio1G
+a1: double +a2: double +y: double +f(_x:double): double +Entrada(): void
Polinomio2G
+a3: double +f(_x:double): double +Entrada(): void
380
Cap tulo 20
Friend
Vimos na Se ca o 3.8 uma breve deni ca o do conceito de friend. Neste cap tulo veremos como C++ implementa o conceito de amizade, a utiliza ca o de classes, m etodos e fun co es friend, al em de como utilizar o conceito de friend para obter maior encapsulamento das diversas classes. Iniciaremos com uma introdu ca o ao conceito de friend (Se ca o 20.1), o prot otipo para uso de friend (Se ca o 20.1), e, em seguida, veremos as classes (Se ca o 20.3) e os m etodos friend (Se ca o 20.4), al em das fun co es globais (Se ca o 20.5). Finalizamos o cap tulo com algumas senten cas para friend (Se ca o 20.6).
20.1
Vimos na Se ca o 3.2 que o conceito de encapsulamento est a relacionado com o ocultamento das informa co es do objeto. Com o encapsulamento nosso c odigo ca melhor, mais seguro. Como voc e e um programador interessado em manter a qualidade de seu c odigo, ir a preocuparse com o encapsulamento. Os atributos e m etodos de uma classe X ser ao, sempre que poss vel, private ou protected. Dessa forma, outros objetos s o poder ao acessar o que for public. Isto e, se voc e tiver um objeto do tipo X com nome obj_x, s o poder a acessar os atributos e m etodos denidos como p ublicos na classe X. Alguns objetos, por em, podem apresentar entre si um relacionamento mais pr oximo, como se fossem amigos. Por exemplo, um desconhecido n ao tem acesso a sua casa, aos seus bens pessoais; um amigo, por sua vez, pode entrar em sua casa e fazer uso de alguns objetos pessoais. Ou seja, com friend podemos implementar associa co es mais ntimas entre as classes. Vamos a um exemplo: se duas classes Y e X t em uma associa ca o do tipo Y acessa X, ent ao os m etodos a serem acessados por Y devem ser p ublicos em X. Neste caso, no entanto, os m etodos p ublicos de X cam p ublicos para qualquer um que queira usar um objeto do tipo X e n ao apenas para Y (quebrando o encapsulamento de X). Podemos manter o encapsulamento de X, informando que a classe Y tem privil egios de acesso ` a classe X, o que e feito com friend. A programa ca o orientada a objeto fornece o conceito de friend para que os objetos que s ao amigos funcionem da mesma forma. Basta informarmos quem s ao os amigos de determinada classe. Com friend podemos preservar o encapsulamento (usando private/protected) e ao mesmo tempo liberar o acesso aos membros da classe para classes/m etodos/fun co es declaradas como amigas. 381
382
20.2
Veja a seguir o prot otipo para fun co es, m etodos e classes amigas. Observe que e adicionada a palavra-chave friend, utilizada para dar a uma classe, atributo, m etodo ou fun ca o a possibilidade de acesso a membros n ao p ublicos da classe. Prot otipo: // Uma fun ca o global retorno NomeFun ca o(par ametros); // Uma classe class X { retorno NomeM etodo(par ametros); }; // Uma segunda classe class Y { // Declara que a classe X e amiga da classe Y (veja se ca o 20.3) friend class X; // Declara que o m etodo X::NomeM etodo e amigo da classe Y (veja se ca o 20.4) friend retorno X::NomeM etodo(par ametros); // Declara que a fun ca o global NomeFun ca o e amiga da classe Y (veja se ca o 20.5) friend retorno NomeFun ca o(par ametros); }; Veja a seguir um conjunto de dicas para uso de friend. A declara ca o friend s o e v alida para a classe em que foi declarada, ou seja, n ao vale para as classes-derivadas. Observe que se uma classe X e amiga de Y, e a classe Y e amiga de Z, n ao implica que X seja amiga de Z, ou seja, todas as amizades devem ser explicitamente denidas. Por conven ca o o especicador friend e usualmente o primeiro. A declara ca o friend apenas indica que a classe/m etodo/fun ca o declarada como amiga e amiga. N ao pode ser confundida como a declara ca o em si da classe/m etodo/fun ca o. Au nica maneira de especicar o relacionamento friend m utuo entre duas classes e declarar toda a segunda classe como friend da primeira e vice-versa. Um m etodo declarado como friend em uma classe deixa claro que este faz parte de uma estrutura l ogica da classe, provavelmente uma associa c ao. A declara ca o de um m etodo envolve tr es aspectos: 1. O m etodo tem acesso aos membros internos. 2. O m etodo est a no escopo da classe. 3. O m etodo precisa de um objeto da classe (com exce ca o dos m etodos est aticos). Observe que uma fun ca o ou um m etodo friend tem apenas o primeiro aspecto. Para deixar o layout do seu programa mais bem organizado e manter um determinado padr ao, coloque todas as declara co es friend no m da classe. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
383
20.3
Classes friend
Se uma classe X for amiga da classe Y, os m etodos da classe X poder ao acessar todos os atributos e m etodos de um objeto da classe Y. No exemplo da listagem 20.1, o m etodo MX() da classe X pode acessar os atributos do objeto obj_y (recebido como par ametro), porque toda classe X e declarada como amiga da classe Y. Observe neste exemplo que toda classe Y e privada; desta forma os atributos e m etodos de Y s o podem ser acessados pela classe X. Listing 20.1: Usando classes friend.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 # include < iostream > // S o m e n t e d e c l a r a a classe Y class Y ; // D e c l a r a c~ ao e defini c~ a o da classe X class X { int x ; public : // M e todo da classe X que recebe como p a r ^ a m e t r o um objeto Y void MX ( Y & obj_y ) ; }; // D e c l a r a c~ ao e defini c~ a o da classe Y class Y { private : int y ; // A classe X e amiga , o m e todo MX () pode a c e s s a r os a t r i b u t o s de Y friend class X ; }; void X :: MX ( Y & obj_y ) { std :: cout << " Fazendo x = obj_y . y ; " << std :: endl ; // O b s e r v e o acesso ao a t r i b u t o y do objeto obj_y x = obj_y . y ; } int main () { std :: cout << " Criando objetos X obj_x ; Y obj_y ; " << std :: endl ; X obj_x ; Y obj_y ; // O objeto obj_x acessa o m e todo MX p a s s a n d o como p a r ^ a m e t r o o obj_y obj_x . MX ( obj_y ) ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ List_18_1 Criando objetos X obj_x ; Y obj_y ; Fazendo x = obj_y . y ;
20.4
M etodos friend
No exemplo da listagem 20.2, um m etodo da classe Y e declarado como amigo da classe Z na linha: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
Como o m etodo MY() e declarado como amigo da classe Z, pode acessar os atributos de um objeto do tipo Z. Observe que o atributo z, mesmo sendo privado, e acessado pelo m etodo MY(). Listing 20.2: Usando m etodos friend.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 # include < iostream > class Z ; // S o m e n t e d e c l a r a a classe Z class Y // D e c l a r a c~ ao e defini c~ a o da classe Y { private : int y ; public : // M e todo da classe Y que recebe um objeto do tipo Z . void MY ( Z & objZ ) ; }; class Z { private : int z ; // O m e todo MY da classe Y e amigo , pode a c e s s a r os a t r i b u t o s de Z friend void Y :: MY ( Z & objZ ) ; }; void Y :: MY ( Z & objZ ) { std :: cout << " Fazendo y = objZ . z ; " << std :: endl ; y = objZ . z ; } int main () { std :: cout << " Criando objetos Y objY ; Z objZ ; " << std :: endl ; Y objY ; Z objZ ; objY . MY ( objZ ) ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ List_18_2 Criando objetos Y obj_y ; Z obj_z ; Fazendo y = obj_z . z ;
20.5
Uma fun ca o com escopo global e uma fun ca o que pode ser acessada a qualquer momento. Ela e declarada e denida fora de qualquer bloco, classe, estrutura ou uni ao. Programas estruturados escritos em C costumam ter diversas fun co es globais (veja discuss ao sobre escopo em C na Se ca o B.4). Veja na listagem 20.3 um exemplo de fun ca o global friend. A fun ca o FuncaoGlobalAmiga() recebe como par ametro um ponteiro para um objeto do tipo X. Listing 20.3: Usando fun co es globais friend.
1 # include < iostream >
385
// D e c l a r a que existe a classe X class X ; // D e c l a r a uma fun c~ a o global void F u n c a o G l o b a l A m i g a ( X * ptr_x ) ; // D e c l a r a a classe X class X { private : static const int x = 321; // D e c l a r a que a fun c~ a o global e amiga da classe X friend void F u n c a o G l o b a l A m i g a ( X * ptr_x ) ; }; // Define a fun c~ a o global void F u n c a o G l o b a l A m i g a ( X * ptr_x ) { std :: cout << ptr_x - > x << std :: endl ; } int main () { X * ptr_x = new X ; F u n c a o G l o b a l A m i g a ( ptr_x ) ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ g ++ List -18 -3 - friend - f u n c a o G l o b a l . cpp [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ a . out 321
20.6
Por padr ao da linguagem, m etodos construtores, m etodos destrutores e m etodos virtuais n ao podem ser friend. Como visto no Cap tulo 4 Modelagem Orientada a Objeto e na Se ca o 6.4.7, uma classe de associa ca o e utilizada para representar conceitos que s o passam a existir com o relacionamento de duas ou mais classes. Para aumentar o encapsulamento do programa, uma classe de associa ca o pode ser toda privada, tendo, em seu interior, declara co es friend das classes que far ao acesso. Na medida do poss vel, classes/m etodos/fun co es friend n ao devem modicar o estado do objeto. Fun co es friend s ao comumente utilizadas para implementar a sobrecarga de operador (veja Se ca o 21.4). Observe que em uma hierarquia os m etodos da classe-base s ao herdados pela classeco es/m etodos declaradas como friend da classe-base n ao s ao herdaderivada, mas as fun das. Fun co es/m etodos friend n ao podem ser virtuais. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
386
Uma fun ca o friend pode acessar atributos est aticos da classe em que foi declarada como amiga (veja exemplo na listagem 20.3). S o use friend quando realmente necess ario. Em alguns casos o uso de friend viola conceitos de POO, devendo, por isso, ser evitados. 2 Tamb em podemos usar friend com fun co es e classes templates. Veremos templates no Cap tulo 27 Templates (ou Gabaritos). 2 Como a fun ca o friend n ao faz parte da classe, pois s o e amiga, ela n ao recebe um ponteiro impl cito this, ou seja, e preciso passar explicitamente o objeto a ser manipulado pela fun ca o.
20.7
Em nossos programas devemos usar, sempre que poss vel, o conceito de encapsulamento; desta forma estaremos diminuindo o acoplamento e as interdepend encias do sistema. O sistema ca mais livre. Como algumas classes e fun co es apresentam naturalmente um relacionamento mais ntimo, como se fossem amigas, C++ apresenta o conceito de friend, que d a a uma determinada classe/m etodo/fun ca o a possibilidade de acessar os membros ocultos (protegidos/privados) da classe declarada como amiga. Aprendemos, por meio dos exemplos apresentados, como implementar o conceito de friend em C++. No pr oximo cap tulo veremos que fun co es friend s ao comumente utilizadas para implementar a sobrecarga de operador (Se ca o 21.4).
20.8
Exerc cios
1. Descreva com suas palavras o conceito de friend. 2. D e exemplos de relacionamentos de amizade na vida real e em termos de programa ca o. 3. Qual a diferen ca pr atica do uso de friend com classes e m etodos? 4. No exemplo da listagem 20.1, tente acessar diretamente o atributo obj_y. 5. Modique as listagens 20.1 e 20.2, adicionando novos atributos, m etodos e relacionamentos de amizades. 6. Encontre o erro da listagem 20.3. 7. Substitua a fun ca o global por um m etodo membro na listagem 20.3.
Cap tulo 21
Sobrecarga de Operador
Neste cap tulo veremos uma introdu ca o ` a sobrecarga de operador (Se ca o 21.1), a lista de operadores que podem ser sobrecarregados (Se ca o 21.2) e os prot otipos para implementar a sobrecarga de operador em C++ (Se ca o 21.3). Em seguida apresenta-se a sobrecarga de operador como fun ca o friend (Se ca o 21.4) e como m etodo membro da classe (Se ca o 21.5). Veremos ainda um exemplo de classe com sobrecarga de operador e seu uso (Se ca o 21.6). No nal do cap tulo apresentam-se alguns prot otipos de sobrecarga de operador (Se ca o 21.7), como sobrecarregar new (Se ca o 21.8), como sobrecarregar new dentro de uma classe (Se ca o 21.8.1), e algumas senten cas (Se ca o 21.9).
21.1
Quando denimos uma classe, denimos um tipo do programador, adicionamos um conjunto de atributos e de m etodos que fazem sentido para a classe. Se criarmos uma classe Polinomio, podemos criar uma fun ca o para somar dois polin omios. Veja o exemplo: Exemplo: // Cria objetos do tipo Polinomio Polinomio pol_a, pol_b, pol_c; // Soma os polinomios pol_a e pol_b e armazena o resultado em pol_c Somar ( pol_a, pol_b, &pol_c ); Embora seja funcional, a nota ca o mostrada e t pica de um programa em C e Java. Seria interessante se pud essemos realizar opera co es como soma (+), subtra ca o (-) e multiplica ca o (*) utilizando os operadores usuais. O operador + realizaria a soma de dois polin omios; o operador * realizaria a multiplica ca o dos polin omios e assim por diante. O c odigo caria mais parecido com a linguagem matem atica. Veja o exemplo: Exemplo: pol_c = pol_a + pol_b; Assim, podemos denir sobrecarga de operador como a deni ca o das tarefas que determinado operador realiza sobre um tipo denido pelo programador. Note que com C++ podemos utilizar uma nota ca o muito mais clara e pr oxima da matem atica. Apresenta-se a seguir a lista de operadores de C++ que podem ser sobrecarregados. 387
388
21.2
Antes de apresentarmos a forma utilizada para implementar a sobrecarga dos operadores, e preciso classicar os operadores. Veja na Tabela 21.1 quais os operadores podem ser un arios ou bin arios. S ao un arios quando atuam sobre um u nico objeto e bin arios quando atuam sobre dois objetos. Observe que alguns operadores n ao podem ser sobrecarregados. No exemplo z = x + y;, o operador + e bin ario, opera sobre os objetos x e y. O operador = e bin ario pois armazena o resultado de "x+y" em z. No exemplo r++, o operador ++ e un ario, pois atua somente sobre o objeto r. Tabela 21.1: Operadores que podem ser sobrecarregados. Operadores bin arios + /= < <= , & ++ . ! %= == -> * -.* * = = != [] + :: / < &= <= () ! ?: % > |= >= new[] += << && delete[] & -= >> || new | *= > >= ->* delete
Nota: n ao podemos alterar a regra de preced encia e associatividade da linguagem (veja Tabela C.1). Isso signica que na seq u encia z = x + y;, primeiro ser a realizada a soma e depois a igualdade, e esta seq u encia n ao poder a ser alterada.
21.3
Veja a seguir o prot otipo para sobrecarga de operador como fun ca o friend e m etodo membro da classe. Observe que a declara ca o e a deni ca o s ao iguais ` as de um m etodo/fun ca o, apenas substitu mos o nome do m etodo/fun ca o pela palavra-chave operator. Em (1) temos a sobrecarga de operador un ario como fun ca o friend; observe que a fun ca o recebe apenas um par ametro o objeto obj1. Em (2) temos a sobrecarga de operador bin ario como fun ca o friend; observe que a fun ca o recebe dois par ametros os objetos obj1 e obj2. Como a fun ca o friend n ao faz parte da classe, pois s o e amiga, ela n ao recebe um ponteiro impl cito this, ou seja, e preciso passar explicitamente o objeto a ser manipulado pela fun ca o. Veja detalhes na Se ca o 21.4. Em (3) declaramos a sobrecarga de operador un ario como m etodo membro; observe que o m etodo n ao recebe nenhum par ametro. Lembre-se de que um m etodo de uma classe tem acesso a todos os atributos e aos outros m etodos da classe. Em (4) declaramos a sobrecarga de operador bin ario como m etodo membro; neste caso, o segundo objeto deve ser recebido como par ametro. Veja detalhes na Se ca o 21.5. Prot otipo: class CNomeClasse { Tipo atributo; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
FRIEND 21.4. SOBRECARGA DE OPERADOR COMO FUNC AO // (1) Sobrecarga de operador un ario como fun ca o friend (veja se ca o 21.4) friend CNomeClasse & operatorX (CNomeClasse & obj1); // (2) Sobrecarga de operador bin ario como fun ca o friend (veja se ca o 21.4) friend CNomeClasse & operatorX (CNomeClasse & obj1, CNomeClasse & obj2); // (3) Sobrecarga de operador un ario como m etodo membro (veja se ca o 21.5) CNomeClasse & operatorX(); // (4) Sobrecarga de operador bin ario como m etodo membro (veja se ca o 21.5) CNomeClasse & operatorX(CNomeClasse & obj2); }; // (1) Deni ca o de sobrecarga de operador un ario como fun ca o friend CNomeClasse & operatorX (CNomeClasse & obj1) {... return (CNomeClasse); } // (2) Deni ca o de sobrecarga de operador bin ario como fun ca o friend CNomeClasse & operatorX (CNomeClasse & obj1, CNomeClasse & obj2) {... return (CNomeClasse); } // (3) Deni ca o de sobrecarga de operador un ario como m etodo membro CNomeClasse & CNomeClasse::operatorX() {... return (CNomeClasse); } // (4) Deni ca o de sobrecarga de operador bin ario como m etodo membro CNomeClasse & CNomeClasse::operatorX(CNomeClasse & obj2) {... return (CNomeClasse); } Vamos abordar primeiro a sobrecarga como fun ca o friend.
389
21.4
Lembre-se que fun co es friend s ao fun co es amigas da classe; n ao fazem parte dela. A declara ca o friend fornece ` a fun ca o a possibilidade de acessar os atributos/m etodos do objeto como se zesse parte da classe ( e uma maneira de fazer com que a fun ca o amiga tenha acesso a todos os atributos e m etodos da classe. Veja Cap tulo 20 Friend). No exemplo a seguir a fun ca o TestaIgualdade() retorna verdadeiro (true) se p1==p2, isto e, se p1.x == p2.x e p1.y == p2.y. Exemplo: // Arquivo CPonto.h class CPonto { public: int x, y; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
390
21.5. SOBRECARGA DE OPERADOR COMO METODO MEMBRO DA CLASSE friend bool TestaIgualdade (const CPonto& p1, const CPonto& p2); }; // Arquivo CPonto.cpp bool TestaIgualdade(const CPonto& p1, const CPonto& p2) { return (p1.x == p2.x) && (p1.y == p2.y); }
Agora vamos montar nossa classe CPonto, substituindo o m etodo TestaIgualdade(), pela sobrecarga do operator== . Note que os operadores denidos com a palavra-chave friend tamb em t em acesso a todos os atributos e m etodos da classe. Exemplo: // Arquivo CPonto.h // Declara c~ ao da sobrecarga de operador bin ario como fun c~ ao friend class CPonto { public: int x, y; friend bool operator== (const CPonto& p1, const CPonto& p2); }; // Arquivo CPonto.cpp // Implementa c~ ao da sobrecarga de operadores bin arios como func~ ao friend bool operator==(const CPonto& p1, const CPonto& p2) { return (p1.x == p2.x) && (p1.y == p2.y); } Observe que a sobrecarga e declarada e denida da mesma forma que uma fun ca o comum. Au nica diferen ca e que, em vez de chamar TestaIgualdade(), usamos o nome operator==. Observe que o operador == verica se os atributos de p1 e p2 s ao iguais. Veja exemplo completo nas listagens 21.1, 21.2 e 21.3.
21.5
Outra forma de implementar a sobrecarga de operador e usar um m etodo membro da classe. Sendo um m etodo da classe, pode acessar diretamente os atributos do objeto. Observe que um operador un ario n ao receber a nenhum par ametro (prot otipo (3)) e um operador bin ario receber a apenas um (prot otipo (4)). Veja no exemplo a seguir que o operador ++ incrementa os valores de x (x++) e de y (y++). O operador + cria um terceiro objeto, com nome p3, no qual armazena a soma de p1 e p2. Observe na linha p3->x = this->x + p2.x; que armazena em p3->x a soma de this->x com p2.x. Exemplo: // CPonto.h class CPonto { public: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
21.6. EXEMPLO PRATICO DE SOBRECARGA DE OPERADOR int x,y; // Sobrecarga de operador un ario como m etodo membro CPonto& operator++(); // Sobrecarga de operador bin ario como m etodo membro CPonto& operator+ (const CPonto& p2); }; // CPonto.cpp CPonto& CPonto::operator++() { x++; y++; return *this; } CPonto& CPonto::operator+(const CPonto& p2) { CPonto *p3 = new CPonto; p3->x = this->x + p2.x; p3->y = this->y + p2.y; return *p3; }
391
21.6
Os exemplos apresentados a seguir mostram, na pr atica, como usar a sobrecarga de operador. Veremos nas listagens 21.1, e 21.2 novamente a classe CPonto, agora com v arios operadores sobrecarregados. Observe na listagem 21.1 o uso de sobrecarga de operador. Note que temos um conjunto de m etodos sobrecarregados como m etodo membro e outro como fun ca o friend. A listagem inclui explica co es adicionais. Listing 21.1: A classe CPonto com sobrecarga de operador.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 # ifndef CPonto_h # define CPonto_h # include < iostream > class CPonto { private : int x ; int y ; static int contador ; public : CPonto () : x (0) , y (0) { contador ++; } CPonto ( const int _x , const int _y ) : x ( _x ) , y ( _y ) { contador ++; } CPonto ( const CPonto & p ) { x = p.x; y = p.y; contador ++; } virtual ~ CPonto () { contador - -; } inline void Set ( const CPonto & p ) {
392
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 x = p.x; y = p.y;
} inline void Set ( const int &x , const int & y ) { this - > x = x ; // Uso de this this - > y = y ; } int X ( int _x ) { x = _x ; } int X () const { return x ; } int Y ( int _y ) { y = _y ; } int Y () const { return y ; } virtual void Desenha () ; static int Contador () { return contador ; }; // D e c l a r a c~ a o da s o b r e c a r g a de o p e r a d o r e s u n a r i o s como m e todo membro CPonto & operator ++( int ) ; // S o b r e c a r g a para ++ p CPonto & operator - -( int ) ; // S o b r e c a r g a para --p CPonto & operator ++() ; // S o b r e c a r g a para p ++ CPonto & operator - -() ; // S o b r e c a r g a para p - // D e c l a r a c~ a o da s o b r e c a r g a de o p e r a d o r e s b i n a r i o s como m e todo membro CPonto & operator + ( const CPonto & p2 ) const ; CPonto & operator - ( const CPonto & p2 ) const ; CPonto & operator = ( const CPonto & p2 ) ; CPonto & operator += ( const CPonto & p2 ) ; CPonto & operator -= ( const CPonto & p2 ) ; // D e c l a r a c~ a o da s o b r e c a r g a de o p e r a d o r e s b i n a r i o s como fun c~ a o friend friend bool operator == ( const CPonto & p1 , const CPonto & p2 ) ; friend bool operator != ( const CPonto & p1 , const CPonto & p2 ) ; // S o b r e c a r g a do o p e r a d o r de i n s e r c~ a o << , uso cout << ponto ; friend std :: ostream & operator < <( std :: ostream & out , const CPonto & p ) ; // S o b r e c a r g a do o p e r a d o r de e x t r a c~ a o >> , uso cin >> ponto ; friend std :: istream & operator > >( std :: istream & in , CPonto & p ) ; }; # endif
Na listagem 21.2 apresentamos a deni ca o da sobrecarga dos operadores para CPonto. O uso de this e descrito na Se ca o 15.4. Observe que a implementa ca o da sobrecarga dos operadores operator++(int) e operator++() s ao iguais; o mesmo ocorre com operator--(int) e operator--(). Os operadores + e - criam um objeto adicional CPonto* p3;, que e usado para armazenar o resultado da opera ca o. Note no in cio do operador= o uso da linha if( this == &p2) return *this; a qual impede que um objeto seja igualado a si mesmo. Finalmente, observe que os operadores (operator< < e operator> >) ser ao sempre sobrecarregados como m etodos friend. Listing 21.2: Implementa ca o da classe CPonto com sobrecarga de operador.
1 2 3 4 5 6 7 8 9 10 # include < iostream > # include " CPonto . h " int CPonto :: contador = 0; // M e todo v i r t u a l void CPonto :: Desenha () { std :: cout << " \ nCPonto : Coordenada x = " << x << " \ nCPonto : Coordenada y = " << y << std :: endl ; }
393
// D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r ++. S i m p l e s m e n t e i n c r e m e n t a x e y CPonto & CPonto :: operator ++( int ) { this - > x ++; this - > y ++; return * this ; } CPonto & CPonto :: operator ++() { this - > x ++; this - > y ++; return * this ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r - -. S i m p l e s m e n t e d e c r e m e n t a x e y CPonto & CPonto :: operator - -( int ) { this - >x - -; this - >y - -; return * this ; } CPonto & CPonto :: operator - -() { this - >x - -; this - >y - -; return * this ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r b i n ario + CPonto & CPonto :: operator +( const CPonto & p2 ) const { CPonto * p3 = new CPonto ; p3 - > x = this - > x + p2 . x ; p3 - > y = this - > y + p2 . y ; return * p3 ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r b i n ario CPonto & CPonto :: operator -( const CPonto & p2 ) const { CPonto * p3 = new CPonto ; p3 - > x = this - > x - p2 . x ; p3 - > y = this - > y - p2 . y ; return * p3 ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r = CPonto & CPonto :: operator =( const CPonto & p2 ) { if ( this == & p2 ) return * this ; // opcional , evita auto c o pia this - > x = p2 . x ; this - > y = p2 . y ; return * this ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r += CPonto & CPonto :: operator +=( const CPonto & p2 ) { this - > x += p2 . x ;
394
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 this - > y += p2 . y ; return * this ; }
// D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r -= CPonto & CPonto :: operator -=( const CPonto & p2 ) { this - > x -= p2 . x ; this - > y -= p2 . y ; return * this ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r == , como fun c~ a o friend bool operator ==( const CPonto & p1 , const CPonto & p2 ) { return ( p1 . x == p2 . x ) && ( p1 . y == p2 . y ) ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r != , como fun c~ a o friend bool operator !=( const CPonto & p1 , const CPonto & p2 ) { return !( p1 == p2 ) ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r de i n s e r c~ a o <<, como fun c~ a o friend std :: ostream & operator < <( std :: ostream & out , const CPonto & p ) { out << " ( " <<p . x << " , " <<p . y << " ) " ; return out ; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r de e x t r a c~ a o >>, como fun c~ a o friend std :: istream & operator > >( std :: istream & in , CPonto & p ) { in >> p . x ; in >> p . y ; return in ; }
Na listagem 21.3 apresentamos o teste de CPonto com sobrecarga. Para entender melhor o funcionamento do programa, compare cada linha com cout com a sa da gerada. Listing 21.3: Usando a sobrecarga de operador.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # include < iostream > # include " CPonto . h " using namespace std ; // E x e m p l o de c r i a c~ a o e uso do objeto CPonto com s o b r e c a r g a int main () { int x ; int y ; // Cria o b j e t o s do tipo CPonto com nomes p1 , p2 , p3 CPonto p1 , p2 , p3 ; // Usando o p e r a d o r >> cout << " Entre com os valores de p1 [ x enter y enter ]: " ; cin >> p1 ; cin . get () ; // Usando o p e r a d o r << cout <<" --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ;
395
// Usando o p e r a d o r = p2 = p1 ; cout << " Ap o s p2 = p1 " << endl ; cout << " --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ; // Usando o p e r a d o r == cout << " Testando p1 == p2 " << endl ; if ( p1 == p2 ) cout << " p1 == p2 " << endl ; else cout << " p1 != p2 " << endl ; // Usando o p e r a d o r ++ p2 ++; cout << " Ap o s p2 ++ " << endl ; cout << " --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ; // Usando o p e r a d o r = cout << " Fazendo p3 = p2 ++ " << endl ; p3 = p2 ++; cout << " --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ; // Usando o p e r a d o r = cout << " Fazendo p3 = ++ p2 " << endl ; p3 = ++ p2 ; cout << " --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ; // Usando o p e r a d o r != cout << " Testando p2 == p3 " << endl ; if ( p2 != p3 ) cout << " p2 != p3 " << endl ; else cout << " p2 == p3 " << endl ; // Usando o p e r a d o r e s + e = p3 = p1 + p2 ; cout << " Ap o s p3 = p1 + p2 " << endl ; cout << " --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ; // Usando o p e r a d o r e s p - - e --p p3 - -; -- p2 ; p1 = p2 - p3 ; cout << " Ap os p3 - -; -- p2 ; p1 = p2 - p3 ; " << endl ; cout << " --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ; // Usando o p e r a d o r e s p += e p -= p3 += p2 ; p1 -= p2 ; cout << " Ap os p3 += p2 ; p1 -= p2 ; " << endl ; cout << " --- p1 - - > " << p1 << " --- p2 - - > " << p2 << " --- p3 - - > " << p3 << endl ; return 0; } Entre com os valores de p1 [ x enter y enter ]:1 2 --- p1 - - >(1 , 2) --- p2 - - >(0 , 0) --- p3 - - >(0 , 0) Ap o s p2 = p1 --- p1 - - >(1 , 2) --- p2 - - >(1 , 2) --- p3 - - >(0 , 0) Testando p1 == p2 p1 == p2 Ap o s p2 ++ --- p1 - - >(1 , 2) --- p2 - - >(2 , 3) --- p3 - - >(0 , 0)
396
Fazendo p3 = p2 ++ --- p1 - - >(1 , 2) --- p2 - - >(3 , 4) --- p3 - - >(3 , 4) Fazendo p3 = ++ p2 --- p1 - - >(1 , 2) --- p2 - - >(4 , 5) --- p3 - - >(4 , 5) Testando p2 == p3 p2 == p3 Ap o s p3 = p1 + p2 --- p1 - - >(1 , 2) --- p2 - - >(4 , 5) --- p3 - - >(5 , 7) Ap os p3 - -; -- p2 ; p1 = p2 - p3 ; --- p1 - - >( -1 , -2) --- p2 - - >(3 , 4) --- p3 - - >(4 , 6) Ap os p3 += p2 ; p1 -= p2 ; --- p1 - - >( -4 , -6) --- p2 - - >(3 , 4) --- p3 - - >(7 , 10)
21.7
Como sobrecarregar ++ e --
Veja a seguir o prot otipo para sobrecarga dos operadores ++ e --. Observe que, para sobrecarga do operator++ (pr e-xado, como em ++obj), n ao passamos nenhum par ametro, mas, para sobrecarrega do operator++ (p os-xado, como em obj++), passamos como par ametro um int. Note que o par ametro int n ao e utilizado; ele e necess ario apenas para diferenciar obj++ de ++obj. Prot otipo: Tipo operator++(); Operador para Tipo operator- -(); Operador para Tipo operator++(int); Operador para Tipo operator- -(int); Operador para ++obj; Incremento Pr e-xado. - -obj; Decremento Pr e-xado. obj++; Incremento P os-xado. obj- -; Decremento P os-xado.
21.8
O operador new pode ser sobrecarregado de tr es formas diferentes. Veja a seguir os prot otipos para sobrecarga de new. Observe que este est a no escopo global. Prot otipo: void* ::operator new(std::size t size) throw (std::bad alloc); // (1) void* ::operator new(std::size t size, const std::nothrow t &) throw(); // (2) void* ::operator new(std::size t size, void* ptr) throw (); // (3) delete ptr->T(); A sobrecarga-padr ao de new e dada em (1). Para usar new padr ao fa ca: new T; Outra sobrecarga para new e new(nothrow) , uma vers ao de new que n ao lan ca exce co es (item (2)). Para usar new(nothrow) fa ca: new (std::nothrow) T; . O item (3) ilustra o uso de new in place. Com ele, o novo objeto vai ser armazenado em um endere co de mem oria existente, ou seja, new in place n ao pede mem oria para o sistema operacional, pois usa a mem oria do objeto previamente alocado (existente). Note que o sizeof() do novo objeto deve ser menor ou igual ao anterior. Para usar new in place fa ca: new (ptr) T; . Note que, quando usamos new in place, devemos chamar o destrutor do objeto criado explicitamente. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
397
Dica: evite usar new(nothrow), pois ele elimina o lan camento de exce co es, e, como o uso de exce co es e um padr ao da linguagem, os usu arios da sua biblioteca/programa esperam seu uso. A dica e: se for realmente necess ario usar new(nothrow), seu uso deve ser muito bem documentado.
21.8.1
O exemplo da listagem 21.4 mostra a declara ca o e o uso de sobrecarga de new para uma classe do usu ario. Observe que sobrecarregamos todas as tr es formas de new. Em cada sobrecarga enviamos uma mensagem para tela e, em seguida, chamamos o operador global equivalente de new. Note que na chamada a new o primeiro par ametro std::size_t n e passado implicitamente. Listing 21.4: Sobrecarregando new em uma classe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 # include < iostream > using namespace std ; class CNome { char ch ; public : // S o b r e c a r g a para new Padr~ ao static void * operator new ( std :: size_t n ) throw () { cout << " Usando new padr~ a o da classe " << endl ; return :: operator new ( n ) ; } // S o b r e c a r g a para new n o t h r o w static void * operator new ( std :: size_t n , const std :: nothrow_t & r ) throw () { cout << " Usando new nothrow da classe " << endl ; return :: operator new (n , r ) ; } // S o b r e c a r g a para new in place static void * operator new ( std :: size_t n , void * ptr ) throw () { cout << " Usando new in place da classe " << endl ; return :: operator new ( n , ptr ) ; } CNome () { cout << " Construiu o objeto CNome . " << endl ; ~ CNome () { cout << " Destruiu o objeto CNome . " << endl ; }; class CAux { public : int x ; CAux () { cout << " Construtor classe auxiliar \ n " ; } ~ CAux () { cout << " Destrutor classe auxiliar \ n " ; } }; int main () { // Usando new padr~ ao CNome * prt_padrao = new CNome ; delete prt_padrao ;
} }
398
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
// Usando new n o t h r o w CNome * prt_nothro w = new ( std :: nothrow ) CNome ; delete prt_nothro w ; // Usando new in place // Cria objeto que tem m e m o r i a s u f i c i e n t e para caber CNome CAux * ptr_inpla c e = new CAux ; // Cria objeto CNome usando new in place e a r m a z e n a em p t r _ i n p l a c e new ( static_cast < void * >( ptr_inpla ce ) ) CNome ; // Chama e x p l i c i t a m e n t e o d e s t r u t o r do objeto criado , p r e c i s a do cast ( reinterpret_ ca s t < CNome * >( ptr_inplac e ) ) - >~ CNome () ; // Chama o d e s t r u t o r do objeto o r i g i n a l delete ptr_inplac e ; return 0; } Usando new padr~ a o da classe Construiu o objeto CNome . Destruiu o objeto CNome . Usando new nothrow da classe Construiu o objeto CNome . Destruiu o objeto CNome . Construto r classe auxiliar Usando new in place da classe Construiu o objeto CNome . Destruiu o objeto CNome . Destrutor classe auxiliar
Dica importante: se sobrecarregar new em uma classe, implemente todas as tr es formas de sobrecarga para que o usu ario da sua biblioteca/programa n ao tenha surpresas desagrad aveis. Isto e necess ario, pois se voc e sobrecarregar apenas new, e desconsiderar new(nothrow), um usu ario pode usar as diferentes formas de new no mesmo programa, e n ao ir a compreender o porqu e do funcionamento diferente. Novamente, a boa documenta ca o do sistema e importante.
21.9
Voc e j a deve ter percebido que muitos operadores da linguagem C++ s ao sobrecarregados para os tipos internos. Por exemplo, o operador * e utilizado para multiplica ca o, declara ca o de ponteiros ou para obter o conte udo de ponteiros. Tente utilizar sempre sobrecarga como m etodo membro. A sobrecarga como fun ca o friend cria uma fun ca o global, que e desaconselh avel em um programa orientado a objeto. Criar uma sobrecarga para += n ao signica que voc e sobrecarregou + e =. Por padr ao, somente sobrecarregue new e delete como m etodos est aticos. Operadores de atribui ca o (=, +=,-=, ..) devem retornar uma refer encia ao objeto, pois podemos ter algo como obj1 = obj2 = obj3;. Exemplo: T& operator=(const T& obj) Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
399
Por padr ao, quando criar uma classe, sempre implemente o construtor de c opia e o operador de atribui ca o (operator=()). Lembre-se de que o operator=() deve evitar a autoc opia. Exemplo: T& T::operator=(const T& src) { if(this == &src) // Evita autoc opia return *this; ...copiar atributos... return *this; // Retorna refer^ encia } A utiliza ca o do operador de atribui ca o (a = b) e do construtor de c opia por inicializa ca o (int a = b;) s ao duas opera co es diferentes. Para evitar surpresas, crie voc e mesmo os operadores de c opia e de atribui ca o sempre que existirem atributos din amicos. Exemplo: class A { A(); // Construtor A(const A& ); // Construtor de c opia por inicializa c~ ao A& operator=(const A& );// Operador de atribui c~ ao }; Os operadores de atribui ca o =, apontador para membro ->, subscrito [] e par enteses () s o podem ser sobrecarregados como m etodos membro da classe (n ao podem ser friend). Quando for implementar a sobrecarga de operador esteja atento a efeitos como: Exemplo: obj1 = obj2 = obj3; // Encadeamentos string1 = string2 = "texto"; // Tipos diferentes complex_c = complex_a + double_x; // Sobrecarga m ultipla complex_d = double_y + complex_a; Observe que os operadores < < e > >, quando aplicados a streams, sempre ser ao sobrecarregados como fun ca o friend. Para reduzir o n umero de sobrecargas, utilize m etodos de convers ao (veremos as convers oes no Cap tulo 25 Convers oes). Veja a seguir outros prot otipos de sobrecarga. Prot otipo: Tipo* operator & (); Operador endere co de. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
400 Tipo operator & (Tipo); Operador & bin ario. Tipo* operator->(); Operador de acesso. Tipo operator-(); Operador - , un ario. Tipo operator-(Tipo); Operador -, bin ario. Tipo & operator[](const Tipo &); Operador subscrito. Tipo & operator()(Tipo &); Operador chamada de fun ca o.
2 Quando sobrecarregar < <, n ao envie a sa da diretamente para cout; envie-a para a stream, pois se pode ter algo como: Exemplo: cout < < "teste " < < objeto < < " "; 2 Segundo Stroustrup [Bjarne, 1999] devido a um acidente hist orico, os operadores = (atribui ca o), & (endere co) e seq uenciamento () t em signicados predenidos quando aplicados a objetos de classes. Voc e pode impedir o acesso a estes (e qualquer outro operador), declarando-os como private. 2 Operadores n ao podem ser denidos para receber exclusivamente ponteiros, exceto (=, &). 2 O primeiro argumento de um operador sobrecarregado deve ser um lvalue. 2 A sobrecarga como m etodo membro n ao e poss vel com m etodos est aticos (static), porque estes n ao recebem implicitamente o ponteiro this. 2 Uma sobrecarga e uma chamada de fun ca o; assim, os par ametros podem denir o namespace a ser utilizado. 2 Para que uma sobrecarga se torne mais r apida, declare-a como inline.
21.10
C++ e uma linguagem de programa ca o sensacional! Com ela, voc e pode sobrecarregar os operadores (+, -, *, /, = etc.) de forma que o exemplo do polin omio possa ser utilizado, ou seja, com C++ podemos utilizar uma nota ca o muito mais clara e pr oxima da matem atica. Anal de contas, o c odigo pol_c = pol_a + pol_b; e muito mais claro que Somar ( pol_a, pol_b, &pol_c ); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
401
Observe que C++ e a programa ca o orientada a objeto aproximam muito os conceitos computacionais dos conceitos f sicos e matem aticos, o que facilita o entendimento e o desenvolvimento de programas para as areas de exatas e engenharia. Vimos que temos operadores un arios e bin arios, e que nem todos os operadores podem ser sobrecarregados. Aprendemos que podemos implementar a sobrecarga de operador utilizando m etodos membro da classe ou fun co es friend. Apresentamos um exemplo a classe . No nal do cap tulo vimos as diferentes formas de sobrecarga para new.
21.11
Exerc cios
1. Diga com suas palavras as vantagens do uso de sobrecarga de operador. Destaque aspectos relacionados ` as areas cient cas como matem atica, estat stica e m etodos num ericos. 2. Implemente exemplo com sobrecarga para operador + como operador un ario e bin ario. 3. Documente a classe CPonto das listagens 21.1 e 21.2. 4. Implemente uma classe CPolinomio com sobrecarga para os operadores +, -, =, ==. Use fun co es friend. 5. Implemente uma classe CMatriz com sobrecarga para os operadores +, -, *, / e []. Use m etodos membro. 6. Explique o c odigo que segue (consulte a Se ca o G.3 Enumera co es). Em seguida, implemente o c odigo para o operator- -. Os estados de um processo s ao discutidos na Se ca o ?? e apresentados na Figura ??. Exemplo: enum EEstado {idle, ready, standby, running, blocked, suspended, zoombied, stopped}; EEstado& operator++(EEstado& e) { if ( e != stopped) e++; else e = idle; }
402
Cap tulo 22
Entrada e Sa da
Veremos neste cap tulo a hierarquia de classes fornecidas pelo C++ para entrada e sa da de dados, bem como denir a localidade a ser utilizada e formatar a sa da e a entrada de dados. Iniciamos com uma introdu ca o ` a entrada e sa da de dados (Se ca o 22.1). Em seguida, apresentamos a biblioteca-padr ao para entrada e sa da de dados (Se ca o 22.2): a classe ios_base (Se ca o 22.3), a classe <iomanip> (Se ca o 22.4), a classe <ostream> (Se ca o 22.5), a classe <ios> (Se ca o 22.6), a classe <istream> (Se ca o 22.7) e a classe <sstream> (Se ca o 22.8). Veremos ainda conceitos avan cados (Se ca o 22.9) como a classe locale (Se ca o 22.9.2) e o uso de facets (Se ca o 22.9.3). Por m, veremos algumas senten cas para stream (Se ca o 22.10). Nota: um guia de refer encia ` as classes e aos m etodos de entrada e sa da est a dispon vel em http://www.cplusplus.com/reference/.
22.1
Nos cap tulos anteriores e nos exemplos apresentados, aprendemos a utilizar os objetos cin e cout para entrada e sa da de dados. Exemplo: using namespace std; int x; // Cria objeto do tipo int com nome x // Enviar para tela o conjunto de caracteres cout < < "Entre com o valor de x:"; cin > > x; // Pega o n umero digitado e armazena em x cin.get(); // Pega o enter // Enviar para tela o valor de x cout < < "Valor de x= " < < x < < endl; Neste exemplo, usamos os objetos cout e cin, que s ao stream s. Uma stream encapsula o conceito de uxo de caracteres. De maneira geral, um objeto A do tipo stream insere (< <) ou extrai (> >) uma seq u encia de caracteres em um objeto B. Normalmente as streams est ao associadas a dispositivos f sicos. O objeto cout, por exemplo, j a vem previamente conectado com o dispositivo monitor, e o objeto cin j a vem previamente conectado com o dispositivo teclado. Diversos dispositivos do seu computador funcionam utilizando streams. Veja os exemplos: 403
404
O teclado de seu computador tem um buer onde s ao armazenados os caracteres digitados. Esses caracteres s ao extra dos do buer do teclado pelo objeto cin. As sa das auxiliares (com1, com2, com3, com4) utilizam e funcionam com streams de caracteres. O modem, as impressoras seriais, entre outros dispositivos, tamb em utilizam e funcionam com streams de caracteres. Programas podem comunicar-se utilizando stream s. No Cap tulo ?? Introdu ca o ao Processamento Paralelo com M ultiplos Processos, utilizaremos streams para trocar dados entre processos, isto e, entre dois ou mais programas. Pois bem, este cap tulo apresenta uma hierarquia de classes oferecidas pela biblioteca-padr ao de C++ para manipula ca o de stream s (entrada e sa da de dados).
22.1.1
Streams buferizadas
Vimos que uma stream tem um buer de mem oria utilizado para armazenar caracteres (Figura 8.2). Quando o buer enche, os caracteres s ao enviados para o dispositivo de destino. A linha cout < < "Entre com o valor de x: "; insere os caracteres "Entre com o valor de x: " no buer de cout (os caracteres seguem o uxo denido pelas setas < <). Observe que os caracteres ainda n ao foram enviados para a tela. Quando voc e usa cin > > x;, o objeto cin envia para o objeto cout um comando flush(), o qual descarrega o buer de cout, enviando todos os caracteres para o dispositivo de sa da, no caso o monitor. Em resumo, o buer de cout armazena temporariamente os caracteres enviados para a tela com cout< <. Quando o objeto cout recebe um comando flush(), ou quando o buer enche, todo conte udo do buer e enviado para a tela, e o buer e esvaziado. Note que a vantagem do uso de um buer e que as opera co es de sa da s ao executadas mais rapidamente.
22.2
Biblioteca de entrada e sa da
A Figura 22.1 ilustra a hierarquia de classes para entrada e sa da de dados com C++. De modo geral, um objeto dessa hierarquia pode armazenar, receber e fornecer caracteres. Um objeto da hierarquia de entrada e sa da e uma stream, a qual cont em um buer onde cam armazenados os caracteres e um conjunto de atributos utilizados na formata ca o desses caracteres. Note que a grande vantagem desta biblioteca e sua facilidade de uso. Por exemplo: o envio de dados para tela e para dispositivos externos (como disco, sa da auxiliar, outros programas) funciona exatamente da mesma forma. Outra grande vantagem e sua portabilidade, isto e, o programa vai funcionar em praticamente todas as plataformas de interesse. Outro exemplo e o uso da classe <locale>, utilizada para denir a localidade (pais de interesse). Com locale podemos denir que o programa funciona usando portugu es do Brasil ou o tradicional padr ao de C. A classe ios_base cont em um conjunto de m etodos b asicos que s ao herdados pelas demais etodo setf() e um conjunto de atributos (status, classes da hierarquia. Essa classe tem o m ags e informa co es de formata ca o) que podem ser utilizados para deni ca o do formato de Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
405
entrada/sa da de dados. Observe que a classe ios_base e independe do tipo de caractere (n ao e uma classe template). A classe <ios> e herdeira de ios_base. Os m etodos good(), bad(), fail() fornecem o estado da stream. Observe que <ios> depende do tipo de locale selecionado. A classe <istream> e utilizada para entrada de dados. C++ fornece o objeto cin do tipo <istream> para leitura de dados do teclado. A classe <ostream> e utilizada para sa da de dados. C++ fornece o objeto cout do tipo <ostream>, o qual e utilizado para enviar caracteres para a tela. A classe <iostream> pode ser utilizada para entrada e sa da de dados. A classe <iomanip> cont em um conjunto de manipuladores que podem ser utilizados para formata ca o da sa da de dados. Como j a visto as classes derivadas de <ios> t em objetivos predenidos. A classe <streambuf> e utilizada nos casos em que a formata ca o n ao precisa ser previamente denida. A classe <sstream> e uma mistura da classe <iostream> com a classe <string>, funcionando ora como uma <string>, ora como uma <iostream>. Em alguns casos, desejamos enviar e receber dados para um dispositivo externo, como um arquivo de disco; nestes casos, utilizamos a classe <fstream> e as classes <ofstream> e <ifstream>. A classe <string> e apresentada no Cap tulo 24 Classe <string>. A hierarquia de classes ilustrada na Figura 22.1 foi desenvolvida utilizando o conceito de templates (gabaritos). Isto signica que esta foi implementada para tipos gen ericos de caracteres. Na pr atica, as classes s ao constru das para dois tipos de caracteres: o char, j a utilizado no C, e o wchar_t. O char suporta 256 caracteres e o wchar_t, cerca de 16.000 caracteres. O wchar_t foi desenvolvido para dar suporte a diversas linguagens (ingl es, portugu es etc.). Veremos os templates no Cap tulo 27 Templates (ou Gabaritos). Vamos iniciar a descri ca o da biblioteca de entrada e sa da de dados, descrevendo a classe ios_base. Nota: veremos o acesso a arquivos de disco no Cap tulo 23 Entrada e Sa da com Arquivos de Disco.
22.3
A classe ios_base
A classe ios_base cont em atributos com informa co es de formata ca o da stream. Observe no diagrama de classes da Figura 22.1 que ios_base n ao considera informa co es do locale. Veremos a seguir os m etodos de ios_base. Na descri ca o de cada m etodo colocamos, em negrito, na primeira linha, a declara ca o do m etodo e abaixo, uma breve descri ca o. M etodos de ios base fmtags setf(fmtags fmt); O m etodo setf() e um dos principais m etodos da classe ios_base, sendo utilizado com o objetivo de denir a formata ca o de sa da. Veja na Tabela 22.1 os ags que podem ser utilizados para alterar os atributos da stream por meio do m etodo setf(). Lembre-se de que diferentes ags podem ser combinados com o operador |, como em setf(ios::scientific | ios::right). O m etodo setf() retorna os ags anteriores. void unsetf(fmtags mask); Desativa formata ca o de sa da. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
406
<ios>
+bad() +clear() +eof() +fail() +good() +rdstate() +setstate() +fill() +rdbuf()
locale
+locale() +name() +global() +classic()
<iomanip>
+boolalpha() +noboolalpha() +showbase() +noshowbase() +showpoint() +noshowpoint() +showpos() +noshowpos() +skipws() +noskipws() +uppercase() +nouppercase() +left() +right() +dec() +hex() +oct() +fixed() +scientific() +endl() +ends() +flush() +ws() +setbase() +setfill() +setprecision() +setw() +unitbuf() +nounitbuf() +setiosflags() +resetiosflags()
<string>
+getline()
<sstream> <istream>
+gcount() +get() +getline() +ignore() +read() +tellg() +seekg() +putback() +unget() +peek() +sync() +operator>>()
<ostream>
+tellp() +seekp() +put() +write() +operator<<() +flush()
+str()
<streambuf>
<iostream>
<ofstream>
+is_open() +open() +close()
<ifstream>
+is_open() +open() +close()
<stringstream> <istringstream>
<ostringstream> <fstream>
407
streamsize width(streamsize n); O m etodo width() dene a largura m nima do campo; isto signica que, se a largura e6 e o n umero enviado para a tela tem 9 d gitos de precis ao, ser ao mostrados os 9 d gitos. Isto e v alido apenas para a pr oxima sa da. streamsize width(); Retorna a largura do campo. streamsize precision(streamsize n); Dene a precis ao da sa da; o valor default e 6 caracteres. Retorna o valor da precis ao anterior. locale imbue(const locale& loc); Seta nova localidade, retorna localidade anterior (veja listagem 22.7). locale getloc(); Retorna a localidade. fmtags ags(); Retorna os ags atuais. fmtags ags(fmtags ags); Seta os ags, retorna ags anteriores.
Tabela 22.1: Flags para o m etodo setf(). Flags de ios base ios::skipws ios::left ios::right ios::internal ios::shombase ios::showpoint ios::uppercase ios::showpos ios::scientific ios::fixed ios::unitbuf ios::stdio ios::dec ios::oct ios::hex ios::boolalpha Signicado Ignora espa cos em branco (somente entrada). Alinhamento ` a esquerda. Alinhamento ` a direita. Caractere de preenchimento entre o sinal +/- e o n umero (nointernal). Mostra indicador de base, 0x para hexadecimal (s o sa da). Mostra ponto decimal (utuante) zeros n ao signicativos no nal. Mai uscula para sa da de valores hexadecimais (nouppercase). Mostra sinal positivo (+) se maior que 0 (noshowpos). Usa nota ca o cient ca. Usa nota ca o xa. Descarrega stream ap os inser ca o. Descarrega stdout e stderr ap os inser ca o. Base 10, decimal. Base 8, octal. Base 16, hexadecimal. Exibe true/false no lugar de 1 e 0.
Veja a seguir um exemplo de uso da classe ios::base. Lembre-se de que cout e um objeto do tipo ostream, herdeiro da classe ios_base, logo cout pode acessar o m etodo setf() diretamente. Observe a forma como os ags da Tabela 22.1 s ao passados para o m etodo setf(). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
408 Exemplo: #include<iostream> using namespace std; int main() { float x = 5.1234567890; // Armazena flags atuais ios::fmtflags flags = cout.flags();
// Muda flags, usa formato cient fico e alinhamento ` a esquerda cout.setf(ios::scientific); // Ativa nota c~ ao cient fica cout.setf(ios::left); // Ativa alinhamento ` a esquerda // cout.setf(ios::scientific | ios::left); // Alternativa cout < < "Valor de x = " < < x < < endl; cout.flags(flags); // Retorna para flags anteriores cout < < "Valor de x = " < < x < < endl; return 0; } Veja no exemplo da listagem 22.1 o uso de sa da formatada. As opera co es de sa da para tela podem ser realizadas com o objeto cout e o operador de inser ca o (< <). O exemplo mostra sa da com e sem showpoint e, em seguida, dene a largura do campo em 5 caracteres e imprime o valor de i. Veja na sa da que o n umero 1 e impresso a partir da coluna 4. Posteriormente, entra em um la co for onde dene a precis ao de sa da e imprime o contador i num campo com largura 2, e, ent ao, o valor de d. Observe que d e truncado e n ao arredondado. No nal, dene o caractere de preenchimento como sendo * e imprime i. Nota: note que dentro de main() criamos um inteiro i e dentro do for um novo inteiro i e que mudan cas no i do for n ao alteraram o valor de i de main(), isto ocorre porque os mesmos est ao em escopos diferentes. Veja Se ca o B.4. Listing 22.1: Formata ca o b asica da sa da de dados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # include < iostream > # include < string > using namespace std ; int main () { int i = 5; double d = 1.23456789 ; string nome = " Clube Palestra It a lia - Palmeiras " ; char letra = c ; char cstring [] = " STRING_DE _C " ; cout << << << << << " \n - - - - - - - - - - - - - - - - - Formato padr~ ao - - - - - - - - - - - - - - - - " " \ nint_i double_d string_nom e char_c char * _cstring " " \n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\ n " i << " " << d << " " << nome << << letra << " " cstring << endl ;
cout << " Alinhamen t o a esquerda " << endl ; cout . setf ( ios :: left ) ; cout . width (10) ; cout << i << " " ;
409
cout << " \ n A l i n h a m e n t o a direita " << endl ; cout . setf ( ios :: right ) ; cout . width (10) ; cout << i << endl ; cout << " Formato cient fico " << endl ; cout . setf ( ios :: scientific ) ; cout << d << endl ; cout << " Mostra sinal positivo " << endl ; cout . setf ( ios :: showpos ) ; cout << d << endl ; cout << " Seta precis~ a o num e rica em 12 " << endl ; cout . precision (12) ; cout << d << endl ; cout << " Seta espa c o do campo em 20 caracteres " << endl ; cout . width (20) ; cout << i << endl ; cout << " Seta o caractere de p r e e n c h i m e n t o # " << endl ; cout . width (20) ; cout . fill ( # ) ; cout << i << endl ; cout << " Escreve na tela 5 caracteres da cstring " << endl ; cout . write ( cstring , 5) ; cout << endl ; cout << " Imprime a letra G na tela " << endl ; cout . put ( G ) ; cout << endl ; cout << " Imprime a letra " << ends << letra << endl ; cout << " Imprime c o digo ascii da letra \ n " << static_cast < int >( letra ) << endl ; cout << " Imprime o n u mero 12 em hexadecim al \ n " << hex << 12 << endl ; cout << " Parenteses evita ambig u idade , imprime \"9\"\ n " << (5 + 4) << endl ; cout << " Imprime string de C \ n " << cstring << endl ; cout . flush () ; // U t i l i z a d o para d e s c a r r e g a r o buffer
cout << " Usando boolalpha : 1 = " << boolalpha << ( bool ) 1 << " \ nUsando noboolalp h a : 1 = " << noboolalph a << ( bool ) 1 << endl ; return 0; } - - - - - - - - - - - - - - - - - Formato padr~ ao - - - - - - - - - - - - - - - int_i double_d string_nom e char_c char * _cstring ----------------------------------------------5 1.23457 Clube Palestra It a lia - Palmeiras c STRING_DE _ C Alinhamen to a esquerda 5 Alinhamen to a direita
410
5 Formato cient fico 1.234568 e +00 Mostra sinal positivo +1.234568 e +00 Seta precis~ a o num e rica em 12 + 1 . 2 3 4 5 6 7 8 9 0 0 0 0 e +00 Seta espa c o do campo em 20 caracteres +5 Seta o caractere de p r e e n c h i m e n t o # ##################+5 Escreve na tela 5 caractere s da cstring STRIN Imprime a letra G na tela G Imprime a letrac Imprime c o digo ascii da letra +99 Imprime o n u mero 12 em hexadecim al c Parentese s evita ambig u idade , imprime "9" 9 Imprime string de C STRING_D E_ C Usando boolalpha : 1 = true Usando noboolalp ha : 1 = 1
Veja exemplo na listagem 22.2. Observe que o valor na sa da de cout e arredondado e n ao truncado e que utilizamos endl para incluir uma linha nova e descarregar o buer (cout < < endl;). O manipulador flush descarrega o buer (cout.flush();). Listing 22.2: Formata ca o da sa da de dados usando o m etodo setf().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # include < iostream > using namespace std ; int main () { int i = 16; double d = 1 . 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; char c = c ; cout << " --> Mostrando n u meros em ponto flutuante " << endl ; cout . unsetf ( ios :: showpoint ) ; cout << " Sem shownpoin t 3.33000= " << 3.33000 << endl ; cout . setf ( ios :: showpoint ) ; cout << " Com shownpoin t 3.33000= " << 3.33000 << endl ; cout << " --> Definindo a largura do campo " << endl ; cout . width (5) ; cout << i << endl ; cout << " --> Definindo a precis~ a o da sa da " << endl ; for ( int i = 1; i <= 5; i ++) { cout << " Precis~ ao = "; cout . width (2) ; cout << i ; cout . precision ( i ) ; cout << " d = " << d << endl ; } cout << " --> Definindo o caractere de p r e e n c h i m e n t o " << endl ;
411
--> Mostrando n u meros em ponto flutuante Sem shownpoint 3 . 3 3 0 0 0 = 3 . 3 3 Com shownpoint 3 . 3 3 0 0 0 = 3 . 3 3 0 0 0 --> Definindo a largura do campo 16 --> Definindo a precis~ a o da sa da Precis~ a o = 1 d =1. Precis~ a o = 2 d =1.1 Precis~ a o = 3 d =1.12 Precis~ a o = 4 d =1.123 Precis~ a o = 5 d =1.1235 --> Definindo o caractere de p r e e n c h i m e n t o ********16
22.4
A classe <iomanip>
A <iomanip> e uma classe de manipuladores que permite a deni ca o de um conjunto de par ametros relacionados ` a formata ca o da sa da de dados. A Tabela 22.2 mostra alguns manipuladores de <iomanip>, se o mesmo e usado para entrada (E) e sa da (S) e seu signicado. Muitos dos manipuladores de <iomanip> s ao equivalentes a alguns ags do m etodo setf(). Observe que, na coluna de signicado, colocamos, dentro de [], o manipulador inverso. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
412
Tabela 22.2: Manipuladores da classe <iomanip>. Manipulador showpos showpoint skipws upercase left/right fixed/scientific endl ends flush resetiosflags(long fl) setbase(int i) setfill(char) setiosflags(lonf fl) setprecision(int n) setw(int w) ws dec oct hex showbase boolalpha unitbuf E/S S S S S S S S S S E/S S E/S E/S E/S E/S S E/S E/S E/S S E/S S Signicado Mostra sinal positivo (+) [noshowpos]. Adiciona zeros [noshowpoint]. Ignora espa cos em branco [noskipws]. Letras mai usculas [nouppercase]. Alinhamento ` a esquerda/direita. Formato xo/cient co. Insere nova linha \n e libera stream [flush]. Envia caractere nulo \0. Esvazia o buer da stream. Dene os bits de ios indicados em long fl. Formata n umeros na base i. Dene o caractere de preenchimento. Dene os bits de ios indicados em long fl. Dene a precis ao float para n casas. Dene o tamanho de campos para w espa cos. Ignora caracteres em branco. Formata n umeros na base decimal (10). Formata n umeros na base octal (8). Formata n umeros na base hexadecimal (16). Se ativo mostra base. Se ativo, usar true/false no lugar de 1/0 [noboolalpha]. Esvazia o buer ap os cada opera ca o [nounitbuf].
No exemplo a seguir testamos o uso de showpoint, boolalpha e uppercase. Exemplo: #include<iostream> int main() { int x = 11; std::cout < < x < < std::endl; < < "Sa da em hexadecimal\n" < < hex < < x < < "\nSa da com showpoint\n" < < showpoint < < x < < "\nSa da com boolalpha e uppercase\n" < < boolalpha < < uppercase < < (bool)0 < < endl; return 0; } Veja no exemplo da listagem 22.3 o uso de sa da formatada usando os manipuladores da classe <iomanip>. Compare esse exemplo com a listagem 22.1. O exemplo inicia-se denindo a largura do campo com setw(). Em seguida, usa setprecision() para denir a precis ao de sa da e setfil() para denir o caractere de preenchimento. Listing 22.3: Formata ca o da sa da de dados usando a classe <iomanip>.
1 # include < iostream >
413
--> Definindo 16 --> Definindo Precis~ ao = 1 Precis~ ao = 2 Precis~ ao = 3 Precis~ ao = 4 Precis~ ao = 5 Precis~ ao = 6 Precis~ ao = 7 Precis~ ao = 8 Precis~ ao = 9 Precis~ a o =10 --> Definindo ********16 --> Definindo hex 15 = f oct 15 =17 dec 15 =15 base 10=15
a largura do campo a precis~ a o da sa da d =1 d =1.2 d =1.23 d =1.235 d =1.2346 d =1.23457 d =1.234568 d =1.234567 9 d =1.2345678 9 d =1.2345678 9 o caractere de p r e e n c h i m e n t o formato do n u mero ( hexadecimal , octal e decimal )
Um bool tem como sa da os valores 0 ou 1. Para ter na sa da "false" ou "true", basta ativar este tipo de sa da utilizando o manipulador boolalpha:
Exemplo: cout < < boolalpha < < 0; // Sa da: true cout < < boolalpha < < 1; // Sa da: false Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
414
22.5
A classe <ostream>
A classe <ostream> e utilizada para enviar caracteres para um dispositivo (sa da de dados). C++ cria automaticamente o objeto cout que pode ser utilizado para sa da na tela do computador. Observe que cout e uma abrevia ca o de C out. A formata ca o da sa da para a tela e realizada em dois passos. Primeiro, denem-se os atributos do objeto ostream (alinhamento, espa camento, formatos), e, em seguida, envia-se a stream para a sa da desejada. Veja as listagens 22.1, 22.2 e 22.3. Veja a seguir os m etodos da classe <ostream>. M etodos de <ostream> ostream& ush(); Descarrega o buer. Como dito anteriormente, uma stream tem um buer onde os caracteres cam armazenados. Quando o buer enche, os caracteres s ao descarregados, isto e, enviados para o seu destino. O m etodo flush() solicita o descarregamento imediato do buer. A classe <iomanip> fornece o manipulador flush. ostream& put(char ch); Insere o caractere ch na stream. long tellp(); Retorna a posi ca o do ponteiro de escrita put. Veja Se ca o 23.5.1. ostream & operator< <(ostream & ); Operador de inser ca o. ostream & write(const signed char* s, streamsize n); Envia para ostream a string s com at e n caracteres. N ao interpreta o conte udo de s. Veja na Tabela 22.3 os caracteres de escape, os quais, quando inseridos em uma stream, realizam uma determinada tarefa. Exemplo: cout < < "\a\a";
Caracter \a \b \f \n \r \t \v \0 \\ \ \"
Tabela 22.3: Caracteres de escape. Efeito. Toca o alarme (beep ). Retrocede uma coluna (retrocesso). Pr oxima linha, ou p agina (). Pr oxima linha, nova linha. Retorno de carro. Tabula ca o horizontal. Tabula ca o vertical. Caractere nulo, usado no m da string. Imprime \. Imprime . Imprime .
415
22.5.1
Veja no exemplo a seguir como e a sobrecarga de uma ostream. Exemplo: ostream& operator< < (ostream& out, const Tipo obj) { out < < obj.atributo; return out; } Observe que a sobrecarga de > > e < < e realizada com fun co es friend, n ao admitindo a utiliza ca o do polimorsmo (n ao s ao m etodos virtuais da classe). Voc e pode, por em, criar um m etodo virtual para entrada e sa da de dados. Exemplo: virtual void Entrada(istream &in); virtual void Saida(ostream &out);
22.6
A classe <ios>
A classe <ios> cont em informa co es de formata ca o da stream considerando as informa co es do locale, isto e, a classe <ios> leva em conta o locale selecionado (a classe locale e descrita na Se ca o 22.9.2). A seguir s ao descritos os m etodos de <ios> utilizados para vericar o estado da stream. M etodos de <ios> bool good(); Retorna um (== 1) se n ao tem erro, isto e, se est a tudo ok. N ao e eof(), n ao e fail(), n ao e bad(). Associado ao bit de estado goodbit. bool bad(); Verica se ocorreu um erro nas opera co es de entrada/sa da de dados. Se estiver bad(), os caracteres da stream est ao perdidos e voc e deve resetar a stream utilizando clear(). Retorna um valor diferente de 0 se ocorreu um erro (badbit == 1). Associado ao bit de estado badbit. bool fail(); Retorna um (== 1) se o estado da stream estiver incorreto. Se estiver fail(), indica que a pr oxima opera ca o ir a falhar. Uma falha pode ocorrer quando voc e realizou a leitura de caracteres incompat veis, ou quando o arquivo a ser aberto e inexistente. Associado ao bit de estado failbit. void clear( int b = 0 ); O m etodo clear() e utilizado para reestabelecer o estado da stream para o estado ok. O par ametro opcional b e usado para setar os bits. Desliga os bits de estado eofbit, failbit e badbit e liga o bit de estado goodbit. bool eof(); Retorna um valor diferente de zero se estamos no nal do arquivo. Observe que eof = end of le. Associado ao bit de estado eofbit. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
char ll(char ch); Dene o caractere de preenchimento (o default e o caractere de espa co, ). Se um campo tem largura denida para 10 caracteres, e a sa da s o ocupa 6, os 4 caracteres restantes s ao preenchidos com o caractere de preenchimento. char ll(); Retorna o caractere de preenchimento. void setstate(iostate b); Usado para setar o estado do bit b. No exemplo a seguir, seta o bit eofbit para verdadeiro, tamb em ativa o bit goodbit. Os demais ags de estado, failbit e goodbit, n ao s ao alterados. Veja exemplo na listagem 26.7. Exemplo: cin.setstate(ios::eofbit); operator!(); Retorna o estado da stream (o mesmo que fail()). ostream* tie(); const Retorna ponteiro para stream de sa da. ostream* tie(ostream* obj); Conecta a stream com uma stream de sa da (ex: cin.tie(cout);). iostate rdstate(); Retorna o estado da stream. iostate exceptions(iostate b); Liga o bit de estado que faz com que clear() dispare uma exce ca o. No exemplo a seguir a chamada a clear() ir a disparar uma exce ca o se o failbit estiver true. Veremos exce co es no Cap tulo 26 Exce co es. Exemplo: cin.exceptions(ios::failbit); streambuf* rdbuf(); Acesso ao buer da stream.
22.6.1
Veja a seguir como usar m etodos de <ios> para saber o estado de cin. Para saber se est a no nal do arquivo. cin.eof(); Os caracteres foram lidos, mas o formato e incorreto. cin.fail(); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
22.7. A CLASSE <ISTREAM> Para saber se houve perda de dados. cin.badbit(); Para saber se tudo ocorreu corretamente. cin.good(); Para reinicializar os ags para o estado ok. cin.clear();
417
A classe <ios> inclui convers oes para bool. Assim, pode-se usar while(cin > > x) para ler os valores de x. Sempre que a entrada de x for correta, cin > > x retorna verdadeiro e continua o la co while. Quando o usu ario digitar um ctrl+d , invalidando a entrada de x, o la co while ser a encerrado.
22.7
A classe <istream>
A classe <istream> e uma classe para entrada de dados (istream = input stream ). Nos diversos exemplos apresentados, voc e aprendeu a utilizar o objeto cin do tipo <istream> para ler dados do teclado. Veremos a seguir alguns m etodos fornecidos pela classe <istream>. Na descri ca o do m etodo nos referimos ao objeto cin, mas o m etodo e v alido para qualquer <istream>. M etodos de <istream> int gcount(); Retorna o n umero de caracteres extra dos na u ltima opera ca o de leitura (v alido para get(), getline() e read()). istream& get(char* cstring, streamsize n, char end=*); e a digita ca o do asterisco=* (o * representa Obt em do teclado at e n caracteres, ou at aqui o caractere terminador; pode ser qualquer caractere), ou at e a digita ca o do retorno de carro(\n), o que ocorrer primeiro. O conjunto de caracteres lidos e armazenado em cstring. A fun ca o get() l e a stream at e o terminador, n ao o incluindo; para pegar o terminador, use um cin.get() adicional. No exemplo a seguir usamos o m etodo get() para ler do teclado at e 20 caracteres ou at e encontrar o ponto . e armazenar os dados lidos em nome. Exemplo: char nome[21]; cin.get(nome, 20, .); cin.get(); istream& get(char ch); Obt em um caractere do teclado e armazena em ch. Observe que se o usu ario digitou a letra A e em seguida pressionou Enter , a letra A e armazenada em ch, o enter digitado pelo usu ario continua no buer do teclado. Isto signica que voc e precisa de um cin.get() adicional para capturar o enter. Observe nos exemplos apresentados que, ap os uma leitura do teclado, utilizamos um cin.get() para capturar o enter. Veja que get() retorna uma refer encia para uma istream. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
418
22.7. A CLASSE <ISTREAM> Exemplo: char ch, novaLinha; cin.get(ch); // Captura um caractere e armazena em ch cin.get(novaLinha); // Captura o enter e armazena em novaLinha
int get(); Obt em um u nico caractere do teclado. Retira um caractere do teclado. Exemplo: cin.get(); istream& getline(signed char* cstring, int n, char=\n); O m etodo getline() e usado para armazenar uma linha inteira digitada no teclado em uma cstring (string de C). O m etodo getline() pega tamb em o retorno de carro. Observe que ele l e at e n-1 caracteres, visto que o u ltimo caractere e utilizado para armazenar o caractere terminador (\0). Exemplo: char nome[255]; cin.getline(nome); // string de C
istream& getline(istream cin, string nome, char end=\n); Armazena uma linha inteira digitada no teclado em uma string de C++ . Observe que voc e inclui a stream cin como par ametro (denida no arquivo de cabe calho <string>). Exemplo: string nome; getline(cin, nome); istream& ignore(streamsize n=1, int delim=EOF); Utilizada para ignorar at e n caracteres do uxo de entrada, ou seja, ela joga fora os pr oximos n caracteres. Por default ignora um caractere. Exemplo: cin.ignore(); // Ignora 1 caractere cin.ignore(2); // Ignora 2 caracteres istream& read(char *cstring, streamsize n); Utilizada para ler n caracteres sem interpretar o conte udo desses caracteres e armazenar em cstring. Desconsidera terminadores e n ao inclui o caractere de termina ca o. int readsome(char* cstring, stramsize n); Assemelha-se ao read(), mas retorna o n umero de caracteres lidos. long tellg(); Retorna a posi ca o atual do uxo (posi ca o do ponteiro get). Veja Se ca o 23.5.1. istream& putback(char ch); Devolve o caractere ch ao uxo de entrada. A pr oxima letra a ser lida ser a ch. Exemplo: char ch = k; cin.putback(ch); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
22.7. A CLASSE <ISTREAM> istream& unget(); Devolve para stream o u ltimo caractere lido. int peek(); Retorna o pr oximo caractere do uxo sem extra -lo da la. Equivale a get(ch); putback(ch);.
419
istream& operator > >(); Usada para armazenar uma entrada do teclado em uma vari avel. O operador > > l e at e o retorno de carro ou at e o primeiro espa co em branco (nova linha, tabulador, avan co de formul ario, retorno de carro). Exemplo: cin > > vari avel; cin > > x > > y > > z; cin > > oct > > numeroOctal; cin > > hex > > numeroHexadecimal; ostream* tie(ostream* os); Existe uma rela ca o entre cin e cout. Observe nas listagens apresentadas que cout n ao est a enviando um caractere de nova linha (\n), mas, ao executar o programa, a nova simples! O objeto cin envia para linha e inclu da. A pergunta e: como isto funciona? E cout uma nova linha. Voc e pode utilizar o m etodo tie() da classe <iostream> para criar uma associa ca o entre uma <istream> e uma <ostream> (da mesma forma como ocorre com cin e cout). Exemplo: istream is; ostream os; is.tie(os); Dica: veja exemplos de uso dos m etodos de <istream> nas listagens 9.4 e 9.8. No exemplo da listagem 22.4, mostramos como obter o n umero de linhas, palavras e caracteres digitados pelo usu ario. Listing 22.4: Contando n umero de linhas, palavras e caracteres.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // C o n t a n d o n u mero de linhas , p a l a v r a s e c a r a c t e r e s # include < cctype > # include < iomanip > # include < iostream > # include < string > using namespace std ; int main () { unsigned long nLinhas = 0; unsigned long nPalavras = 0 ; unsigned long nCaracter es = 0; string linhaAtual ; while ( getline ( cin , linhaAtual ) ) { ++ nLinhas ; nCaracter es += linhaAtual . size () + 1;
420
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
bool naPalavra = false ; for ( size_t i = 0; char c = linhaAtual [ i ]; ++ i ) if ( isspace ( static_cast < unsigned char >( c ) ) ) { if ( naPalavra ) ++ nPalavras ; naPalavra = false ; } else if (! naPalavra ) naPalavra = true ; if ( naPalavra ) ++ nPalavras ; } cout << \ n << left << nLinhas << \ n << left << nPalavras << \ n << left << nCaracteres < < return 0; } C ++ e mesmo uma linguagem de programa c a ~ o sensaciona l . O uso de streans e simples e i n c r i v e l m e n t e pr a tico . nLinhas : nPalavras : nCaracte re s : 3 17 107 setw (15) << " nLinhas : " setw (15) << " nPalavras : " << right << setw (15) << << right << setw (15) <<
setw (15) << " nCaracter es : " << right << setw (15) << endl ;
No exemplo da listagem 22.5, mostramos como controlar a entrada de dados. Listing 22.5: Controle de entrada.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // E x e m p l o com c o n t r o l e de e n t r a d a . # include < iostream > # include < fstream > # include < string > # include < sstream > using namespace std ; int main () { int numero , soma = 0; cout << " Digite valores inteiros ( ctrl + d para encerrar entrada ) : " ; while ( true ) { cin >> numero ; // Se a e n t r a d a foi ok if ( cin . good () ) soma += numero ; // Se chegou o fim do a r q u i v o ( ctrl + d no GNU / Linux , ctrl + z no w i n d o w s) else if ( cin . eof () ) break ; // Se o c o r r e u um erro na e n t r a d a do n u mero else { cin . clear () ; string entrada ;
421
22.7.1
A classe <istream> e uma especializa ca o do gabarito <basic_istream> para caracteres do tipo char. Para caracteres do tipo wchar_t, utilize a <wistream>. O caractere utilizado para encerrar uma entrada de dados e diferente nas plataformas DOS/Windows e Unix, GNU/Linux, MacOS X. Exemplo: // No DOS, um ctrl+z encerra o la co a seguir // No Unix, Mac OS X, GNU/Linux, um ctrl+d encerra o la co a seguir int var; do { cout < < "Entre com um n umero:"; } while( cin > > var ); Exemplo: // L^ e os caracteres do teclado usando cin // e joga para tela at e que ctrl+d // (no GNU/Linux) ou ctrl +z (no Windows) seja digitado. char ch; while(cin.get(ch)) cout.put(ch); O operador > >, ao ler uma stream (do teclado, do disco ou de outros dispositivos de entrada) desconsidera espa cos em branco , nova linha \n, avan co de formul ario \f e retorno de carro (enter). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
422
A fun ca o isspace() denida em <cctype> informa se o caractere e um espa co. A leitura para uma string do C [char*] automaticamente inclui o caractere de termina ca o (\0). Veja no exemplo a seguir como sobrecarregar uma istream. Exemplo: istream& operator> > (istream& in, Tipo obj) { in > > obj.atributo; return in; }
22.8
A classe <sstream>
O arquivo de cabe calho <sstream> inclui as classes ostringstream, istringstream, stringstream e stringbuf. Estas representam um misto de uma classe string e uma classe stream, funcionando ora como uma string, ora como uma stream. Veja a seguir os m etodos de <sstream>. M etodos de <sstream> string str(); Retorna a string corrente. void str(string); Seta a string. stringbuf type* rdbuf() const; Oculta deni ca o da classe-base, isto e, oculta ios::rdbuf(). Retorna buer corrente. operator< <(); Operador de inser ca o (< <). operator> >(); Operador de extra ca o (> >). As classes ostringstream (output string stream ) e istringstream (input string stream ) podem ser utilizadas para substituir com vantagens as fun co es printf() e scanf() de C. A classe stringstream pode ser usada para leitura e escrita. O exemplo da listagem 22.6 mostra como formatar uma string utilizando os m etodos de ostringstream e istringstream. Preste aten ca o neste exemplo: primeiro criamos um objeto os, utilizado para armazenar os caracteres das strings s1, s2 e os n umeros d e i, funcionando como uma stream (como cout). Em seguida, o objeto os e utilizado para mostrar a string na tela com os.str(), ou seja, os.str() retorna uma string. Voc e pode usar um objeto os para formatar uma sa da de dados em uma string. Observe que a fun ca o setf(), os manipuladores de <iomanip> e os ponteiros de posicionamento de leitura e escrita (veja Se ca o 23.5.1) podem ser utilizados. No nal do exemplo, criamos um objeto in, do tipo istringstream, que recebe como entrada a string formatada em os (os.str()), ou seja, o objeto in atua como uma string. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
423
A seguir, in e utilizado para enviar os caracteres para as strings s3, s4 e os n umeros d2 e i2, atuando como uma stream (como cin). Observe que, com um objeto do tipo ostringstream, pode-se substituir com vantagens a antiga fun ca o sprintf() de C, e, com um objeto istringstream, a antiga scanf(). Listing 22.6: Usando sstream (ostringstream e istringstream).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 # include < iostream > # include < string > # include < sstream > using namespace std ; // s t r e a m s // string de C ++ // stream e string junto
int main () { string s1 ( " oi_tudo " ) , s2 ( " bem " ) ; double d = 1.2345; int i = 5;
// Cria o b j e t o s
// Objeto do tipo o s t r i n g s t r eam , f u n c i o n a ora como stream ora como string o s t r i n g s t r e a m os ; // Abaixo , o objeto " os " f u n c i o n a como uma stream , como cout os << s1 << " " << s2 << " " << d << " " << i ; // A seguir o objeto os f u n c i o n a como uma string , str () r e t o r n a a string cout << " os . str () = " << os . str () << endl ; // Cria objeto do tipo i s t r i n g s t r e a m com nome in , // aqui in f u n c i o n a como uma string i s t r i n g s t r e a m in ( os . str () ) ; // Cria s t r i n g s s3 e s4 e dados n u m e r i c o s d2 e i2 string s3 , s4 ; double d2 ; int i2 ; // Extrai os dados da stream in e a r m a z e n a em s3 , s4 , d2 , i2 // aqui in f u n c i o n a como uma stream , como cin in >> s3 >> s4 >> d2 >> i2 ; cout << " s3 = " << s3 << " \ n " << " s4 = " << s4 << " \ n " << " d2 = " << d2 << " \ n " << " i2 = " << i2 << endl ; return 0; } os . str () = oi_tudo s3 = oi_tudo s4 = bem d2 = 1.2345 i2 = 5 bem 1.2345 5
22.9
22.9.1
Voc e pode criar seus pr oprios manipuladores. Veja o prot otipo a seguir. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
424
Prot otipo: istream & NomeManipulador(istream & is) { is > > vari avel; return is;} ostream & NomeManipulador(ostream & os) {return os < < Op co esDeFormata ca o....;} No exemplo a seguir criamos um manipulador que emite um beep. Exemplo: ostream& beep(ostream& os) { return os < < \a; } Utilizando o manipulador beep denido pelo usu ario: Exemplo: cout < < beep; Veja a seguir o exemplo de manipulador usado para ignorar uma linha inteira: Exemplo: inline istream& ignoreline(istream& in) { in.ignore( numeric.limits<long int>::max(), \n ); return in; }
22.9.2
A classe locale2
Com a classe locale voc e pode denir caracter sticas de formata ca o relacionadas a uma determinada localidade (pa s, regi ao). Como, por exemplo, a formata ca o de n umeros (ex.: 1.0 ou 1,0), o c odigo postal, datas, telefones etc. Veremos a seguir a classe locale: class std::locale { public: locale(const char*); locale(const locale&);
// Construtor // Construtor de c opia // Cria locale a partir de x e y locale(const locale& x, const locale& y); string name(); // Retorna o nome do locale // Recebe novo locale global e retorna antigo static locale global(const locale& ); const locale classic(); // Retorna locale cl assico }; Observe que um locale pode ser constru do a partir de uma cstring (const char *), de um outro locale ou de uma combina ca o de locales. Voc e pode obter o locale-padr ao chamando o construtor da classe locale sem par ametros, locale(), tamb em pode construir o locale do usu ario chamando locale("");. O m etodo global() e utilizado para denir uma nova localidade-padr ao e retornar a localidade antiga. O m etodo classic() retorna o locale cl assico (o mesmo que locale("C")). O m etodo name() retorna uma string com uma s erie de informa co es da localidade. eja Tabela 22.4. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
425
Tabela 22.4: Informa co es fornecidas pelo m etodo locale.name(). Vari avel Descri ca o LC CTYPE Classica ca o e convers ao de caracteres. LC COLLATE Ordem como as strings devem ser copiadas. LC MESSAGES Como traduzir mensagens como yes/no. LC NUMERIC Como representar n umeros. LC MONETARY Como representar dados monet arios. LC TIME Congura ca o de data e tempo. Dica: no GNU/Linux Red Hat e Fedora, as informa co es do locale s ao armazenadas no arquivo /etc/syscong/i18n e iniciam-se com as letras LC . Observe na Figura 22.1 que cada stream ao ser criada tem um locale associado o localepadr ao. Voc e pode alterar o locale de uma stream chamando o m etodo imbue(). No exemplo da listagem 22.7, vamos criar uma classe TestandoLocale() com tr es m etodos. O m etodo Mostra() mostra as informa co es dos locales inicial, padr ao, POSIX e C. O m etodo Define() solicita e dene o locale a ser utilizado. O m etodo Testa() testa o locale selecionado. Observe na sa da do exemplo os valores da localidade do usu ario (lc_usuario). A seguir, denimos o novo locale como pt_BR;. Observe que digitamos uma v rgula para denir o separador decimal do novo valor de x (exemplo: 1235,678). O locale-padr ao de C exige que o separador decimal de valores num ericos seja digitado com ponto (exemplo: 1235.678). Ap os denido o novo locale, setamos as stream s cin e cout usando o m etodo imbue(). Nota: o locale do usu ario e denido pelo usu ario quando se instala o sistema operacional. O uso de exce co es, bloco try{} throw e catch ser a visto no Cap tulo 26 Exce co es. Listing 22.7: Usando a classe locale.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # include < iostream > # include < string > # include < iomanip > using namespace std ; // s t r e a m s // string de C ++ // F o r m a t a c~ a o de s t r e a m s
// / Cria classe para visualiza c~ a o , ajuste e teste do locale class C T e s t a n d o L o c a l e { public : void Mostra () ; void Define () ; void Testa () ; private : locale lc_usuario ; // O locale s e l e c i o n a d o pelo u s u ario public : // Construtor , seta a t r i b u t o s i n t e r n o s // define locale do u s u a r i o p a s s a n d o uma string vazia "". // O locale do u s u ario e d e f i n i d o em seu s i s t e m a o p e r a c i o n a l . C T e s t a n d o L o c a l e () { lc_usuario = locale ( " " ) ; } };
426
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
// / Mostra a l g u m a s l o c a l i d a d e s p a d r ~ o e s como C , POSIX , a l o c a l i d a d e inicial , // / e a l o c a l i d a d e do u s u a r i o l c _ u s u a r i o . name () . void C T e s t a n d o L o c a l e :: Mostra () { cout << " \ n l o c a l i d a d e _ i n i c i a l = " << locale () . name () << " \ n l o c a l i d a d e _ p a d r a o _ C = " << locale ( " C " ) . name () << " \ n l o c a l i d a d e _ p a d r a o _ P O S I X = " << locale ( " POSIX " ) . name () << " \ n l o c a l i d a d e _ u s u a r i o = " << lc_usuario . name () << endl ; } void C T e s t a n d o L o c a l e :: Define () { string nomeLocale ; // S o l i c i t a nome da l o c a l i d a d e a ser u t i l i z a d a cout << " Entre com o novo locale ( ex : pt_BR , en_US , pt , fr , C ) : " ; getline ( cin , nomeLocale ) ; // Tenta d e f i n i r novo locale a partir da e n t r a d a do u s u ario try { // Define a l o c a l i d a d e do u s u ario lc_usuario = locale ( nomeLocale . c_str () ) ; // Define a l o c a l i d a d e global como sendo a do u s u ario locale :: global ( lc_usuario ) ; // Define a l o c a l i d a d e de cin e cout cout . imbue ( lc_usuario ); cin . imbue ( lc_usuario ); } catch ( ... ) { cerr << " \ n \ a \ aErro ao tentar definir novo locale , o locale - > " << nomeLocale << " deve ser inv a lido .\ n " ; } } void C T e s t a n d o L o c a l e :: Testa () { double x = 1.234; cout << " Entre com x ( ex : " << x << " ) : " ; cin >> x ; cin . get () ; cout << " x = " << s e t p r e c i s i o n (10) << x << endl ; } int main () { C T e s t a n d o L o c a l e localidad e ; localidade . Mostra () ;
int continuar = 1 ; while ( continuar == 1) { localidade . Define () ; // S o l i c i t a e altera o locale localidade . Testa () ; // Testa o locale s e l e c i o n a d o cout << " \ n \ aTestar novo locale (1) ou sair (0) ?: " ; cin >> continuar ; cin . get () ; } return 0; }
427
22.9.3
Usando facets 2
Um locale pode ser adaptado a uma determinada localidade denindo-se facets (classes que especicam algumas propriedades das stream s). Para detalhes do funcionamento de um locale, consulte o livro de [Bjarne, 1999] (3a . edi ca o revisada em ingl es). Infelizmente, a edi ca o traduzida para o portugu es, a terceira, n ao contempla o ap endice sobre locale. Entretanto, o autor disponibilizou no seu site, o Appendix D: Locales, no endere cohttp://www.research. att.com/~bs/3rd_loc0.html. No exemplo da listagem 22.8, vamos mostrar o uso de facets. Tamb em mostraremos o uso de wstring e wcout. Listing 22.8: Usando facets.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // E x e m p l o de uso de facet # include < iostream > # include < fstream > # include < string > # include < sstream > # include < locale > using namespace std ; int main () { // Usando facets // A c h a n d o o s m b o l o usado com dolar locale us ( " en_US " ) ; wstring dolar = use_facet < moneypunct < wchar_t > > ( us ) . curr_symbo l () ; wcout << " S mbolo para dolar = " << dolar << endl ; // A c h a n d o o s m b o l o usado com real locale br ( " pt_BR " ) ; wstring real = use_facet < moneypunct < wchar_t > > ( br ) . curr_symb o l () ; wcout << " S mbolo para real = " << real << endl ; return 0; }
428
22.10
Lembre-se de que, no uso de cin > > mensagem;, caracteres como espa co s ao desconsiderados. A inclus ao de #include <iostream> fornece, al em dos objetos cin e cout, os objetos cerr (mensagens de erro) e clog (mensagens de log) que tamb em s ao conectados ` a sa dapadr ao do sistema (o monitor). cout e clog s ao buferizadas; isto signica que os caracteres n ao s ao imediatamente enviados para a tela. Para enviar imediatamente ` a tela, inclua uma chamada ao m etodo flush(). Exemplo: cout.flush(); // ou cout < < flush; O objeto cerr n ao e buferizado; isto signica que ele envia os caracteres imediatamente para a tela. Assim como cin, cerr e conectada com o monitor e deve ser utilizada para enviar mensagens de erro para a tela. Nas suas classes inclua sobrecarga para os operadores de extra ca o > > e de inser ca o < <. Note que o usu ario de sua classe espera que os operadores < < e > > estejam sobrecarregados. Para ter certeza da sa da do operador de inser ca o (< <), utilize par enteses. Exemplo: cout < < (a+b); Ap os uma leitura com cin, utilize cin.get() para retirar o caractere de retorno (o enter ). Lembre-se de que o manipulador width() se aplica ` a sa da seguinte. Como dito, ios e v alido para char, e wios para wchar_t. As equival encias s ao: ios>wios, istream->wistream, ostream->wostream, iostream->wiostream, ofstream->wofstream, ifstream->wifstream, fstream->wfstream, streambuf->wstreambuf, e, nalmente, filebuf>wfilebuf. A classe <ios> dene um operador void*() que retorna NULL se o bit failbit e true, isto e, se ocorreu um erro na leitura [Lischner, 2003].
22.11
Vimos neste cap tulo a hierarquia de classes fornecidas pelo C++ para entrada e sa da de dados. Aprendemos que a biblioteca-padr ao e bastante extensa e inclui diversas classes para entrada e sa da de dados, classes com e sem buer. Aprendemos que o uso de buer e importante pois os mesmos deixam o programa mais r apido. Vimos que podemos denir a formata ca o de entrada e sa da de dados usando o m etodo setf() ou usando manipuladores. Aprendemos a criar nossos pr oprios manipuladores. Vimos que a entrada de dados e feita com as classes <ios> e <istream>. Substitu mos o uso da obsoleta printf() e scanf() (de C) pelas classes ostringstream e istringstream. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
429
Finalmente, aprendemos a denir a localidade a ser utilizada, a usar a classe locale e os facets. A seguir, no Cap tulo 23 Entrada e Sa da com Arquivos de Disco, aprenderemos a acessar dispositivos de disco e veremos alguns conceitos como redirecionamento de entrada e sa da.
22.12
Exerc cios
1. Inclu mos a seguir dois exemplos de fun co es utilit arias que realizam a convers ao de n umeros double para string e vice-versa. Como exerc cio, monte fun co es equivalentes para int, float, long double. Em seguida, monte uma fun ca o template para realizar a mesma coisa para tipos gen ericos. // Fun c~ ao global utilit aria, convers~ ao double->string string doubleToString(double d) { ostringstream os; os < < d ; return os.str(); } // Fun c~ ao global utilit aria, convers~ ao string->double double stringToDouble(string s) { istringstream in( s ); double d; in > > d; if( in.fail() || !in.eof()) return 0.0; return d; } 2. Quais objetos est ao associados ` a sa da e entrada padr ao, ` a sa da de erro e de logs? Quais s ao buferizados? (falar o nome e para que serve). 3. Qual a diferen ca entre \n e ends? 4. Monte um exemplo que utilize putback() e unget(). 5. Pesquise na internet o uso de facets e, em seguida, modique a listagem 22.7, incluindo o uso de facets. 6. Monte um exemplo que inclua a deni ca o e o uso do manipulador beep. 7. Crie um par de manipuladores que fa cam a convers ao de d olar para real e de real para d olar. 8. Monte um exemplo em que o n umero de caracteres lidos seja mostrado na tela a cada opera ca o de leitura. 9. Na listagem 22.6, verique como ca a istringstream depois de usada. 10. Comente o funcionamento l ogico da listagem 22.4.
430
Cap tulo 23
23.1
Reveja na Figura 22.1, a hierarquia de classes de entrada e sa da. Herdeira da classe <ostream>, a classe <ofstream> e utilizada para enviar caracteres para um dispositivo externo, como um arquivo de disco (ofstream = output le stream ). Herdeira da classe <istream>, a classe <ifstream> e utilizada para ler caracteres de um dispositivo, como um arquivo de disco (ifstream = input le stream ). Herdeira da classe <iostream>, a classe <fstream> e utilizada para leitura e escrita em arquivos de disco. Para usar o acesso a arquivos de disco, inclua o arquivo de cabe calho <fstream>: Exemplo: #include <fstream>
23.2
A classe <fstream>
fstream(); Construtor default da classe, cria objeto sem associ a-lo a um arquivo de disco. fstream(const char* arq, int = modoDeAbertura, int = modoDeProte c ao); Construtor sobrecarregado, cria objeto e associa-o a um dispositivo, normalmente um arquivo de disco. Se voc e deseja abrir o arquivo sem eliminar o existente, inclua um ios::app para adicionar caracteres no m do arquivo. modoDeAbertura Especica como abrir o arquivo (veja Tabela 23.1). modoDeProte ca o Especica o formato de prote ca o do arquivo (veja Tabela 23.2). fstream(int); Construtor sobrecarregado, cria objeto e associa-o a arquivo identicando-o com um n umero int (n ao e coberto pelo padr ao Ansi C++, mas e disponibilizado em alguns sistemas). void open (const char *arq, int = modoDeAbertura, int = modoDeProte c ao); O m etodo open() e usado para abrir arquivos de disco. Por default, abre o arquivo eliminando o arquivo existente. Se voc e deseja abrir o arquivo sem eliminar o existente, inclua um ios::app para adicionar caracteres no m do arquivo. Exemplo: ofstream fout; fout.open("nomeDoArquivo.dat");
Tabela 23.1: Modos de abertura do m etodo open(). ios::app Acrescenta ao m do arquivo (modo append ) ios::ate Abre arquivo e vai para o m dele ios::in Abre o arquivo para entrada (leitura) ios::out Abre o arquivo para sa da (escrita) ios::nocreat N ao cria se o arquivo n ao existe (uma falha) ios::noreplace Se o arquivo j a existir, ocorre uma falha ios::binary Abre o arquivo em modo bin ario ios::trunc Elimina o arquivo se j a existir e recria (default )
Tabela 23.2: Modos de prote ca o do m etodo open() (atributos de arquivo). 0 Arquivo 1 Apenas leitura 2 Escondido 4 Sistema 8 Ativar o bit do arquivo (backup) Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
433
istream & seekg(streamo deslocamento, seekdir manipulador); Quando uma istream abre um arquivo de disco, o ponteiro de leitura aponta para o in cio do arquivo. A medida que a istream e utilizada, o ponteiro de leitura e deslocado para o pr oximo dado a ser lido. O m etodo seekg() e utilizado para movimentar o ponteiro de leitura. Podemos mudar a posi ca o do ponteiro de leitura sem ter que realizar uma leitura (veja se ca o 23.5.1). ostream & seekp(streamo deslocamento, seekdir manipulador); Movimenta ponteiro de escrita (veja se ca o 23.5.1). Veja na Tabela 23.3 os manipuladores que podem ser passados para esses m etodos. Exemplo: // Movimenta ponteiro get fin.seekg(deslocamento,manipulador); // Movimenta ponteiro put fout.seekp(deslocamento,manipulador); // Obt em posi c~ ao do ponteiro get ios::pos_type pg = fin.tellg(); // Obt em posi c~ ao do ponteiro put ios::pos_type pp = fout.tellp(); bool is open(); Retorna verdadeiro se o arquivo esta aberto. void close(); Descarrega o buer e fecha o arquivo aberto; se j a fechado, ignora-o.
Tabela 23.3: Manipuladores seekdir para os m etodos seekp() e seekg(). ios::beg Vai para o in cio do arquivo ios::end Vai para o m do arquivo ios::cur Posi ca o corrente ios::fail Opera ca o E/S falhou (possivelmente o arquivo est a com problemas) ios::bad E/S inv alida (possivelmente o arquivo est a com problemas) Na listagem 23.1 apresentamos, al em da sa da, os arquivos gerados pelo programa (o comando cat do GNU/Linux mostra o conte udo de um arquivo). O programa inicia criando o objeto fout. A seguir abre o arquivo de disco "data.dat" e envia para o arquivo a mensagem "Isto vai para o arquivo de disco". Num segundo bloco, abrimos o arquivo de disco "data2.dat", usando o construtor de ofstream que recebe o nome do arquivo a ser aberto. No terceiro bloco, o arquivo "data.dat" e aberto, agora para leitura. O conte udo da primeira linha do arquivo e copiada para a string s. Dentro do for, utilizamos um objeto ostringistream para criar arquivos de disco com nomes: nomeDoArquivo-1.dat, nomeDoArquivo-2.dat, nomeDoArquivo-3.dat. Arquivos seq uenciais s ao muito u teis em programas de simula ca o cient ca. Como dito anteriormente, os.str(), retorna uma string de C++, j a c_str(), converte uma string de C++ em uma string de C (char *). Observe que o funcionamento dos objetos do tipo ofstream e ifstream, e muito semelhante ao uso de cout e cin. Em ambos os casos, o acesso a disco e nalizado quando fechamos a conex ao com o dispositivo de disco com close(). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
434
23.2. A CLASSE <FSTREAM> Listing 23.1: Uso de stream de disco (ifstream e ofstream).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
# include < iostream > # include < fstream > # include < string > # include < sstream > using namespace std ; int main () { { // Cria o objeto do tipo o f s t r e a m ofstream fout ;
// A s s o c i a o objeto fout ao a r q u i v o de disco data . dat fout . open ( " data . dat " ) ; // Se a a b e r t u r a do a r q u i v o falhou , e n c e r r a o p r o g r a m a if ( fout . fail () ) { cout << " N~ a o abriu o arquivo de disco . " << endl ; return 1; } // Se o a r q u i v o abriu corretamente , insere c a r a c t e r e s no a r q u i v o . fout << " Isto vai para o arquivo data . dat \ n " ; // D e s c a r r e g a o buffer e fecha o a r q u i v o. fout . close () ; } { // P o d e m o s criar o objeto fout e associ a - lo a um a r q u i v o de disco ofstream fout ( " data2 . dat " ) ; fout << " Isto vai para o arquivo data2 . dat \ n " ; fout . close () ; // D e s c a r r e g a o buffer e fecha o a r q u i v o . } { // Um i f s t r e a m e um f s t r e a m com ios :: in , // a s s o c i a objeto de l e i t u r a fin ao a r q u i v o de disco data . dat ifstream fin ( " data . dat " ) ; string s ; getline ( fin , s ) ; // L^ e a string s do a r q u i v o de disco data . dat cout << " Conte u do do arquivo : " << s << endl ; fin . close () ; // Fecha o a r q u i v o } { for ( int i = 0; i < 3; i ++) { // Cria objeto do tipo o s t r i n g s t r e a m o s t r i n g s t r e a m os ; // os f u n c i o n a como uma ostream , e e u t i l i z a d a para criar // o nome do a r q u i v o de disco que ser a aberto a seguir os << " nomeDoArquivo - " << i << " . dat " ; // Abre a r q u i v o n o m e D o A r q u ivo -0. dat ,... ofstream fout ( os . str () . c_str () ) ; // A r m a z e n a dados no a r q u i v o aberto fout << " no arquivo de disco : " << os . str () << endl ; cout << " Escrevendo no arquivo de disco : " << os . str () << endl ; fout . close () ; // Fecha o a r q u i v o }
435
vai para o arquivo data . dat disco : nomeDoArquivo -0. dat disco : nomeDoArquivo -1. dat disco : nomeDoArquivo -2. dat
bash -3.00 $ cat data . dat Isto vai para o arquivo data . dat bash -3.00 $ cat data2 . dat Isto vai para o arquivo data2 . dat bash -3.00 $ no arquivo bash -3.00 $ no arquivo bash -3.00 $ no arquivo cat nomeDoArquivo -0. dat de disco : nomeDoArquivo -0. dat cat nomeDoArquivo -1. dat de disco : nomeDoArquivo -1. dat cat nomeDoArquivo -2. dat de disco : nomeDoArquivo -2. dat
O exemplo da listagem 23.2 mostra como ler um arquivo de disco com formata ca o simples. O programa abre o arquivo de disco "data3.dat" e armazena no arquivo 3 linhas. Na primeira linha um n umero inteiro seguido de coment ario. A seguir, repete o procedimento para um float e uma string. Depois o arquivo e fechado com close(). Na segunda etapa o programa, abre o arquivo de disco e cria as vari aveis que ser ao lidas do arquivo de disco. Na linha fin > > x; o objeto fin percorre o arquivo de disco desconsiderando espa cos em branco e retornos de carro. Quando encontra o primeiro caracter v alido, verica se o mesmo e um n umero inteiro e copia o mesmo para x. No caso copia o n umero 1452 para x. A linha fin.ignore(255,\n); e usada para ignorar o restante da linha. O mesmo procedimento e usado para ler y e s. Para ler a1, a2 e a3, usamos fin.ignore(255,#); ou seja, ignorar tudo at e encontrar o caracter separador, no caso #. Observe na sa da que os valores de x, y, s, a1, a2 e a3 est ao corretos. Listing 23.2: Lendo um arquivo com dados e coment arios.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # include < iostream > # include < fstream > # include < string > # include < sstream > using namespace std ; int main () { { // Cria a r q u i v o de disco e a r m a z e n a dados com c o m e n t arios ofstream fout ; fout . open ( " data3 . dat " ) ; // valor # c o m e n t arios fout << 1452 << " # representa bla .. bla .. bla ..1 " << endl ; fout << 0.123 << " # representa bla .. bla .. bla ..2 " << endl ; fout << " msg " << " # representa bla .. bla .. bla ..3 " << endl ; // valor # valor # valor # fout << 12 << " # " << 13 << " # " << 14 << " # " << endl ; fout . close () ; } { // L^ e os dados do a r q u i v o de disco ifstream fin ( " data3 . dat " ) ;
436
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 int x ; float y ; string s ; int a1 , a2 , a3 ; fin >> x ; fin . ignore (255 , \ n ) ; fin >> y ; fin . ignore (255 , \ n ) ;
fin >> s ; fin . ignore (255 , \ n ) ; cout << " x = " << x << " y = " << y << " s = " << s << endl ; fin >> a1 ; fin . ignore (255 , # ) ; fin >> a2 ; fin . ignore (255 , # ) ; fin >> a3 ; fin . ignore (255 , # ) ; cout << " a1 = " << a1 << " a2 = " << a2 << " a3 = " << a3 << endl ; fin . close () ; } return 0; } x = 1452 y = 0.123 s = msg a1 = 12 a2 = 13 a3 = 14
23.3
Com os m etodos read() e write(), podemos armazenar um objeto em disco e posteriormente l e-lo do disco, o que e muito u til para manipula ca o de dados (banco de dados). Reveja a seguir o prot otipo dos m etodos read() e write(). Prot otipo: istream & read(char *charbufer, streamsize n); ostream & write (const signed char *charbuer, int n); A listagem 23.3 mostra um exemplo. O programa inicia-se denindo uma classe CData. Observe a sobrecarga dos operadores de inser ca o e extra ca o. Dentro de main(), solicita o nome do arquivo de disco e o associa ` a stream fout. Ap os vericar se o arquivo de disco foi corretamente aberto, cria um vetor para armazenar objetos do tipo CData. A seguir, entra em um looping while, onde o usu ario entra com os dados de cada objeto (x e y). Envia o objeto para o arquivo de disco com fout < < obj; e mostra o objeto na tela, cout < < "Objeto=" < < obj;. No nal do do while(), adiciona o objeto no vetor com push_back(obj);. Fora do while(), fecha o arquivo de disco, fout.close(), e mostra todos os objetos do tipo CData que est ao armazenados no vetor d. Na segunda parte do programa, abre um objeto de leitura de arquivo de disco, ifstream fin, e verica se o arquivo foi corretamente aberto, if (!fin). Para mostrar que os dados que foram armazenados em disco ser ao corretamente lidos, cria-se um segundo vetor, com nome d2. Entra num novo while, onde l e todos os objetos armazenados em disco, mostra-os na tela e armazena no vetor d2. Finalmente mostra o vetor d2. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
23.3. ARMAZENANDO E LENDO OBJETOS Listing 23.3: Leitura e grava ca o de objetos simples usando read() e write().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 # include < string > # include < fstream > # include < vector > # include < iostream > using namespace std ; class CData { int x ; int y ; public : CData () : x (0) , friend istream friend ostream friend ifstream friend ofstream }; // D e c l a r a classe CData
437
( istream & , CData &) ; ( ostream & , CData &) ; ( ifstream & , CData * &) ; ( ofstream & , CData * &) ;
// de in para CData , e x e m p l o: cin >> d ; istream & operator >> ( istream & in , CData & d ) { cout << " \ nx : " ; in >> d . x ; cout << " \ ny : " ; in >> d . y ; return in ; } // de CData para out , e x e m p l o : cout << d ; ostream & operator << ( ostream & out , CData & d ) { out << " ( x = " << d . x << " , y = " << d . y << " ) " << endl ; return out ; } // de in para CData , e x e m p l o: fin >> d ; ifstream & operator >> ( ifstream & in , CData * & d ) { in . read ( r e i n t e r p r e t _ c a s t < char * >( d ) , sizeof ( CData ) ) ; return in ; } // de CData para out , e x e m p l o : fout << d ; ofstream & operator << ( ofstream & out , CData * & d ) { out . write ( r e i n t e r p r e t _ c a s t < const char * >( d ) , sizeof ( CData ) ) ; return out ; } int main () { cout << " Nome do Arquivo : " ; // S o l i c i t a nome do a r q u i v o string nomeArqui vo ; getline ( cin , nomeArqui vo ) ; // Abre a r q u i v o de disco ofstream fout ( nomeArqui v o . c_str () ) ; if (! fout ) // V e r i f i c a se o a r q u i v o foi aberto { // ou use if ( fout . i s _ o p e n () ) cout << " \ n \ nErro na abertura de arquivo " ; exit (1) ; } vector < CData > d ; // Cria vetor para o b j e t o s do tipo CData
438
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 CData obj ; CData * pobj ; pobj = & obj ;
cout << " Entre com os valores de x e y de cada objeto . " << " Para encerrar ctrl + d " << endl ; while ( cin >> obj ) // E n q u a n t o l e i t u r a for c o r r e t a { cin . get () ; fout << pobj ; // A r m a z e n a dados do objeto no a r q u i v o de disco cout << " Objeto = " << obj ; // Mostra dados do objeto lido na tela d . push_back ( obj ) ; // A r m a z e n a objeto no vetor }; cin . clear () ; // Reseta a stream , pronta para p r oxima leitura fout . close () ; // Fecha o a r q u i v o de disco cout << " \ nMostrand o objetos do vetor d \ a " << endl ; for ( int i = 0; i < d . size () ; i ++ ) cout << d [ i ] << endl ; // Mostra todos os o b j e t o s lidos cout << " Vai ler os objetos do disco " << endl ; ifstream fin ( nomeArquiv o . c_str () ) ; if (! fin ) { cout << " \ n \ nErro na Abertura de arquivo " ; exit (1) ; } vector < CData > d2 ; while ( fin >> pobj ) { d2 . push_back ( obj ) ; }; fin . close () ;
cout << " \ nMostrand o objetos do vetor d2 \ a " << endl ; for ( int i = 0; i < d2 . size () ; i ++) cout << d2 [ i ] << endl ; return 0; } Nome do Arquivo : Teste . txt Entre com os valores de x e y de cada objeto . Para encerrar ctrl + d x : 1 y : 2 Objeto =( x = 1 , y = 2) x : 3 y : 4 Objeto =( x = 3 , y = 4) x : 5 y : 6 Objeto =( x = 5 , y = 6) x : y : Mostrando objetos do vetor d ( x = 1 , y = 2) ( x = 3 , y = 4) ( x = 5 , y = 6) Vai ler os objetos do disco Mostrando objetos do vetor d2 ( x = 1 , y = 2) ( x = 3 , y = 4)
439
Observe que este mecanismo de armazenamento e leitura de arquivos em disco funciona corretamente. Mas se o objeto usar aloca ca o din amica para atributos internos, o conte udo do ponteiro e que ser a armazenado em disco. Voc e ter a de usar um outro mecanismo para gerenciar o armazenamento e a leitura de objetos com atributos din amicos.
23.4
Redirecionamento de entrada e sa da
Tanto na linha de comando do GNU/Linux como do Mac OS X e do Windows, voc e pode utilizar os mecanismos de redirecionamento de entrada e sa da de dados. Voc e j a usou o comando ls (ou dir ) para listar o conte udo de um diret orio. Exemplo (GNU/Linux): ls Exemplo (Windows): dir Entretanto, se a sa da do comando ls (ou dir ) for muito grande e n ao couber na tela, os primeiros diret orios e arquivos ir ao desaparecer. Neste caso, voc e pode usar um comando de redirecionamento como pipe (|), para enviar a sa da do comando ls (ou dir ) para um paginador como o less. No Windows, o equivalente de ls e dir e o equivalente do less e o more (ou type). O programa less e um paginador, pois permite que voc e navegue em um arquivo. Para sair do less digite a letra q. Veja no exemplo a seguir que pegamos a sa da do programa ls e a enviamos para o programa less. Exemplo (GNU/Linux): ls | less Exemplo (Windows): dir | more Quando voc e executa um programa a sa da-padr ao e a tela. Voc e pode redirecionar a sa da do programa para um arquivo de disco utilizando redirecionamento >. Veja o exemplo. Exemplo (GNU/Linux): ls > arquivo.dat cat arquivo.dat Exemplo (Windows): dir > arquivo.dat type arquivo.dat | more No exemplo anterior, voc e pegou a sa da do programa ls e a enviou para o arquivo arquivo.dat. O programa cat apenas mostrou o conte udo do arquivo arquivo.dat. Se o arquivo arquivo.dat for muito grande, utilize novamente o paginador less. Exemplo (GNU/Linux): cat arquivo.dat | less Exemplo (Windows): type arquivo.dat | more Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
440
Voc e pode adicionar a sa da de um programa no nal de um arquivo utilizando o operador de concatena ca o (> >), ou seja, escrever a sa da de um programa em um arquivo de disco j a existente. Exemplo (GNU/Linux): ./Simulacao > resultado.dat ./Simulacao > > resultado.dat Exemplo (Windows): Simula c~ ao.exe > resultado.dat Simula c~ ao.exe > > resultado.dat Neste caso, primeiro, voc e cria o arquivo resultado.dat que armazenar a o resultado da primeira simula ca o realizada. Depois, executa novamente o programa ./Simulacao , adicionando os novos resultados no nal do arquivo resultado.dat. Outra possibilidade bastante interessante e criar um arquivo de disco com as entradas que ser ao solicitadas por determinado programa. Assim, em vez de esperar o usu ario digitar cada entrada, o programa l e as entradas diretamente do arquivo de disco. Veja exemplo a seguir. Exemplo (GNU/Linux): ./Simulacao < entrada.dat Exemplo (Windows): Simulacao.exe < entrada.dat Vamos utilizar o exemplo da listagem 23.4 para mostrar o uso dos mecanismos de redirecionamento. Observe que a listagem 23.4 solicita a entrada de 3 valores. O nome do arquivo, o n umero de repeti co es e a precis ao do solver. Depois, mostra os valores lidos. O programa pode ser compilado e executado normalmente. Para rodar este exemplo, voc e precisa de um arquivo de disco com o nome "teste.dat" com o seguinte conte udo: teste.dat 3 0.0001 Para rodar, basta digitar ./nomeDoPrograma < < arquivoComDados. Observe na sa da que executamos o programa sem redirecionamento e a seguir com redirecionamento. Listing 23.4: Usando redirecionamento de arquivo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # include < iostream > # include < fstream > # include < string > using namespace std ; int main () { string n o m e A r q u i v o D i s c o ; cout << " Entre com o nome do arquivo de disco : " ; getline ( cin , n o m e A r q u i v o D i s c o ) ; cout << " Entre com o n u mero de repeti co ~ es : " ; int repeticoes = 0; cin >> repeticoes ; cin . get () ;
441
23.5
Veremos nesta se ca o conceitos avan cados de entrada e sa da em C++. O acesso a impressora e a sa da auxiliar. O uso de arquivos de disco bin arios e como executar programas externos e enviar comandos para eles.
23.5.1
Quando estamos lendo informa co es de um arquivo do disco, estamos com o nosso objeto de leitura apontando para uma determinada posi ca o do arquivo. Os m etodos seekg() e seekp() s ao utilizados para posicionar o ponteiro de leitura (get ) e o de escrita (put ) em um determinado arquivo. Os m etodos tellg() e tellp() s ao utilizadas para obter a posi ca o dos ponteiros de leitura get() e escrita put(). Veja o uso de seekg(), read(), write() e arquivos bin arios na listagem 23.5. O programa inicia-se denindo uma classe CA, que tem os atributos x e y e um m etodo de entrada Input(). O m etodo ArmazenaObjeto() cria um objeto do tipo CA e abre um arquivo de disco. A seguir, entra num la co while() onde os dados de cada objeto s ao lidos e armazenados em disco. No nal do m etodo ArmazenaObjeto(), o arquivo de disco estar a com todos os objetos que foram lidos. O m etodo LeObjetos() solicita ao usu ario qual objeto deve ser lido. A seguir, abre o arquivo de disco e usa o m etodo seekg() para movimentar o ponteiro get e o posicionar no in cio do objeto a ser lido. A fun ca o read() l e o objeto do arquivo de disco. Finalmente o objeto Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
442
lido e mostrado na tela. Enm, neste exemplo, criamos uma base de dados, armazenando-a em disco com write() e usamos os m etodos seekg() e read() para ler o objeto selecionado. Observe que os objetos s ao armazenados e lidos no formato bin ario (ios::binary). Listing 23.5: Usando read(), write() e seekg().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 # include < iostream > # include < fstream > using namespace std ; class CA { public : int x ; int y ; CA () : x (0) , y (0) { }; bool Input () { cout << " Entre com x e y ( x espa co y ):" ; cin >> x ; cin . get () ; cin >> y ; cin . get () ; if ( cin . fail () ) { cin . clear () ; return 0; } return 1; } }; // A r m a z e n a o b j e t o s em disco void A r m a z e n a O b j e t o s () { cout << " sizeof ( CA ) = " << sizeof ( CA ) << endl ; CA obja ; ofstream fout ( " readwrite . dat " , ios :: binary ) ; if (! fout ) { cout << " N~ a o consegue abrir arquivo de disco " ; return ; } while ( obja . Input () ) { cout << " obja . x = " << obja . x << " obja . y = " << obja . y << endl ; fout . write ( r e i n t e r p r e t _ c a s t < char * >(& obja ) , sizeof ( CA ) ) ; } fout . close () ; } void LeObjetos () { CA obja ; cout << " \ nQual objeto quer ler ? " ; int i ; cin >> i ; cin . get () ; // Cria objeto fin , que aponta para a r q u i v o r e a d w r i t e . dat ifstream fin ( " readwrite . dat " , ios :: binary ) ;
443
y ) :1 2 y ) :3 4 y ) :5 6 y):
23.5.2
Como dito anteriormente, alguns sistemas aceitam o uso de um construtor de fstream que recebe um inteiro. Um exemplo e o DOS. Para ligar um arquivo diretamente ` a impressora no DOS, utilize: Prot otipo: fstream cprn(4); caux(3); // cprn e conectado a impressorafstream // caux e conectado a sa da auxiliar.
No exemplo a seguir enviamos para impressora o texto Estou escrevendo na impressora. Exemplo: // Testado no DOS fstream cprn(4); cprn < < Estou escrevendo na impressora ; cprn.close(); fstream caux(3); caux < < Estou enviando texto para sa da auxiliar ; caux.close(); No GNU/Linux o dispositivo impressora est a localizado em /dev/lp0, /dev/lp1,.., etc. Assim, posso criar uma stream e a seguir conect a-la ao dispositivo /dev/lp0. Veja o exemplo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
444
23.5. ENTRADA E SA IDA COM ARQUIVOS DE DISCO - USO AVANCADO Exemplo: ofstream fout ("/dev/lp0");
Observe como o uso de objetos streams e surpreendente. O procedimento para enviar uma string para a tela e exatamente o mesmo utilizado para enviar uma string para a impressora, sa da auxiliar, modem ou outro programa.
23.5.3
Os m etodos get() e put() operam byte a byte, sem interpret a-los. Veja a seguir o prot otipo. Prot otipo: istream & get(char & c); ostream & put(char & c); No exemplo a seguir a string "oi tudo bem e percorrida com s.at[i]. Enquando o acesso n ao falhar, isto e, se o caracter existe, ent ao o mesmo e enviado para o disco com put(). Exemplo: #include <fstream> main() { ofstream fout("data.dat", ios::binary); string s = oi tudo bem ; while(s.at[i]) // Enquanto houver algo fout.put(s[i++]); // Escreve no disco em modo binario fout < < end; fout.close(); return 0; }
23.5.4
Um exemplo muito interessante e u til do uso das streams de C++ e a execu ca o e o envio de comandos para um outro programa. Isto e, o seu programa pode executar um programa B e enviar comandos a ele. Nosso objetivo e desenvolver um programa que ir a gerar um conjunto de dados, armazenar estes dados em disco e a seguir executar o programa gnuplot para fazer o gr aco dos dados gerados. O exemplo da listagem 23.6 foi testado na plataforma GNU/Linux/Fedora e utiliza o arquivo de cabe calho "pstream.h" que n ao e padr ao e esta disponibilizado em http://pstreams. sourceforge.net/. Veremos no Cap tulo ?? - Introdu ca o ao Processamento Paralelo com M ultiplos Processos, m etodos alternativos ao uso de "pstream.h". A classe opstream localizada no namespace redi, e utilizada para conectar o seu programa com um programa externo. O nome do programa externo deve ser passado para o construtor de opstream dentro de aspas (). O programa da listagem 23.6 inicia abrindo o arquivo de disco "data.dat", e armazenando neste arquivo um conjunto de dados (x, y = sin(x), z = cos(x)). A seguir o programa executa o programa externo gnuplot na linha redi::opstream gnuplot("gnuplot");. Neste ponto, criamos um objeto do tipo opstream com nome gnuplot, e executamos o programa gnuplot, de forma que poderemos enviar caracteres (comandos) diretamente para o gnuplot. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
445
Depois o programa envia para o gnuplot um conjunto de instru co es para gerar o gr aco desejado. O programa gnuplot e aberto e o gr aco e apresentado (veja Figura 23.1). O gnuplot e um programa utilizado para fazer gr acos. O mesmo est a dispon vel no site: http://www.gnuplot.info/. Se voc e usa GNU/Linux, provavelmente j a tem o gnuplot instalado. Depois de instalar o gnuplot abra um terminal, digite gnuplot e a seguir plot sin(x),cos(x) seguido de enter. Pronto, voc e acaba de gerar um gr aco usando o gnuplot. Quer gerar um gr aco em 3D? digite splot sin(x)*cos(x) . Voc e encontra no site https://www.lenep.uenf.br/~bueno/SoftwareLivre, material da disciplina de Software Livre, o que inclui aula sobre o uso do gnuplot (veja Lista das Aulas, e procure por gnuplot ). As instru co es a seguir s ao utilizadas para plotar, em duas dimens oes, os dados do arquivo data.dat. Com estas instru co es vamos gerar duas curvas, a primeira usando a coluna 1 (x) contra a coluna 2 (y) . A segunda curva vai mostrar os dados da coluna 1 (x) contra os dados da coluna 3 (z). "plot data.dat using 1:2,data.dat using 1:3 O comando pode ser aperfei coado, acrescentando-se t tulos para os dados (title dados de y), e o tipo de linha (with linespoint). "plot data.dat using 1:2 title dados de y with linespoint, data.dat using 1:3 title dados de z with linespoint"
-5
10
Listing 23.6: Executando e enviando comandos para um outro programa (com <opstream>).
1 # include < iostream >
446
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
23.6. SENTENCAS
# include < cstdio > # include < cmath > # include < fstream > # include " pstream . h " // D i s p o n v e l em http :// p s t r e a m s . s o u r c e f o r g e . net / using namespace std ; int main () { // Cria a r q u i v o de disco , onde ir a a r m a z e n a r os dados de x ,y , z ofstream fout ( " data . dat " ) ; float x , y , z ; // A r m a z e n a um c o n j u n t o de dados em disco for ( x = -10; x <= 10; x += 0.1) { y = sin ( x ) ; z = cos ( x ) ; fout << x << " " << y << " " << z << endl ; } fout . close () ; // Cria objeto g n u p l o t do tipo o p s t r e a m e o c o n e c t a com o p r o g r a m a g n u p l o t redi :: opstream gnuplot ( " gnuplot " ) ; // Envia c o m a n d o para o g n u p l o t gnuplot << " plot data . dat using 1:2 title dados de y with linespoint " << " , data . dat using 1:3 title dados de z with linespoint " << endl ; cout << " \ nPression e enter " << endl ; cin . get () ; // E n c e r r a e x e c u c~ a o do g n u p l o t gnuplot . close () ; return 0; }
23.6
Senten cas
A equival encia entre os modos de abertura no C e C++ e dada por: "r" equivale a ios::in; "w" a ios::out e ios::out | ios::trunc; "a" a ios::out | ios::app; "rf" a ios::in | ios::out; "w+" a ios::in | ios::out | ios::trunc. Ap os ler um arquivo de disco at e EOF - End Off File, use clear() para zerar o estado da stream, antes de usar a stream com outro arquivo.
23.7
No Cap tulo 22 - Entrada e Sa da com C++, aprendemos a utilizar as classes streams de C++. Neste cap tulo vimos uma introdu ca o ao acesso a disco, onde aprendemos que um objeto ofstream e utilizado para escrever dados em um arquivo de disco e um arquivo ifstream e utilizado para leitura de dados de um arquivo de disco. Aprendemos que podemos criar um objeto ofstream/ifstream j a o associando a dispositivos de disco, ou deixar para fazer esta associa ca o depois com o m etodo open(). Vimos que podemos armazenar e ler objetos inteiros em disco, e que podemos posicionar os ponteiros de arquivos com os m etodos seekg(), seekp(), tellg(), tellp(). Aprendemos a Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
447
usar redirecionamentos, e vimos que os mesmos funcionam usando > > e < < (da mesma forma que os operadores de inser ca o< < e extra ca o> >). Aprendemos a acessar a impressora e a sa da aux liar, a criar arquivos de disco bin arios, e a executar e enviar comandos para outros programas usando as classes de <pstream.h> (se ca o 23.5.4). No pr oximo cap tulo, Cap tulo 24 - A Classe string, veremos em detalhes o uso de strings de C++.
23.8
Exerc cios
1. Planilhas eletr onicas como excel, calc, gnumeric, podem importar arquivos de texto com dados em ASCII. Monte um programa que gera um conjunto de dados (x,y,z) e a seguir importe os dados usando uma destas planilhas. A seguir monte gr acos x versus y, e x versus z. 2. Criar uma classe CEstat stica, que e utilizada para calcular a m edia e o desvio padr ao de um conjunto de dados passados pelo usu ario usando cin, ou armazenados em um arquivo de disco. 3. Tenho um arquivo de disco com um nome qualquer, que tem o formato abaixo. Criar uma classe CData1D, em que os valores de uma coluna, como a coluna x, possam ser armazenados. CData1D deve armazenar o nome da coluna, a m edia, o desvio padr ao, a vari ancia, o valor m nimo, e o valor m aximo. Observe que para o arquivo a seguir, iremos precisar de 3 objetos do tipo CData1D. 3 # o n umero 3 indica o n umero de colunas x y z # nome das vari aveis, utilizado como t tulos dos gr aficos 123 432 254 321 765 987 .... 890 543 780 4. Criar um programa que usa CData1D e o programa externo gnuplot para plotar os dados. 5. Modique a listagem 23.1, acrescente a possibilidade de se criar um arquivo de disco em que o nome muda de acordo com dois ndices, i e j. 6. Modique a listagem 23.2, de forma que a mesma possa ler um arquivo de texto exportado por uma planilha usando como separador um caracter qualquer denido pelo usu ario (precisa solicitar o nome do separador (ex: ;,-). 7. Modique a listagem 23.3 , acrescentando o uso de seekg() e seekp(). 8. Modique a listagem 23.3, adaptando as mesmas para um caso que seja de seu interesse. 9. Modique a listagem 23.5, substitua ArmazenaObjeto pelo operador < < e LeObjeto pelo operador > >. 10. Modique a listagem 22.4 de forma a obter o n umero de linhas, palavras e caracteres de um arquivo do disco. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
448
11. Montar exemplo que envia para impressora um arquivo postscript (nome.ps). Usar ofstream fout ("/dev/lp0");. 12. Na se ca o 23.5.3, o exemplo usa s.at[i], para acessar a posi ca o i e depois s[i++], esta l ogica esta correta? justique. 13. Modique a listagem 23.6, acrescente uma classe polinomio de grau n. O programa deve solicitar ao usu ario os coecientes do polin onio e a seguir gerar o gr aco no intervalo especicado.
Cap tulo 24
A Classe <string>
A classe <string> foi brevemente apresentada na se ca o 9.4.1 e utilizada em nossos exemplos. Neste cap tulo, vamos nos aprofundar nos conceitos da classe <string>. Veremos uma introdu ca o ` as strings de C++ (se ca o 24.1), discutiremos os diferentes m etodos de <string> (se ca o 24.2), seus construtores (se ca o 24.2.1), iteradores (se ca o 24.2.2), a manipula ca o do tamanho da <string> (se ca o 24.2.3), os operadores de acesso (se ca o 24.2.4), a atribui ca o e concatena ca o (se ca o 24.2.5), a inser ca o, remo ca o e substitui ca o (se ca o 24.2.6). A compara ca o de strings (se ca o 24.2.7), e o uso de substrings (se ca o 24.2.8). Como fazer pesquisas em uma <string> com find e rfind (se ca o 24.2.9). Um exemplo (se ca o 24.3). Finalizamos o cap tulo apresentando algumas senten cas para strings de C++ (se ca o 24.4).
24.1
Introdu c ao ` as strings
A classe basic_string e uma classe template que pode manipular um conjunto de caracteres gen ericos. Normalmente precisamos de caracteres ASCII de 8 bits, ou caracteres de 16 bits. Para satisfazer a estas necessidades, foram denidos os seguintes apelidos: typedef basic_string< char, string_char_traits<char> > typedef basic_string< wchar_t > wstring; string;
Assim, <string> e um apelido para basic_string<char, string_char_traits<char> >, e utilizada para manipular caracteres do tipo char. J a a classe <wstring> e utilizada para manipular caracteres do tipo wchar_t. Nos exemplos que ser ao apresentados nos referimos a <string>, mas os conceitos s ao v alidos para <wstring>. Para utilizar a classe <string>, inclua o arquivo de cabe calho <string>. Exemplo: #include <string>
Nota: nos prot otipos que ser ao apresentados usamos <string> para representar basic_string<char> e char para representar um caracter qualquer. Usamos rst (ou begin()) para indicar um iterador (ou ponteiro) para o in cio da string e last (ou end()) para indicar o m do intervalo (posi ca o n). Num vetor de dimens ao n, podemos acessar da casa 0, at e a casa n-1. Lembre-se this refere-se ao objeto que chama o m etodo. 449
450
24.2
M etodos de <string>
24.2.1
Construtores e destrutor
Um objeto <string> pode ser constru do vazio, a partir de uma outra <string> (de C ou C++), a partir de um caracter ou mesmo de uma sub-string. Observe que alguns construtores recebem o tipo de alocador a ser utilizado. inline string(); Constr oi uma string vazia. explicit string (const Alloc a); Constr oi uma string vazia, recebe o tipo de alocador a ser utilizado. string (const string &src); Construtor de c opia. string (const string& src, size type pos, size type n = npos); Constr oi uma c opia de src a partir da posi ca o pos at e a posi ca o npos. string (const string & src, size type pos, size type n, const Alloc & a); Constr oi string a partir da posi ca o pos da string src, considerando n caracteres. string (size type n, char c, const Alloc& a = Alloc()); Constr oi string de tamanho n, com n c opias do caracter c. string (InputIterator beg, InputIterator end, const Alloc & a = Alloc ()); Constr oi string considerando iteradores beg() e end(). Os iteradores ser ao descritos na se ca o 31.3. Veja a seguir um exemplo. Exemplo: // Cria string com nome s1 string s1; // Cria string com nome s2 e armazena "a classe string" string s2 ("a classe string"); // Cria string com nome s3 e inicializa com " e legal" // utiliza construtor de c opia string s3 = " e legal"; // Cria string com nome s4 uma c opia de s3 // utiliza construtor de c opia string s4 (s3); // Cria string s5, com espa co para 10 caracteres, preenche com b string s5 (10, b); // Cria string s6, uma c opia de s4. // s4.begin() aponta para o in cio de s4 // s4.end() aponta para o fim de s4 string s6 (s4.begin(), s4.end()); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
451
24.2.2
Iteradores
Como dito, a classe <string>, tem semelhan cas com as classes containers da STL. Nesta se ca o descrevemos os m etodos de <string> utilizados para obten ca o de iteradores, ponteiros inteligentes, para partes da <string>. Os iteradores ser ao descritos na se ca o 31.3. iterator begin (); Retorna um iterador para in cio da string. Utilizado para varrer a string do in cio para o m. iterator end (); Retorna um iterador para m da string. Utilizado para informar que chegamos ao m da string. Exemplo: string s = "oi tudo bem!"; for(string::iterator i = s.begin(); i != s.end(); i++) cout < < s[i] ; reverse iterator rbegin (); Retorna um iterador reverso para m da string. Utilizado para varrer a string do m para o in cio. reverse iterator rend (); Retorna um iterador reverso para in cio da string.
24.2.3
A classe <string> tem um conjunto de m etodos para manipula ca o do tamanho da string. Veremos os m etodos size(), length(), capacity(), max_size(), resize(), reserve(), clear(), empty(). size type size () const; Retorna dimens ao utilizada. size type length () const; Retorna dimens ao utilizada (uso obsoleto). size type capacity () const; Retorna capacidade alocada. Exemplo: string msg(100); // Tem capacidade para armazenar 100 caracteres msg = "123456789"; // Mas o size() e de 9 caracteres size type max size () const; Retorna maior dimens ao poss vel para a string, limitada pela quantidade de mem oria dispon vel em seu computador. void resize (size type n); Redimensiona a string para o tamanho n. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
452
void resize (size type n, char c); Redimensiona a string para o tamanho n. Se forem criados novos caracteres os mesmos ser ao preenchidos com o caracter c. void reserve (size type res arg = 0); Reserva espa co de mem oria adicional, muda a capacidade da string. void clear (); Zera a string. O size() da string passa a ser zero. bool empty () const; Returna true se a string estiver vazia Veja a seguir um exemplo. Exemplo: // Cria string com nome s6 e a seguir redimensiona string s6 ("eu terei espa co para 100 caracteres"); s6.resize(100); if(s6.empty()) // Verifica se a string esta vazia cout < < "A string s6 esta vazia.";
24.2.4
Operadores de acesso
O operador [] foi sobrecarregado para acessar cada casa da string. Assim, podemos usar s[i] para acessar o elemento i da string s (da mesma forma que usamos <vector>). O m etodo s.at[i] faz o mesmo que s[i], a diferen ca e que se a casa i n ao existe, s.at[i] lan ca uma exce ca o e s[i] causa um estouro de pilha. reference operator[] (size type pos); Acesso a posi ca o i, usando []. Retorna uma refer encia para i. reference at (size type n); Retorna uma refer encia para posi ca o i. Se a casa i n ao existe, lan ca uma exce ca o. const reference operator[] (size type pos) const; Acesso a posi ca o i, usando []. Retorna uma refer encia constante para i. const reference at (size type n) const; Retorna uma refer encia constante para posi ca o i. Se a casa i n ao existe, lan ca uma exce ca o.
24.2.5
Atribui c ao e concatena c ao
O m etodo assign() e usado para atribuir uma string assign(string); uma parte de uma string, assign(string,inicio,n); uma string de C, assign(cstring); ou um caracter, assign(ch) a uma string de C++. string & assign (const string & str); Atribui a string str, para string this. string & assign (const string & str, size type pos, size type n); Atribui a string str, a partir da posi ca o pos, considerando n caracteres. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
453
24.2.6
Voc e pode remover, remove(), ou substituir, replace(), partes da string. Pode inserir novos caracteres, insert(), ou substrings em uma string existente. void insert (iterator p, size type n, char c); Insere a partir da posi ca o p, n caracteres do tipo c. void insert (iterator p, InputIterator beg, InputIterator end); Insere a partir da posi ca o p, a sub-string acessada por beg e end. string & erase (size type pos = 0, size type n = npos); Apaga bloco de dados a partir da posi ca o pos considerando n caracteres. iterator erase (iterator pos); Apaga caracter na posi ca o dada por pos. iterator erase (iterator begin(), iterator end()); Apaga caracteres no intervalo dado pelos iteradores begin() e end(). string & replace (size type pos, size type n, const string & str); A partir da posi ca o pos, considerando n caracteres, coloca a string str. size type copy (char * s, size type n, size type pos = 0) const; Copia n caracteres de s para posi ca o pos. void swap (string & s); Troca o conte udo das strings. Veja a seguir um exemplo. Exemplo: string s1 = "0123456789"; string s2 = "abcdefghijklmnopqrst"; cout < < s1 < < "\t" < < s2 < < endl; s1.erase(s1.begin()+3); s2.swap(s1); cout < < s1 < < \t < < s2 < < endl;
24.2.7
Compara c ao
Voc e pode comparar strings utilizando os operadores: ==, !=, >, <, >=, <=, ou o m etodo compare(). Se compare() retorna 0 as strings s ao iguais. Se o retorno e menor que zero s1 e maior que s2, se o retorno e maior que zero, s1 e menor que s2. int compare (const string & str) const; Compara string this com str. int compare (size type pos, size type n, const string & str) const; Compara string this com str, a partir da posi ca o pos, considerando n caracteres. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
454
24.2.8
Substrings
Pode-se criar e manipular sub-strings a partir de uma string. string substr (size type pos = 0, size type n = npos) const; Cria uma sub-string a partir da posi ca o pos, considerando n casas. const char* c str(); Retona uma string no estilo de C (uma cstring). Exemplo: string s = "Palmeiras campe~ ao mundial 1951"; string sub = s.substr(0,10);
24.2.9
Pesquisa
A classe <string> fornece fun co es de pesquisa como find() e pesquisa invertida com rfind(). O m etodo find("seq") localiza a primeira ocorr encia de "seq" na string. Pode-se especicar com um inteiro a posi ca o inicial da busca. O m etodo rfind() busca da posi ca o nal para a inicial, ou seja, faz pesquisa reversa. Outros m etodos de pesquisa find_first_of(), find_last_of(), find_first_not_of() e find_last_not_of() tratam a string argumento como um conjunto de caracteres. A posi ca o do primeiro caractere encontrado e retornada e, se n ao encontrar, retorna uma exce ca o do tipo out_of_range. O prot otipo destes m etodos e apresentado a seguir, veja exemplo na listagem ??. size type nd (const string & str, size type pos = 0) const; Procura a primeira ocorr encia da string str, a pesquisa inicia em pos. size type nd (const char * str, size type pos, size type n) const; Procura a primeira ocorr encia da cstring str, a pesquisa inicia em pos e considera at en caracteres. size type rnd (const string & str, size type pos = npos) const; Procura a primeira ocorr encia da string str, a pesquisa inicia em pos e e feita do m de this para o in cio (pesquisa reversa). size type nd rst of (const string & str, size type pos =0) const; Procura a primeira ocorr encia da string str, a pesquisa inicia em pos. size type nd last of (const string & str, size type pos = npos) const; Procura a u ltima ocorr encia da string str, a pesquisa inicia em pos. size type nd rst not of (const string & str, size type pos=0) const; Procura a primeira n ao ocorr encia da string str, a pesquisa inicia em pos. size type nd last not of (const string & str, size type pos = npos) const; Procura a u ltima n ao ocorr encia da string str, a pesquisa inicia em pos e e invertida. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
455
24.3
Na listagem 24.1, alguns m etodos da classe <string> s ao testados. O c odigo esta documentado. Listing 24.1: Usando a classe <string> de C++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 # include < iostream > # include < string > # include < cstring > using namespace std ; int main () { // Cria string com nome s1 string s1 ; s1 = " Oi , tudo bem " ; // Cria string com nome s2 e a r m a z e n a " C ++ e legal " string s2 ( " C ++ e legal " ) ; // Cria string com nome s3 e i n i c i a l i z a com " demais " string s3 = " demais " ; // Cria string com nome s4 uma c o pia de s3 ( usa c o n s t r u t o r de c o pia ) string s4 ( s3 ) ; // Cria string com nome s5 e define t a m a n h o como sendo 100 c a r a c t e r e s string s5 = " eu tenho espa c o para 100 caracteres " ; // R e d i m e n s i o n a a string s5 s5 . resize (100) ; cout << " Conte u do das strings :\ ns1 = " << s1 << " \ ns2 = " << s2 << " \ ns3 = " << s3 << " \ ns4 = " << s4 << " \ ns5 = " << s5 << endl ; // Tamanho , c a p a c i d a d e e cout << " s5 . size () = " << " s5 . capacity () = " << " s5 . max_size () = " t a m a n h o m a ximo da string s5 << s5 . size () << s5 . capacity () << s5 . max_size () << endl ;
// Cria a string s7 e p r e e n c h e com o c a r a c t e r e a string s7 (10 , a ) ; cout << " s7 . size () = " << s7 . size () << " s7 = " << s7 << endl ; // R e d i m e n s i o n a s7 . resize (15 , t ) ; cout << " Depois de s7 . resize (15 , t ) ; s7 . size () = " << s7 . size () << " s7 . length () = " << s7 . length () << " s7 = " << s7 << endl ; // R e t o r n a true se a string s7 e s t i v e r vazia if ( s7 . empty () ) cout << " A string s7 est a vazia " << endl ; // C o pia de s t r i n g s s1 = s2 ; cout << " Ap o s s1 = s2 , s1 = " << s1 << " , s2 = " << s2 << endl ; // A t r i b u i c~ a o de uma string de C s4 = " - p r o f i s s i o n a l " ; // A t r i b u i c~ a o de um u nico c a r a c t e r e s5 = - ; cout << " s4 = " << s4 << " \ t s5 = " << s5 << endl ;
456
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
// A d i c i o n a r a string e x i s t e n t e ( c o n c a t e n a r ) s5 += " Inclui a STL - e e "; cout << " s4 = " << s4 << " \ t s5 = " << s5 << endl ; // A d i c i o n a ao final de s5 , 6 c a r a c t e r e s de s3 , a partir da p o s i c~ a o 1 de s3 . s5 . append ( s3 , 1 , 6) ; cout << " Ap o s s5 . append ( s3 , 1 , 6) ; s5 = " << s5 << endl ; // Cria uma c o pia de s2 , a d i c i o n a s4 , s5 , e mostra na tela cout << " ( s2 + s4 + s5 ) = " << ( s2 + s4 + s5 ) << endl ; // Troca o c o n t e u d o das s t r i n g s s1 e s5 s5 . swap ( s1 ) ; cout << " Ap o s s5 . swap ( s1 ) ; " << endl << " s1 = " << s1 << " \ ns5 = " << s5 << " \ nDo caracter s1 [11] at e s1 [14]= " ; // Acessa a p o s i c~ a o i da string ( como em v e t o r e s) for ( int i = 11; i < 14; i ++) cout << s1 [ i ]; cout << endl ; // Coloca a letra P na p o s i c~ ao 2 s4 [2] = P ; cout << " Ap o s s4 [2]= P , s4 [2]= " << s4 [2] << " s4 = " << s4 << endl ; // O mesmo que s4 [2] , acessa p o s i c~ a o 2 ( com at (2) v e r i f i c a acesso ) cout << " s4 . at (2) = " << s4 . at (2) << endl ; // Cria uma string no padr~ a o C , uma c s t r i n g char cstring [256]; // Copia a string s4 para cstring , usa fun c~ a o strcpy do a r q u i v o de // c a b e c a l h o < cstring > strcpy ( cstring , s4 . c_str () ) ; cout << " cstring = " << cstring << endl ; // Uso de r e p l a c e e insert s5 . replace (9 , 1 , " t " ) ; s4 = " para as outras linguagens " ; s3 . insert ( s3 . end () , s4 . begin () , s4 . end () ) ; cout << s5 << s3 << endl ; s5 = " tem " ; // S u b s t i t u i c a r a c t e r e s de s1 [17] at e s1 [22] por s5 s1 . replace ( s1 . begin () +17 , s1 . begin () +22 , s5 . begin () , s5 . end () ) ; cout << s1 + " - e m u l t i p l a t a f o r m a " << endl ; // A d i c i o n a " p r o g r a m a c~ ao gen erica e " s1 . insert (10 , " programa ca ~ o gen e rica e " ) ; cout << s1 << endl ; // Cria uma s u b s t r i n g de s1 , a partir da p o s i c~ a o 10 at e o final de s1 cout << " s1 . substr (10) = " << s1 . substr (10) << endl ; // Cria uma s u b s t r i n g de s4 cout << " s1 . substr (10 , 12) = " << s1 . substr (10 , 12) << endl ; // C o n c a t e n a n d o s t r i n g s com append // append aceita uma v a r i e d a d e de c o m b i n a c~ oes string s10 ( " Oi " ) ; cout << s10 << endl ;
457
Na listagem 24.2, os m etodos find(), rfind(), find_first_of(), find_first_not_of(), replace() da classe <string> s ao testados. Observe que mostramos como trocar espa cos por , o que e util para renomear arquivos. Tamb em mostramos como trocar a extens ao de um arquivo. Listing 24.2: Usando os m etodos de pesquisa da classe string de C++.
1 2 3 4 5 6 7 # include < iostream > # include < string > # include < cstring > using namespace std ; int main () {
458
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 // Usando find () e rfind () string s1 = " cascavel / parana " ; cout << " s1 = " << s1 << " \ ns1 . find (\" ca \") = " << " \ ts1 . find (\" ca \" , 1) = " << " \ ns1 . rfind (\" ca \") = " << " \ ts1 . rfind (\" ca \" , 2) = "
// s1 [0]= c , s1 [1]= a ,.. << << << << s1 . find ( " ca " ) s1 . find ( " ca " , 1) s1 . rfind ( " ca " ) s1 . rfind ( " ca " , 2) << endl ;
// P r o c u r a a p r i m e i r a o c o r r ^ e n c i a de aeiou int i = s1 . f i n d _ f i r s t _ o f ( " aeiou " ) ; cout << " f i n d _ f i r s t _ o f aeiou = " << i ; // P r o x i m a n~ a o vogal int j = s1 . f i n d _ f i r s t _ n o t _ o f ( " aeiou " , i ) ; cout << " \ n f i n d _ f i r s t _ n o t _ o f aeiou = " << j
<< endl ;
// Para trocar c a r a c t e r e s em uma string string n o m e A r q u i v o C o m E s p a c o s ( " Nome de Arquivo Com Espacos . txt " ) ; cout << n o m e A r q u i v o C o m E s p a c o s << endl ; // Troca os e s p a c o s " " por " _ " int pos = 0; while (( pos = n o m e A r q u i v o C o m E s p a c o s . find ( " " , pos ) ) > 0) n o m e A r q u i v o C o m E s p a c o s . replace ( pos ,1 , " _ " ) ; // Para s u b s t i t u i r a e x t e n s ~ a o de um a r q u i v o pos = n o m e A r q u i v o C o m E s p a c o s . rfind ( " . " ) ; n o m e A r q u i v o C o m E s p a c o s . replace ( pos , 4 , " . dat " ) ; cout << n o m e A r q u i v o C o m E s p a c o s << endl ; return 0; } s1 = cascavel / parana s1 . find (" ca ") = 0 s1 . find (" ca " , 1) = 3 s1 . rfind (" ca ") = 3 s1 . rfind (" ca " , 2) = 0 f i n d _ f i r s t _ o f aeiou = 1 f i n d _ f i r s t _ n o t _ o f aeiou = 2 Nome de Arquivo Com Espacos . txt N o m e _ d e _ A r q u i v o _ C o m _ E s p a c o s . dat
Veja na listagem 24.3 a utiliza ca o das classes <string>, sstream e ifstream para executar um programa do shell. O programa cria um arquivo de disco com o nome lixo, onde s ao armazenados os nomes dos arquivos que t em extens ao *.jpg. A seguir, monta a linha de comando a ser executada. Finalmente, realiza a convers ao de imagens no formato *.jpg para o formato *.ps executando o programa convert (um programa do GNU/Linux usado para converter imagens de um formato para outro). Observe que o programa usa a fun ca o system() para executar comandos do shell. Neste exemplo, o comando os.str() retorna um objeto da classe <string>. Para obter uma string no estilo de C, chama-se adicionalmente o m etodo c_str(). Nota: este exemplo e meramente did atico, visto que existem maneiras mais inteligentes de converter arquivos. Listing 24.3: Usando as classes <string> e sstream para executar comandos do shell.
1 2 3 # include < iostream > # include < fstream > # include < string >
459
24.4
As fun co es insert() e remove() s ao similares as de vetores. A fun ca o replace() e uma combina ca o de remove() e insert(), substituindo o intervalo especicado por novo valor. A fun ca o compare() raramente e acessada diretamente; normalmente utilizamos os operadores de compara ca o (<, <=, ==, !=, >= e >). Pode-se comparar duas strings de C++ ou uma string de C++ com uma string de c (uma cstring). Em C++ o operador == verica se duas strings s ao iguais (se o conte udo e igual). Em Java este operador verica se as duas strings s ao a mesma (ocupam o mesmo espa co de mem oria). O operador endere co (&) aplicado a s[0] n ao e um ponteiro para o primeiro elemento da string. Isto e, a string n ao tem um ponteiro para o primeiro elemento. Para manipula ca o avan cada de strings, utilize iteradores (veja Parte III - Introdu ca o ` a STL). Se a string for redimensionalizada, possivelmente os iteradores existentes ir ao apontar para um monte de lixo (iteradores s ao descritos no Cap tulo 31). Observe que se uma string for muito grande, voc e pode quebr a-la no c odigo usando \. Exemplo: string s = "Releia o cap tulo com aten c~ ao, cada linha e verifique \ como esta pode ser utilizada em seus programas"; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
460
24.5
Vimos uma breve descri ca o da classe <string> na se ca o 9.4.1, neste cap tulo aprendemos novos m etodos da classe <string>. Discutimos os diferentes tipos de construtores, o uso de iteradores, operadores de acesso e operadores de compara ca o de strings. A classe <string> tem um conjunto de m etodos para manipula ca o do tamanho da string. Pode-se obter o tamanho utilizado com size() e a capacidade real da string com capacity(). Pode-se redimensionalizar a string com resize(). O m etodo max_size() retorna o tamanho da maior string que pode ser constru da. O m etodo length() e denido para manter compatibilidade com vers oes antigas da classe <string>. Vimos o uso de substrings. No nal do cap tulo aprendemos a fazer pesquisas em uma <string> com find(), rfind(). E ainda vimos o arquivo <string> da biblioteca padr ao. Nota: Os livros de C++ procuram explicar apenas parte das fun co es/m etodos da biblioteca padr ao. Isto se deve ` a necessidade de se limitar o n umero de p aginas dos livros. Se f ossemos incluir todos os m etodos os livros passariam de 2000 p aginas. A dica e: para conhecer em detalhes determinada classe da biblioteca padr ao, abra e leia o arquivo correspondente.
24.6
Exerc cios
1. Monte um exemplo em que a lista de arquivos de um diret orio e armazenada em um arquivo de disco. A seguir pergunte para o usu ario qual arquivo quer localizar. Depois abra o arquivo e use os m etodos de <string> para localizar e mostrar partes do arquivo que foi aberto. 2. Adicione ao programa anterior a possibilidade de renomear arquivos. 3. Adicione ao programa anterior a possibilidade de mudar a extens ao dos arquivos. 4. Crie um programa que calcula o tamanho m nimo, m aximo e m edio dos arquivos em um determinado diret orio. 5. Criar um programa que recebe um arquivo de disco e calcula: o n umero de letras, palavras e frases. A freq u encia de ocorr encia de cada letra (visualizar o histograma utilizando o programa gnuplot ). c por c, a por a. 6. Monte um programa que troque: por , 7. Corrigir o exemplo da listagem 24.3, de forma que os arquivos que tenham espa co no nome possam ser convertidos corretamente. 8. Criar exemplo que use as diferentes vers oes de: find(), rfind(), find_first_of() e find_first_not_of(). 9. Leia agora o arquivo /usr/include/c++/4.1.1/bits/basic string.h, da biblioteca padr ao.
Cap tulo 25
Convers oes
Neste cap tulo mostraremos o prot otipo para convers oes entre objetos (se ca o 25.1) e sua necessidade (se ca o 25.2). A seguir veremos o construtor de convers ao (se ca o 25.3), o operador de convers ao (se ca o 25.4) e o uso de explicit em construtores (se ca o 25.5). Discutiremos ainda a utiliza ca o de static_cast<> (se ca o 25.6), dynamic_cast<> (se ca o 25.7), const_cast<> (se ca o 25.8) e reinterpret_cast (se ca o 25.9). Finalmente veremos algumas senten cas para convers oes (se ca o 25.10).
25.1
Na vida real estamos o tempo todo adaptando os objetos para uso diferente do inicialmente projetado. Poder amos citar milhares de casos, mas vamos mostrar apenas alguns poucos, bem comuns: Voc e precisa de um abridor de latas, mas s o tem uma faca, o que voc e faz? A resposta e simples e direta, usa a faca como abridor de lata. Voc e precisa de uma chave de fenda, mas s o tem uma faca, o que voc e faz? A resposta e simples e direta, usa a faca como chave de fenda. Quando temos um programa real nos deparamos com diversas situa co es onde precisamos utilizar um objeto para uma fun ca o alternativa. De um modo geral, o objeto pode ser utilizado para uma fun ca o n ao previamente planejada, desde que tenha funcionalidades semelhantes ao objeto a ser substitu do. Um caso usual de convers oes e a convers ao entre n umeros, de inteiro (int) para utuante (float) e vice-versa. Outro exemplo e a convers ao de classes-derivadas em classes-base. Veja a seguir o prot otipo para deni ca o e uso dos construtores de convers ao e dos operadores de convers ao. Ao longo deste cap tulo os mesmos ser ao detalhados. Prot otipo: class Base { // Declara ca o de construtor com explicit (veja se ca o 25.5) explicit Base (par ametros); }; 461
462
25.2. NECESSIDADE DE CONVERSAO class Derivada : public Base { // Construtor de convers ao (veja se ca o 25.3) // Cria objeto da classe-derivada a partir de objeto da classe-base Derivada(const Base & obj){}; // Declara ca o de operador de convers ao para classe-base (veja se ca o 25.4) operator Base(); // Declara ca o de operador de convers ao, converte para outro tipo (veja se ca o 25.4) operator Tipo(); }; // Deni ca o do m etodo de convers ao Tipo Derivada::operator Tipo() { // Descri ca o de como se processa a convers ao return(Tipo); }; ... // Utiliza ca o de static cast<> (veja se ca o 25.6) Derivada der; Base base = static cast<Base> (der); // Utiliza ca o de dynamic cast<> (veja se ca o 25.7) Base* ptrBase = new Derivada; Derivada* ptrDerivada = dynamic cast <Derivada*> (ptrBase); // Utiliza ca o de refer encias e dynamic cast<> (veja se ca o 25.7.1) Tipo & ref = dynamyc cast<Tipo & >(r); ca o 25.8) // Utiliza ca o de const cast<> (veja se Tipo* ptr = const cast<Tipo*> (const ptr);
25.2
Necessidade de convers ao
Voc e j a sabe que existe uma hierarquia de classes para os tipos num ericos e um sistema de convers ao entre os diferentes tipos num ericos. Assim, um int pode ser convertido em double (sem perda de dados) e um double pode ser convertido em int (com poss vel perda de dados). Da mesma forma, os tipos denidos pelo programador tamb em podem ser convertidos, devendo o programador denir a forma como esta convers ao deve ser realizada. Observe o seguinte exemplo: digamos que exista uma classe B e uma classe-derivada D, e que foi criado o objeto b1 do tipo B e o objeto d1 do tipo D. Criamos tamb em os objetos b2, fazendo B b2 = d1; e um objeto b3, fazendo B b3 = b1;. Como a classe D e derivada da classe B, um objeto do tipo D pode ser convertido para B. Entretanto, n ao e poss vel criar um objeto do tipo D a partir de um objeto do tipo B, (fazendo D d2 = b1;), porque B e menor que D. A listagem 25.1 esclarece melhor esta situa ca o. Listing 25.1: Mostrando a necessidade de convers oes.
1 2 3 4 5 6 7 8 // Define tipo B class B { public : int x ; }; // Define tipo D class D : public B
463
// // // // //
Cria objeto do tipo B com nome b1 Cria objeto do tipo D com nome d1 Ok Ok Erro , b1 n~ a o p r e e n c h e d2 ( b1 n~ a o tem y ) .
n e c e s s i d a d e C o n v e r s a o . cpp : In function int main () : n e c e s s i d a d e C o n v e r s a o . cpp :19: error : conversion from B to non - scalar type D requested
Na linha B b2 = d1; o c odigo funciona porque d1 tem os atributos x e y e o compilador faz b2.x = d1.x;. Na linha D d2 = b1; b1 s o tem o atributo x, e d2 precisa de um x e um y. Como b1 n ao tem y, o compilador acusa o erro. A solu ca o para este tipo de problema e a utiliza ca o de construtores de convers ao, descritos a seguir.
25.3
Construtor de convers ao
Um construtor de convers ao e utilizado para construir um objeto do tipo D a partir de um objeto do tipo B. Isto e, recebe um objeto do tipo base e constr oi um objeto do tipo derivado. Veja no exemplo a seguir que o construtor do objeto D, faz y = 0;. Exemplo: class D: public B { int y; // Construtor de convers~ ao, recebe um B e constr oi um D D(const& B obj) { this->x = obj.x; this->y = 0; } }; Com o construtor de convers ao do exemplo acima, resolvemos o problema da linha D d2 = b1; preenchendo o valor de y com zero (this->y = 0;). Entretanto, se tivermos Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
464 B b; D d; d = b;
o objeto b e o objeto d j a foram criados. Neste caso e necess ario um m etodo que converta o objeto b em d. Para solucionar este problema, utiliza-se um operador de convers ao descrito na se ca o 25.4.
25.4
Um operador de convers ao e utilizado para converter um objeto de um tipo em outro. Observe que o m etodo n ao precisa ser da mesma hierarquia. O prot otipo e dado a seguir. Veja que o m etodo operator Tipo(); deve converter de CNome para Tipo. Observe o uso da palavra-chave operator, seguida do nome do tipo a ser criado a partir de CNome. Prot otipo: class CNome {... // Declara ca o de m etodo de convers ao operator Tipo(); }; No exemplo a seguir o operator B() e utilizado para converter um objeto do tipo B num objeto do tipo D. Note que para utilizar o m etodo de convers ao, podemos ter uma convers ao impl cita ou explicita. Exemplo: class D { public: int y; operator B() { B* b = new B(); b->x = this->x; return *b; } }; int main() { B b; D d; b = d; // b = (B) d; // // tico de C++ b = static_cast< return 0; }
// Converte da classe D para classe B // Cria objeto do tipo B // Preenche atributos do objeto b // Retorna objeto
Impl cita, converte de d para b Expl cita, com a utiliza c~ ao de cast de d Expl cita, com a utiliza c~ ao do cast est aB > (d);
Veremos o uso de static_cast< >(); na se ca o 25.6. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
465
25.5
Em algumas hierarquias as convers oes ocorrem automaticamente. Se voc e n ao quiser que isso ocorra, ou seja, quiser ter controle das convers oes, utilize a palavra-chave explicit na declara ca o do construtor. Veja na listagem 25.2 exemplo de uso de construtor com explicit. Observe que na linha Saida(10); deveria ocorrer um erro, pois Saida() recebe como par ametro um CData, e estamos passando um int. Mas como existe um construtor de CData que recebe um int, o compilador vai criar automaticamente um objeto CData e a seguir chamar Saida(). Observe na sa da que ao trocar o construtor CData por explicit CData o compilador n ao realiza a convers ao autom atica e emite o erro de inicializa ca o incorreta. Veja na sa da que quando o construtor n ao usa explicit, a linha Saida(10); funciona, pois o compilador troca automaticamente a linha Saida(10); por Saida(CData(10)); ou seja, cria um CData a partir do n umero 10 e a seguir executa o m etodo Saida(). Listing 25.2: Usando construtor com explicit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # include < iostream > using namespace std ; class CData { public : int x ; // C o n s t r u t o r sem uso de e x p l i c i t CData ( int _x = 10) : x ( _x ) { }; // C o n s t r u t o r com uso de e x p l i c i t // e x p l i c i t CData ( int _x = 10) : x ( _x ) { } }; // Fun c~ a o global , recebe um objeto do tipo CData void Saida ( const CData & dat ) { cout << dat . x << endl ; } int main () { int i = 5; CData data ( i ) ; cout << " Saida ( data ) ; " ; Saida ( data ) ; cout << " Saida ( 10 ) ; " ; Saida ( 10 ) ; return 0; } Sa da sem uso de explicit : ------------------------bash -3.00 $ ./ a . out Saida ( data ) ; 5 Saida ( 10 ) ; 10
466
Sa da com uso de explicit : ------------------------bash -3.00 $ g ++ Usando - explicit . cpp Usando - explicit . cpp : In function int main () : Usando - explicit . cpp :37: error : invalid i n i t i a l i z a t i o n of reference of type const CData & from expression of type int Usando - explicit . cpp :19: error : in passing argument 1 of void Saida ( const CData &)
25.6
Na linguagem C uma vari avel int pode ser convertida para double usando-se cast. Exemplo: int x = 3; float y = (float) x; Neste exemplo o cast e o trecho de c odigo (float), que for ca a convers ao de x do tipo int para float. como se Note que o uso de cast subverte o controle de tipos realizados pelo compilador. E o programador dissece para o compilador ca tranquilo, eu sei o que estou fazendo. Ou seja, a responsabilidade pelo uso do cast e toda do programador. Para implementar o conceito de cast em C++, usamos a palavra-chave static_cast<>. Veja prot otipo a seguir. Note que static_cast<> e utilizado para convers oes de tipos em tempo de compila ca o. Se a convers ao for ilegal, o compilador acusa o erro, o que n ao e feito no cast de C. Prot otipo: TipoA obja; TipoB objb = static cast<TipoB> (obja); No exemplo a seguir, static_cast<> converte de float para double. Exemplo: float fpi = 3.141516; double dpi = static_cast<double>(fpi);
25.7
Quando temos uma hierarquia de classes, podemos criar um ponteiro para a classe-base e fazer com que esse ponteiro aponte para um objeto de uma classe-derivada (veja Cap tulo 19 Polimorsmo). Em algumas ocasi oes e necess ario converter o ponteiro da classe-base em um ponteiro de classe-derivada. Isto e feito com o uso de cast din amico, um cast realizado em tempo de execu ca o e que utiliza a palavra-chave dynamic_cast<>. No prot otipo a seguir converte o ponteiro ptrBase para um ponteiro do tipo TipoDerivado. Funciona se TipoDerivado e derivado direta ou indiretamente do TipoBase, caso contr ario retorna uma exce ca o do tipo bad_cast (veremos exce co es no Cap tulo 26 - Exce co es). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
DINAMICA 25.7. CONVERSAO COM DYNAMIC_CAST<> Prot otipo: TipoBase* ptrBase; ptrBase = new TipoDerivado; TipoDerivado* ptr = dynamic cast <TipoDerivado*> (ptrBase);
467
No exemplo a seguir, cria-se um ponteiro pm que aponta para um objeto TImagem (derivado). Posteriormente cria TImagem* im a partir de pm, utilizando dynamic_cast<>. Funciona porque o objeto criado e apontado por pm e um objeto do tipo TImagem. Exemplo: class TMatriz{}; // Classe-base class TImagem: public TMatriz{}; // Classe-derivada TMatriz* pm; // Ponteiro para classe-base pm = new TImagem(); // Aponta para objeto derivado .................... // pm e usado // Converte pm para im usando dynamic_cast<> TImagem * im = dynamic_cast < TImagem* > (pm); Veja no exemplo da listagem 25.3 a utiliza ca o de dynamic_cast<>. Listing 25.3: Usando dynamic_cast e typeid.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 // E x t r a d o do HELP do B o r l a n d C ++ 5.0 e a d a p t a d o # include < iostream > # include < typeinfo > using namespace std ; class Base1 { virtual void f () }; class Base2 {}; // Base1 { };
// Base2
// D e r i v a d a class Derivada : public Base1 , public Base2 { }; int main () { Derivada d ; // Cria objeto d Derivada * pd = 0; // P o n t e i r o para D e r i v a d a Base1 * pb1 = & d ; // P o n t e i r o para Base1 , aponta para objeto d cout << " Tipo do ponteiro resultante = " << typeid ( pb1 ) . name () << endl ; cout << " Realiza um cast din^ a mico ( downcast ) de Base1 para Derivada .\ n " ; if (( pd = d y n a m i c _ c a s t < Derivada * >( pb1 ) ) != 0) { cout << " Tipo do ponteiro resultante = " << typeid ( pd ) . name () << endl ; } // Fique atento a h i e r a r q u i a da classe . // Cast de uma classe B1 para D e depois de D para B2 . Base2 * pb2 = 0; cout << " Realiza um cast din^ a mico ( croscast ) de Base1 para Base2 . " << endl ; if (( pb2 = d y n a m i c _ c a s t < Base2 * >( pb1 ) ) != 0) {
468
38 39 40 41 42
return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ a . out Tipo do ponteiro resultante = P5Base1 Realiza um cast din^ a mico ( downcast ) de Base1 para Derivada . Tipo do ponteiro resultante = P8Derivada Realiza um cast din^ a mico ( croscast ) de Base1 para Base2 . Tipo do ponteiro resultante = P5Base2
Para uso do cast din amico e necess aria a passagem do par ametro - RTTI para o compilador (leia informa co es de seu compilador). A sigla RTTI signica Run-Time Type Information , ou seja, informa co es sobre os objetos criados em tempo de execu ca o. A utiliza ca o do RTTI e do dynamic_cast<> implica c odigos maiores e mais lentos.
25.7.1
O dynamic_cast<> tamb em pode ser utilizado com refer encias, veja o prot otipo. Se o dynamic_cast<> para uma refer encia falha, uma exce ca o do tipo bad_cast e lan cada. Veremos o uso de exce co es no Cap tulo 26 - Exce co es. Prot otipo: Tipo & ref = dynamic cast< Tipo & >(r);
25.8
Quando o ponteiro e const, dynamic_cast<> e static_cast<> n ao podem ser utilizados. Neste caso, voc e deve utilizar const_cast<>. Veja a seguir o prot otipo e um exemplo. Observe que o ponteiro ptr vai ser convertido para T*. Prot otipo: const T* constptr; T* ptr = const cast<T*> (constptr); Exemplo: void f(const T* constptr ) { T* ptr = const_cast<T*> (constptr ); .... }
25.9
A palavra-chave reinterpret_cast<> permite reinterpretar um cast. Veja exemplo na listagem 21.4. Note que com reinterpret_cast<> podemos for car qualquer tipo de convers ao entre tipos (semelhante ao antigo cast de C). Prot otipo: T* p = reinterpret cast<T*> (ptr); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
25.10. SENTENCAS PARA CONVERSOES Exemplo: int main() { int a = 3; int* pa = &a; cout < < "pa=" < < *pa < < endl; // Imprime o caracter ! cout < < *reinterpret_cast<char*>(pa) < < endl; return 0; }
469
Dica: n ao use reinterpret_cast<>. Se em algum momento precisar dele e sinal de que sua modelagem esta com problemas.
25.10
Lembre-se um cast subverte o sistema de verica ca o de tipo, devendo ser evitado. Convers oes denidas pelo programador somente s ao utilizadas implicitamente se forem n ao amb guas. Um n umero inteiro com valor 0 e convertido para false. Qualquer n umero diferente de zero e convertido para true. M etodos de convers ao podem ser virtuais. A biblioteca-padr ao utiliza m etodos de convers ao. No exemplo a seguir o operador while espera um bool (0 ou != 0), enquanto a chamada a cin > > x;, for realizada corretamente; cin e convertido em true, se cin > > x; falha, cin e convertido em false. Exemplo: while( cin > > x ) cout < < "objeto :" < < x < < " lido."; Tente ocultar do usu ario o uso de cast. Segundo [Lischner, 2003], um lvalue e convertido automaticamente para rvalue, se o contexto requer um rvalue. Um valor de uma enumera ca o e convertido automaticamente para int, mas um int n ao e convertido automaticamente para uma enumera ca o. Para converter um int para uma enumera ca o usamos static_cast<>. Veja exemplo na listagem G.2. Um m etodo de convers ao em uma classe-derivada n ao oculta um m etodo de convers ao em uma classe-b asica, a menos que os dois m etodos convertam para o mesmo tipo. Seja cauteloso com o uso de convers oes impl citas, pois elas podem funcionar de modo inesperado. Ou seja, use explicit e evite surpresas. Reduza o n umero de m etodos construtores utilizando argumentos pr e-denidos. Com a palavra-chave explicit, o construtor s o ser a chamado de forma expl cita. Sempre testar o ponteiro ap os o dynamic_cast<>. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
470
Se o ponteiro for const, voc e deve utilizar const_cast<>. Pode-se reduzir o uso de dynamic_cast<> (que e lento), incluindo-se na classe-base o m etodo que desejamos acessar. Se a classe destino for privada ou protegida, o dynamic_cast<> falha. Observe que voc e n ao deve usar RTTI com o tipo void*. Prera dynamic_cast<> a typeid(). O tempo de processamento para vericar um dynamic_cast<> (ou typeid()) e maior que o usado para localizar um m etodo virtual. Se numa hierarquia voc e tiver classes duplicadas, bases virtuais acess veis por mais de um caminho, deve vericar se o cast desejado n ao e amb guo. Se for amb guo, o dynamic_cast<> retorna 0 (ou bad_cast). Um cast para classe-derivada e chamado dowcast, e para classe-base upcast. 3 Para converter da classe C para a classe H (sendo H n ao herdeira de C), deve-se criar uma fun ca o de convers ao dentro da classe C, e declarar como friend dentro de H. 3 Convers oes impl citas e fun co es friend n ao podem ser criadas com refer encias simples (&). Exemplo: friend ...return X& ; // Erro // Mas podem ser criados para friend...return ...const X& ; friend....return...X;
25.11
Neste cap tulo entendemos a necessidade das convers oes. Aprendemos os diferentes prot otipos para realizar convers oes entre objetos. Vimos que podemos realizar convers oes com construtores e com m etodos de convers ao. Vimos ainda que o construtor de convers ao pode ser utilizado para criar objetos novos a partir de objetos de diferentes tipos. Aprendemos a utilizar o operador de convers ao para converter um objeto existente para outros tipos. Eliminamos as convers oes autom aticas nos construtores com o uso de explicit. Aprendemos ainda a utilizar os operadores de convers ao: static_cast<>, const_cast<> e reinterpret_cast<>. Aprendemos a criar um ponteiro para uma classe herdeira da classe-base a partir de um ponteiro para classe-base usando dynamic_cast<>.
25.12
Exerc cios
1. Tente descrever exemplos pr aticos onde o uso de convers oes e importante. 2. Implemente os exemplos da se ca o 25.2, e veja as mensagens de erro. 3. Modique a listagem 25.2. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
25.12. EXERC ICIOS 4. Ampliar a hierarquia da listagem 25.3. 5. Monte um exemplo para convers ao de moedas de diferentes pa ses.
471
472
Cap tulo 26
Exce c oes
Neste cap tulo apresentaremos os conceitos b asicos e a utiliza ca o de exce co es. Como ca a seq u encia de controle em um programa com exce co es. Iniciamos com uma introdu ca o ` as exce co es (se ca o 26.1). A seguir veremos o prot otipo para exce co es (se ca o 26.2), e seus conceitos b asicos de exce co es (se ca o 26.3), como o uso de try (se ca o 26.3.1), throw (se ca o 26.3.2) e catch (se ca o 26.3.3). Veremos ainda uma lista com as exce co es-padr ao (se ca o 26.4). A seq uencia de execu ca o do programa (se ca o 26.5), sem (se c ao 26.5.1) e com exce ca o (se ca o 26.5.2). Como ca a pilha (heap ) em um programa com exce co es (se ca o 26.6). O que ocorre com exce co es n ao tratadas (se ca o 26.7)? Na se ca o uso avan cado de exce co es (se ca o 26.8) veremos temas como: exce ca o para new (se ca o 26.8.1), controlando entrada com exce co es (se ca o 26.8.1), e uma pol tica para uso de exce co es(se ca o 26.8.1).
26.1
A utiliza ca o de exce co es permite a constru ca o de programas mais robustos, com maior toler ancia a falhas. O exemplo da listagem 26.1 mostra um problema usual em programas, a divis ao por zero. Observe na sa da que o valor de c, de acordo com o padr ao ANSI C++, e igual a inf, representando um valor muito grande (innito). Listing 26.1: Exce co es: Divis ao por zero.
1 2 3 4 5 6 7 8 9 10 11 12 13 // Uma d i v i s ~ a o por zero sem c o n t r o l e de erro # include < iostream > int main () { float a = 3.0; float b = 0.0; float c = a / b ; float d = c ; std :: cout << " a = " << a << " b = " << b << " c = a / b = " << c << " d = " << d << std :: endl ; return 0; }
473
474
A solu ca o usualmente adotada para resolver este problema e algo como apresentado na listagem 26.2. Observe que embora o programa n ao tenha mais um bug, h a a necessidade de se criar um conjunto de ags e verica co es adicionais. Listing 26.2: Exce co es: Divis ao por zero com controle simples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # include < iostream > using namespace std ; int main () { float a = 3.0; float b ; float c ;
cout << " Entre com b : " ; cin >> b ; cin . get () ; if ( b == 0 ) // c o n t r o l e cout << " Erro b == 0 " << endl ; else { c = a / b; cout << " c = a / b = " << c << endl ; } return 0; } bash -3.00 $ ./ a . out Entre com b :7 c = a / b = 0.428571 bash -3.00 $ ./ a . out Entre com b :0 Erro b == 0
De uma maneira geral, o controle de erros em um programa pode ser feito de duas formas. No meio do c odigo (forma usual), controlando a entrada de dados e os uxos do programa. Esta metodologia de controle deixa o c odigo mais confuso, pois o tratamento dos erros ca no meio do c odigo. Utilizando as t ecnicas de tratamento de exce co es, que permitem uma formula ca o mais robusta para o tratamento e a verica ca o de erros em um programa. O uso das t ecnicas de tratamento de exce co es e o foco deste cap tulo.
26.2
Veja a seguir o prot otipo para uso de exce co es. Observe que o bloco try tenta executar um bloco de c odigo. Se neste bloco ocorrer algum problema, uma exce ca o e lan cada com throw. A exce ca o e capturada e tratada (processada) pelo bloco catch. Prot otipo: ... try { ... Tipo obj;... Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
26.3. CONCEITOS BASICOS DE EXCEC OES throw obj; } catch(Tipo & obj) { ...tratamento da exce ca o... }
475
26.3
Uma exce ca o e uma condi ca o excepcional que ocorre em um programa, o que exige um composta basicamente de tr tratamento especial. E es elementos: Um bloco try que cont em o bloco de c odigo a ser executado (veja se ca o 26.3.1). Uma ou mais chamadas a throw, anunciando que ocorreu a exce ca o. O throw lan ca uma exce ca o, lan ca um objeto que ser a capturado por um bloco catch (veja se ca o 26.3.2). Um ou mais blocos catch, que s ao respons aveis pelo tratamento das exce co es lan cadas com throw (veja se ca o 26.3.3). O exemplo da listagem 26.3 ilustra o processo. Neste exemplo inclu mos o tratamento de exce co es. Dentro do bloco try se b == 0, o programa lan ca uma exce ca o do tipo out_of_range. A exce ca o lan cada com throw e capturado pelo bloco catch(out_of_range). Observe que colocamos v arios blocos catch. Ou seja, podemos lan car v arios tipos de exce co es com throw e cada exce ca o lan cada deve ser capturada com o bloco catch correspondente (se ca o 26.3.3). Por exemplo, um throw domain_error; e capturado pelo catch (domain_error obj). Um throw out_of_range; e capturado pelo catch (out_of_range obj). Observe na sa da que quando b == 0, o bloco catch (out_of_range obj) e executado. Listing 26.3: Exce co es: Divis ao por zero com exce co es.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 # include < iostream > # include < string > # include < exception > # include < stdexcept > using namespace std ; // Uma d i v i s ~ a o por zero com t r a t a m e n t o de e x c e c~ oes int main () { float a = 3.0; float b ; float c ; // Bloco try try { cout << " Entre com b : " ; cin >> b ; cin . get () ; if ( b == 0) // Lan ca a exce c~ a o do tipo o u t _ o f _ r a n g e throw o u t _ o f _ r a n g e ( " divis~ a o por zero " ) ; c = a / b; cout << " c = a / b = " << c << endl ; } // C a p t u r a e x c e c~ a o do tipo o u t _ o f _ r a n g e ( fora do i n t e r v a l o )
476
27 28 29 30 31 32 33 34 35 36 37
catch ( o u t _ o f _ r a n g e obj ) { cout << " Exce ca ~ o o u t _ o f _ r a n g e : " << obj . what () << endl ; } // C a p t u r a e x c e c~ a o do tipo d o m a i n _ e r r o r ( erro de d o m nio) catch ( d o m a i n _ e r r o r obj ) { cout << " Exce ca ~ o d o m a i n _ e r r o r : " << obj . what () << endl ;} // C a p t u r a q u a l q u e r tipo de exce c~ a o , devendo , // por este motivo ser o u ltimo catch . catch (...) { cout << " Ocorreu uma exce ca ~ o diferentes de o u t _ o f _ r a n g e . " ; } return 0; } bash -3.00 $ ./ a . out Entre com b :1 c = a / b = 3 bash -3.00 $ ./ a . out Entre com b :0 Exce ca ~ o o u t _ o f _ r a n g e : divis~ a o por zero
Veja a seguir a descri ca o dos tr es componentes de uma exce ca o, o uso de try (se ca o 26.3.1), throw (se ca o 26.3.2) e catch (se ca o 26.3.3)
26.3.1
try
Os blocos try podem lan car uma ou mais exce co es, lan cando diferentes tipos de objetos. Dentro do bloco try voc e pode lan car diretamente uma exce ca o com throw ou chamar m etodos - que podem ser encadeados - e que em algum momento lancem uma exce ca o com throw. Exemplo: try { M1(); M1(){ M2(); M2(){ M3(); M3(){ throw }; }; }; "erro"; }; // // // // Tenta executar o bloco que chama M1() M1() chama M2() M2() chama M3() M3() lan ca uma exce c~ ao
O lan camento de uma exce ca o por um m etodo naliza imediatamente a execu ca o do m etodo, e chama o pr oximo bloco catch que recebe o tipo de objeto lan cado. Observe que uma exce ca o permite a um m etodo ter um retorno diferente do especicado, alterando a linha de execu ca o do programa (veja se ca o 26.6).
26.3.2
throw
O throw e usado para lan car um objeto, indicando que uma exce ca o ocorreu. O uso de throw e similar a chamada de um m etodo. Se um m etodo lan ca uma exce ca o com throw, voc e pode mudar sua declara ca o, incluindo as exce co es que podem ser lan cadas. A vantagem em se declarar os tipos de exce co es que um m etodo pode lan car e que o compilador confere e impede que o m etodo lance uma exce ca o n ao declarada em seu prot otipo. Veremos exemplo na listagem 26.5. Prot otipo: retorno NomeM etodo(par ametros) throw (tipoExce ca o1, tipoExce ca o2, ...); Exemplo: // Declara c~ ao de m etodo informando a exce c~ ao que pode ser lan cada Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
26.3. CONCEITOS BASICOS DE EXCEC OES void M1() throw (out_of_range& ob); // Declara c~ ao de m etodo que pode lan car mais de um tipo de exce c~ ao void M2() throw (out_of_range& ob, string &s);
477
O throw funciona como um retorno multin vel, visto que o retorno do m etodo e diferente do especicado. De um modo geral os objetos lan cados com throw s ao const tipo&. Disparar uma exce ca o com throw fora de um bloco try provoca o encerramento do programa, executando a fun ca o terminate(). Veja se ca o 26.7. Uma exce ca o lan cada com throw e considerada tratada (encerrada), assim que entra no bloco catch. A especica ca o dos tipos de exce co es que podem ser lan cadas n ao fazem parte da assinatura do m etodo (vericada em tempo de compila ca o). Isto indica, que os mesmos s o s ao considerados na execu ca o, devendo ser evitados.
26.3.3
catch
O catch e o tratador de exce co es. O bloco catch ir a capturar o objeto lan cado com throw e realizar a os processamentos necess arios. Logo ap os o bloco try, voc e deve ter o bloco catch. Como um bloco try pode lan car mais de um tipo de exce ca o, voc e pode ter mais de um bloco catch, um para cada tipo de objeto lan cado. Exemplo: // Captura exce c~ ao do tipo string catch(string s) {......}; // Captura exce c~ ao do tipo int catch(int i) {......}; // Captura exce c~ ao do tipo domain_error (erro de dom nio) catch (domain_error obj) { cout < < "Exce c~ ao domain_error: " < < obj.what() < < endl;} // Captura exce c~ ao do tipo invalid_argument (argumento inv alido) catch (invalid_argument obj) { cout < < "Exce c~ ao invalid_argument: " < < obj.what() < < endl;} // Captura exce c~ ao do tipo out_of_range (fora do intervalo) catch (out_of_range obj) { cout < < "Exce c~ ao out_of_range: " < < obj.what() < < endl;} // Captura exce c~ ao do tipo range_error (erro no intervalo) catch (range_error obj) { cout < < "Exce c~ ao range_error: " < < obj.what() < < endl;} // Captura exce c~ ao do tipo overflow_error (n umero muito grande) catch (overflow_error obj) { cout < < "Exce c~ ao overflow_error: " < < obj.what() < < endl;} // Captura exce c~ ao do tipo underflow_error (n umero muito pequeno) catch (underflow_error obj) { cout < < "Exce c~ ao underflow_error: " < < obj.what() < < endl;} Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
478
26.4. EXCEC OES-PADR AO // Trata qualquer tipo de exce c~ ao (deve ser o ultimo catch) catch(...) {......};
Observe que o bloco catch s o e executado se tiver sido lan cada uma exce ca o com throw. Se foi lan cado um objeto do tipo T, o bloco catch a ser executado e aquele que trata um objeto do tipo T. Um grupo de tratamento catch se assemelha a um if..else encadeado. Um catch pode receber um objeto, uma refer encia a um objeto, um objeto constante ou um ponteiro para um objeto. Como um catch(...) trata qualquer tipo de exce ca o, este deve ser o u ltimo catch. Observe ainda que como catch(...) n ao recebe nenhum objeto, n ao tem muita ec acia. Dentro de um bloco catch, voc e pode relan car a exce ca o chamando apenas throw.
26.4
Exce c oes-padr ao
Veremos a seguir algumas exce co es-padr ao do C++. As mesmas est ao listadas nos arquivos de cabe calho <exception> e <stdexcept> (veja Figura 26.1). Estas exce co es s ao lan cadas automaticamente pelo sistema. Por exemplo, se ocorre uma falha de aloca ca o uma exce ca o padr ao do tipo bad_aloc e lan cada. Se o argumento de uma fun ca o e inv alido, uma exce ca o invalid_argument e lan cada. Se uma opera ca o matem atica gera um n umero muito grande, uma exce ca o do tipo overflow_error e lan cada. Ou seja, C++ tem um conjunto de exce co espadr ao, quando a falha ocorre, a exce ca o e lan cada. Exce co es: bad_alloc (falha aloca ca o), bad_cast (falha convers ao), bad_typeid (falha verica ca o de tipo), bad_exception (falha de exce ca o). Para indicar erros l ogicos: invalid_argument (argumento inv alido), lenght_error (dimens ao errada), out_of_range (fora do intervalo), domain_error (fora do dom nio). Para indicar erros em tempo de execu ca o: overflow_error (n umero muito grande), underflow_error (n umero muito pequeno), range_error (erro em opera co es matem aticas). Observe que as exce co es padr ao formam uma hierarquia. Da mesma forma, voc e pode criar hierarquias de classes que far ao o tratamento das exce co es lan cadas. Assim, o c odigo para tratamento de erro pode ser reaproveitado. Outra vantagem e que a declara ca o do m etodo que lan ca a exce ca o pode conter apenas a classe base da hierarquia de exce co es, veja o prot otipo. Prot otipo: retorno NomeM etodo(par ametros) throw (nomeClasseBase);
26.5
A seq u encia de execu ca o do programa pode ser normal, isto e, sem ocorr encia de exce co es (se ca o 26.5.1) ou com ocorr encia de exce ca o (se ca o 26.5.2). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
479
logic_error
+<stdexcept>
bad_alloc
+<new>
bad_cast
+<typeinfo>
bad_exception
+<exception>
bad_typeid
+<typeinfo
ios_base::failure
+<ios>
out_of_range
+<stdexcept>
lenght_error
+<stdexcept>
invalid_argument
+<stdexcept>
domain_error
+<stdexcept>
runtime_error
+<stdexcept>
underflow_error
+<stdexcept>
overflow_error
+<stdexcept>
range_error
+<stdexcept>
26.5.1
No exemplo ilustrado na Figura 26.2, quando n ao ocorre nenhuma exce ca o, a seq u encia executada e dada pelo tem (a). Observe que como n ao ocorre a exce ca o, isto e, a linha throw B; n ao e executada. Depois do bloco try, o programa executa a linha que segue o u ltimo bloco catch, ou seja, restante do c odigo.
26.5.2
No caso em que ocorre uma exce ca o a seq uencia de execu ca o e modicada, veja o tem (b) da Figura 26.2. Observe que como ocorre a exce ca o do tipo B, isto e, a linha throw B; e executada. O bloco try e encerrado na linha em que ocorre o throw, a seguir e executado o bloco catch (B) e depois a seq uencia continua em restante do c odigo.
26.6
Quando uma exce ca o e lan cada, os objetos locais criados dentro do bloco try e os objetos din amicos alocados com auto_ptr1 s ao destru dos. A seguir, o pr oximo catch que trata a exce ca o lan cada e executado. Se este catch n ao existe no escopo do try que lan cou a exce ca o, todas as demais chamadas de m etodos que est ao penduradas na pilha e que foram inclu das neste bloco try s ao desempilhadas (desconsideradas). Releia o par agrafo anterior e veja que faz sentido, pois se houve problemas no bloco try, suas subrotinas devem ser descartadas. Veja no exemplo da listagem 26.4 que a classe Teste tem tr es m etodos: M1(), M2(), M3(). Observe que M1() chama M2() e que M2() chama M3().
1 Veremos
480
Figura 26.2: Seq u encia de execu ca o sem exce ca o (a) e com exce ca o (b).
(a) Seqncia de execuo sem exceo. (b) Seqncia de execuo com exceo.
exceo = false; int main() { try { ..diversos.. if(exceo) trow B; ... } catch(A) {...} catch (B) {...} catch (C) {...} restante do cdigo... ... }
exceo = true; int main() { try { ..diversos.. if(exceo) trow B; ... } catch(A) {...} catch (B) {...........} catch (C) {...} restante do cdigo... ... }
481
Observe que dentro de main(), n ao existe uma linha throw, a linha com throw ca dentro de M3(). Veja na sa da a execu ca o com e sem exce ca o. Observe que quando o usu ario selecionou a op ca o 0, sem exce ca o, a seq u encia executada e a normal. Quando o usu ario seleciona a op ca o 1, a exce ca o e lan cada dentro de M3(), n ao retornando para M3(), M2() e M1() (n ao escreve Fim M3, Fim M2, Fim M1). Ou seja, os retornos dos m etodos M3(), M2() e M1() s ao retirados da pilha e desconsiderados. Listing 26.4: Exce co es e desempilhamento.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 # include < iostream > # include < stdexcept > # include < string > using namespace std ; class Teste { public : void M3 ( int resp ) { cout << " In cio M3 . " << endl ; if ( resp == 1) throw ( string ( " M e todo 3 " ) ) ; cout << " Fim M3 . " << endl ; } void M2 ( int resp ) { cout << " In cio M2 . " << endl ; M3 ( resp ) ; cout << " Fim M2 . " << endl ; } void M1 ( int resp ) { cout << " In cio M1 . " << endl ; M2 ( resp ) ; cout << " Fim M1 . " << endl ; } }; int main () { int resp ; cout << " \ nDeseja executar sem exce ca ~ o (0) ou com exce ca ~ o (1) : " ; cin >> resp ; cin . get () ; Teste obj ; try { obj . M1 ( resp ) ; } catch ( string s ) { cout << " \ nOcorreu Exce ca ~ o no M e todo : " << s << endl ; } return 0; } [ b u e n o @ l d s c 0 5 ] $ ./ a . out Deseja executar sem exce ca ~ o (0) ou com exce ca ~ o (1) :0 In cio M1 .
482
In cio M2 . In cio M3 . Fim M3 . Fim M2 . Fim M1 .
[ b u e n o @ l d s c 0 5 ] $ ./ a . out Deseja executar sem exce ca ~ o (0) ou com exce ca ~ o (1) :1 In cio M1 . In cio M2 . In cio M3 . Ocorreu Exce ca ~ o no M e todo : M e todo 3
26.7
As exce co es n ao tratadas terminam a execu ca o do programa. Quando uma exce ca o e lan cada e n ao capturada, as seguintes fun co es s ao executadas: unexpected(), que chama terminate(), que chama abort(), que naliza o programa. Voc e pode criar suas pr oprias fun co es unexpected() e terminate(), e substituir as default com as fun co es set_terminate() e set_unexpected(). Veja o exemplo a seguir. Exemplo: // Cria uma fun c~ ao sem retorno e sem par^ ametro void minhaFuncaoTerminate() { std::cerr < < "Programa encerrado, a exce c~ ao n~ ao foi capturada\n"; }; // Define como terminate set_terminate(minhaFuncaoTerminate); Veja exemplo na listagem 26.5. Observe que a fun ca o Teste(), lan ca uma exce ca o n ao declarada. Comprovando que o controle das exce co es lan cadas e feito em tempo de execu ca o e n ao de compila ca o. Listing 26.5: Usando set_unexpected() e set_terminate().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # include < iostream > # include < exception > # include < stdexcept > using namespace std ; // Fun c~ a o de teste da lista de e x c e c~ oes void Teste () throw ( string ) { throw 5; // N~ ao inclu d a na l i s t a g e m de throw , vai chamar u n e x p e c t e d } void M i n h a F u n c a o U n e x p e c t e d () { cerr << " Minha fun ca ~ o unexpected foi chamada porque Teste () \ n " << " lan c a uma exce ca ~ o n~ a o inclu da em sua lista .\ n " ; } void M i n h a F u n c a o T e r m i n a t e () { cerr << " Minha fun ca ~ o terminate foi executada .\ n " ; }
483
int main () { cout << " Este programa compila , mas ocorre um erro na execu ca ~ o .\ n " << endl ; // Posso d e f i n i r a fun c~ a o u n e x p e c t e d a ser e x e c u t a d a . u n e x p e c t e d _ h a n d l e r old = s e t _ u n e x p e c t e d ( M i n h a F u n c a o U n e x p e c t e d ) ; // Posso d e f i n i r a fun c~ a o t e r m i n a t e a ser e x e c u t a d a set_terminate ( MinhaFuncaoTerminate ); try { // Inicia bloco try
Teste () ; } catch ( string ) { cerr << " Exce ca ~ o para string ocorreu . " ; } cout << " fim do programa " ; return 0; } Este programa compila , mas ocorre um erro na execu ca ~o . Minha fun ca ~ o unexpected foi chamada porque Teste () lan c a uma exce ca ~ o n~ a o inclu da em sua lista . Minha fun ca ~ o terminate foi executada . Abortado
26.8
26.8.1
O operador new foi apresentado na se ca o 15.3.1 e a sobrecarga de new na se ca o 21.8. De uma maneira geral new tenta alocar a mem oria solicitada; Nas vers oes antigas de C++, quando new falhava retornava o ponteiro 0 (NULL) . Nos novos compiladores (Ansi C++), quando new falha, em vez de retornar 0, lan ca uma exce ca o do tipo bad_alloc (throw(bad_alloc)). Se o programa n ao tiver tratamento para exce ca o lan cada, o mesmo e encerrado (veja se ca o 26.7). Veja na listagem 26.6 um exemplo. O programa dene uma estrutura s. A seguir, dentro de main(), cria um vetor. No bloco do for innito, aloca uma estrutura dinamicamente e acrescenta-a ao vetor. Quando a mem oria de seu computador terminar, ocorre uma exce ca o do tipo bad_alloc, e o bloco catch (bad_alloc) e executado. Note que a sa da depende da quantidade de mem oria de seu computador. Listing 26.6: Exce ca o para new.
1 2 3 4 5 6 7 # include < iostream > # include < new > # include < vector > # include < stdexcept > using namespace std ; // Define uma e s t r u t u r a
484
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 struct S { int indicador [50000]; double valor [50000]; }; int main () { vector < S > v ; try {
long int i = 0; for (;;) // Um for i n f i n i t o { S * ptr_s = new S () ; // Aloca m e m oria v . push_back (* ptr_s ) ; // A d i c i o n a no vetor cout << " \ nv [ " << i << " ] alocada " << endl ; i ++; } } catch ( bad_alloc erro ) // T r a t a m e n t o de erro { cout << " \ nExce ca ~ o " << erro . what () << endl ; } } ... v [8190] alocada v [8191] alocada Exce ca ~o St9bad_alloc
Se quiser desativar a chamada da exce ca o para new, use a palavra-chave nothrow. Exemplo: S* ptrS = new (nothrow) S(); Voc e pode criar uma fun ca o f() para tratar a aloca ca o com new, esta deve receber e retornar um void e pode ser ativada com set_new_handler(f). Como voc e redeniu o tratamento para new, a exce ca o para new deixa de ser lan cada e sua fun ca o f() e executada.
26.8.2
No exemplo da listagem 26.7, usamos exce co es para controle da entrada e sa da de dados. Observe que ativamos as exce co es para erros com cin e cout. Isto e, se ocorrer um erro de entrada/sa da, uma exce ca o ser a lan cada e tratada. Observe na sa da que as palavras aparecem ordenadas. Nota: o uso de map ser a descrito no Cap tulo 34 - Os Containers Associativos <set>, <multiset>, <map> e <multimap>. Um map armazena uma chave e um valor. Neste exemplo usamos a palavra como um ndice que e utilizado para acessar o map e a seguir incrementar o contador associado a palavra. Listing 26.7: Usando exce co es para controle de entrada e sa da.
1 2 3 // C o n t r o l e de e n t r a d a e saida ( p r o b l e m a s de I / O ) // A d a p t a d o de C ++ in a n u t s h e l l # include < algorithm >
485
void Saida ( const std :: pair < std :: string , std :: size_t >& p ) { std :: cout << p . first << \ t << p . second << \ n ; } int main () { using namespace std ; try { string palavra ; map < string , size_t > contador ; cin . exceptions ( ios_base :: badbit ) ; cout . exceptions ( ios_base :: badbit ) ; while ( cin >> palavra ) ++ contador [ palavra ]; ~ d a === " << endl ; cout << " ==== S a A for_each ( contador . begin () , contador . end () , Saida ) ; } catch ( ios_base :: failure & ex ) { std :: cerr << " Erro de E / S : " << ex . what () << \ n ; return 1; } catch ( exception & ex ) { std :: cerr << " Erro fatal : " << ex . what () << \ n ; return 2; } catch (...) { A o diferente de failure e exception : Disastre toral .\ n " std :: cerr << " E x c e ~ A ~ ; return 3; } return 0; } O uso de exce co ~ es e de controle de entrada e sa da facilita o d e s e n v o l v i m e n t o de softwares amig a veis e a prova de erro . O 1 a 1 amig a veis 1 controle 1 de 5 desenvolvimento 1 e 3 entrada 1 erro . 1 exce co ~ es 1 facilita 1
486
o 1 prova 1 sa da 1 softwares uso 1
26.8.3
preciso adotar uma pol E tica clara para uso de tratamento de exce co es e esta pol tica deve ser respeitada pela equipe de desenvolvimento. Veja a seguir dicas de [Sutter, 2006], para uma pol tica de exce co es: Determine uma pol tica global de tratamento de erro para sua aplica ca o ou subsistema e a mantenha. Informe o tipo de erro. Dena como vai ser a propaga ca o dos erros. Dena como ser a o tratamento do erro (API). Escreva throw nos lugares que detectar um erro e n ao puder lidar com ele. Escreva try ou catch nos lugares que tem conhecimento suciente para tratar o erro. Finalmente e bom lembrar que todo sistema de controle de erro deve ser amplamente documentado. O que inclui tens como o que? porque? como? quando?
26.9
Somente utilize exce ca o para casos cr ticos; evite sua utiliza ca o como mais um mecanismo de programa ca o. Uma exce ca o n ao resolve os destinos do seu programa; esta tarefa ainda e sua. Os m etodos para tratamento de exce co es e aqueles de tomada de decis ao devem ser separados do c odigo num erico. Observe que em um sistema tradicional de tratamento de erros, as instru co es de tratamento de erro cam misturadas no c odigo. Com o uso de try, throw e catch, voc e separa aa rea do c odigo da area de tratamento de erros. Depois de um bloco try ou catch n ao coloque o ; (ponto-e-v rgula). A seq u encia dos catchs deve respeitar a hierarquia das classes. Preste aten ca o no exemplo a seguir, o catch da classe-derivada deve vir antes do da classe-base. Exemplo: // Errado catch(Base b) {...} catch(Derivada1 d1) catch(Derivada2 d2) // Correto catch(Derivada2 d2) catch(Derivada1 d1) catch(Base b) {...}
487
Uma fun ca o/m etodo declarada com throw e uma fun ca o/m etodo que n ao lan ca exce co es. Se um bloco de c odigo pode estar gerando uma exce ca o, coloque-o dentro de um bloco try. Dentro de um m etodo, voc e pode declarar objetos locais, que ser ao eliminados quando do encerramento do m etodo. Mas se dentro do m etodo for lan cada uma exce ca o com throw, o m etodo n ao termina e os objetos locais n ao ser ao eliminados. Para resolver este problema, deve-se ativar a op ca o RTTI do compilador, que assegura que os objetos locais tenham seus destrutores chamados. Mesmo ativando a op ca o RTTI, somente os objetos locais que n ao s ao din amicos s ao destru dos. Objetos din amicos devem ser destru dos antes do lan camento da exce ca o, pelo programador, ou devem ser criados usando auto_ptr<> veja se ca o F.5. Voc e pode lan car uma exce ca o dentro de um construtor; se esta ocorrer, os demais objetos n ao s ao criados, deixando de ser destru dos. Se throw lan ca um const, catch deve capturar um const. Pode-se construir sequ enciar try...catch,...,try...catch.. Se voc e dispara com um throw um ponteiro ou refer encia de um objeto do tipo A, esta deve ser capturada por um catch que recebe um ponteiro ou refer encia do tipo A. Por isso, voc e conclui que um catch (void*) captura todos os lan camentos de ponteiros e deve ser o u ltimo deste tipo. Um bloco try praticamente n ao apresenta custo computacional, mas o lan camento de uma exce ca o com throw tem um custo de performance elevado, [Lischner, 2003]. Segundo [Meyers, 2005], um m etodo/fun ca o seguro deve garantir: Se ocorrer uma exce ca o todo o restante do programa continua num estado v alido (n ao ocorreram corrup co es de dados). Uma garantia forte promete que se uma exce ca o e lan cada, o estado do programa n ao e alterado. Ou seja, a chamada a fun ca o/m etodo e um processo at omico, no sentido de que se ocorrer sucesso, o mesmo e completo, e se ocorrer um fracasso, o programa n ao e alterado (como se a fun ca o nunca tivesse sido chamada). Um construtor pode incluir um bloco try, veja no exemplo a seguir o prot otipo: Exemplo: CNomeClasse(par^ ametros) try : atributo1(valor1),atributo2(valor2),... { ...c odigo do construtor... } catch () {... } A diferen ca entre as fun co es exit() e abort(), e que abort() emite uma mensagem de erro. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
Embora um m etodo possa informar quais ser ao as exce co es que podem ser lan cadas em tempo de execu ca o, isto deve ser evitado. O motivo e simples, esta verica ca o n ao e feita em tempo de compila ca o mas em tempo de execu ca o. Ent ao, para ter mais robustes no seu c odigo, evite o uso da declara ca o da exce ca o que pode ser lan cada. Para maiores detalhes, consulte [Sutter, 2006]. Evite usar new (nothrow). Segundo [Sutter, 2006], em sistemas operacionais modernos, que utilizam mem oria virtual, a verica ca o da aloca ca o ap os o uso de new tem pouco sentido pr atico, pois, geralmente, o sistema tem mem oria. Ou ir a travar, antes de new retornar um bad_alloc, em fun ca o do excesso de pagina ca o. [Sutter, 2006] parte do princ pio de que as falhas na aloca ca o com new s ao raras. De um modo geral o problema esta em denir o que ser a feito se o sistema n ao tem mais mem oria. Note que a arma ca o acima n ao tem sentido quando falamos de programa ca o cient ca. 3 N ao e poss vel criar um ponteiro para uma fun ca o que tenha a informa ca o do tipo de exce ca o a ser lan cada usando-se typedef. Mas e poss vel criar o ponteiro diretamente, sem o typedef. Veja o exemplo. Exemplo: typedef void (*pf)()throw(C1,C2,..); // Erro void (*pf)()throw(C1,C2,..); // ok pf = f; // ok Veja na se ca o ?? a utiliza ca o da instru ca o assert.
26.10
A quest ao do tratamento de exce co es esta diretamente associada ao controle da execu ca o do programa. O que fazer quando o usu ario entra com um dado errado? o que fazer se a mem oria do sistema acabou? o que fazer se um dispositivo, como o disco r gido come ca a apresentar problemas? Vimos que o controle das exce co es pode ser feito no meio do c odigo, m etodo antigo, ou utilizando o conceito de exce co es, m etodo novo. A vantagem do uso de exce co es e que o tratamento das condi co es de erro e separado do processamento normal, al em disso, a biblioteca padr ao j a fornece um conjunto de classes para os tratamentos mais comuns de erros. Iniciamos o cap tulo com uma introdu ca o ` as exce co es. Vimos os conceitos b asicos de exce co es , o uso de try, throw e catch. A seq uencia de execu ca o do programa, com e sem exce co es. Como ca a pilha (heap ). O que ocorre com exce co es n ao tratadas, exce ca o para new e uma lista com as exce co es-padr ao. Dica: releia os exemplos apresentados com aten ca o, e veja que o uso de exce co es e simples.
26.11
Exerc cios
1. Qual a vantagem do uso de exce co es? Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
26.11. EXERC ICIOS 2. No seu cotidiano, qual tipo de programa pode se beneciar do uso de exce co es? 3. Acrescentar a listagem 26.1 ocorr encias de outros tipos de erros. 4. Reveja o exemplo da listagem 22.7. 5. Modique a listagem 26.3, acrescentando novos tipos de lan camentos com throw. 6. Na listagem 26.4 coloque um coment ario no bloco catch e veja o que acontece. 7. Acrescentar no exerc cio anterior uma fun ca o terminate() (veja se ca o 26.7). 8. Monte exerc cio que use set_new_handler(f). 9. Modique as listagens da se ca o 19.6, acrescentando o uso de exce co es.
489
10. Modique a listagem 26.6, substituindo S *ptr_s = new S(); por S* ptr_s = new (nothrow) S();. 11. Na listagem 26.5, modique as fun co es MinhaFuncaoUnexpected() e MinhaFuncaoTerminate(). 12. Modique a listagem 26.6, retire a linha try() e veja o que acontece. 13. No exerc cio anterior, acrescente uma fun ca o f() para tratar a aloca ca o com new usando set_new_handler(f).
490
Cap tulo 27
Templates ou Gabaritos
Os conceitos mais u teis e extraordin arios de C++ s ao os de classes, de polimorsmo e de templates. Veremos neste cap tulo o conceito e uso de templates. Veremos uma introdu ca o aos templates (gabaritos) (se ca o 27.1), e a seguir: Fun co es templates (se ca o 27.2): o prot otipo para fun co es templates (se ca o 27.2.1), a instancia ca o e dedu ca o de argumentos (se ca o 27.2.2), a declara ca o expl cita de fun ca o template (se ca o 27.2.3), como resolver problemas de convers oes (se ca o 27.2.4), como implementar a sobrecarga de fun ca o template (se ca o 27.2.5), como criar objetos est aticos dentro de uma fun ca o template (se ca o 27.2.6). Classes templates ou tipos param etricos (se ca o 27.3): o prot otipo para classes templates (se ca o 27.3.1), regras gerais para classes templates (se ca o 27.3.2), e o uso de argumentos pr e-denidos em classes templates (se ca o 27.3.3). No nal do cap tulo veremos algumas senten cas para templates (se ca o 27.4) e alguns exerc cios. No pr oximo cap tulo veremos: Uso avan cado de fun co es template (se ca o 28.1): especializa ca o de fun co es template (se ca o 28.1.1), o que s ao fun co es expandidas em tempo de compila ca o (se ca o 28.1.2), como mapear fun co es template utilizando especializa co es (se ca o 28.1.4), uso de typename com templates (se ca o 28.1.3). Uso avan cado de classes template (se ca o 28.2): templates dentro de classes template (se ca o 28.2.1), como especializar classes (se ca o 28.2.2). Nota: veremos neste cap tulo que a constru ca o de fun co es e classes templates podem incluir par ametros a serem denidos em tempo de compila ca o. Como as fun co es e m etodos tamb em tem seus pr oprios par ametros, a palavra par ametro teria dois usos semelhantes conceitualmente mas diferentes do ponto de vista da implementa ca o. Para facilitar o entendimento e a diferencia ca o dos par ametros de templates dos par ametros de uma fun ca o/m etodo, vamos utilizar a seguinte nomenclatura: Par ametro Refere-se aos par ametros de um m etodo/fun ca o, passados dentro de (). Argumento Refere-se ao argumento de um template, denido em tempo de compila ca o, passado dentro de <>. 491
492
27.1
No Cap tulo 14 - Sobrecarga de M etodos, vericamos que a sobrecarga permite criar m etodos com mesmo nome para manipular diferentes tipos de argumentos: Exemplo: float f(float x) int f(int x) double f(double x)
Observe como as fun co es s ao semelhantes; a u nica diferen ca s ao os tipos dos par ametros e do retorno que est ao sendo tratados. No exemplo, o programador cria a fun ca o f() para float, depois para int e double. O ideal seria escrever uma fun ca o gen erica da forma: Tipo f(Tipo x) { return ( x*x ); }
Fun co es template de C++ funcionam exatamente assim. Uma fun ca o template e uma fun ca o denida para um (ou mais) tipo(s) gen erico(s) em tempo de compila ca o. No exemplo anterior, se a fun ca o f() for chamada tendo como par ametro um int, o compilador cria uma fun ca o f() para int; se o par ametro for double, o compilador cria uma fun ca o f() para double, e assim por diante. Ou seja, o compilador ir a gerar uma c opia da fun ca o f() para cada tipo para a qual ela venha a ser chamada. As fun co es template (ou gabaritos de C++) possibilitam a constru ca o de algor tmos com c odigo independente do tipo de dado a ser manipulado (Ornellas et all. (2002)). Segundo o mesmo autor, O principio de trabalho dos gabaritos e fornecer um modelo de algor tmo que e automaticamente replicado pelo compilador, em tempo de compila ca o, de forma a gerar todas as inst ancias da fun ca o necess arias para atender todas as chamadas realizadas. Assim, podemos denir que um template e um gabarito para cria ca o - em tempo de compila ca o - de classes e fun co es como inst ancias do template. A programa ca o usando o conceito de templates e conhecida como programa ca o gen erica ou metaprograma ca o, [Lischner, 2003].
27.2
27.2.1
Veja a seguir o prot otipo para fun co es templates. Observe na linha anterior ` a declara ca o do nome da fun ca o, que colocamos a palavra-chave template, seguida de <, a palavra-chave typename, os tipos gen ericos (Tipo1, Tipo2,..,Tipon) e >. Estes elementos criam os tipos gen ericos Tipo1, Tipo2,..., Tipon, que ser ao utilizados dentro do bloco da fun ca o template. Prot otipo: template<typename Tipo1,...,typename Tipon> Tipoi NomeFun ca o(Tipoi nome,...,Tipon nomen) {....// Deni ca o da fun ca o template return Tipoi; } Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
493
A fun ca o template do exemplo a seguir recebe um objeto do tipo T e retorna o resultado da multiplica ca o de x por x, que tamb em e um objeto do tipo T. Exemplo: template <typename T> T f(T x) { return ( x*x ); } Tudo bem, voc e ainda n ao entendeu como funciona o template. Bem, template pode ser traduzido para o portugu es como gabarito. traduzido como gabarito, mas funciona como um gabarito? Exatamente. E E como C++ implementa esses gabaritos? simples, E e como um copiar/colar inteligente. Ao encontrar a declara ca o de uma func a o template, o compilador verica se a declara ca o est a correta. Se esta estiver correta, o compilador armazena a declara ca o em um buer (na mem oria). Quando voc e chama a fun ca o declarada com o template, passando como par ametro um int, o compilador reescreve toda a fun ca o, substituindo o tipo gen erico T pelo tipo real int. O compilador faz substituir (T) por (int). Essa busca e substitui ca o e repetida para cada tipo. Veja no exemplo a seguir que o template da fun ca o T f(T x) { return x * x; } para o tipo int ap os o search(T) replace(int) resulta em int f(int obj) { return x * x; }. Exemplo: int f(int x) { return ( x*x ); }
Da mesma forma, ap os o search(T) replace(float) ca da forma Exemplo: float f(float x){ return ( x*x ); } Dica: como um template espera a deni ca o do tipo dentro de <>, e podemos ter um template recebendo outro, voc e deve incluir um espa co antes de >. Evita-se tamb em a ambiguidade com o operador > >. Veja o exemplo: Exemplo: complex< double > c; vector< complex<float> > v;
27.2.2
Denimos anteriormente que um objeto e uma inst ancia de uma classe. A classe e a planta para cria ca o de um ou mais objetos. Da mesma forma, um template de uma fun ca o e uma planta para implementa ca o de uma ou mais fun co es, ou seja, o template da fun ca o n ao e a fun ca o em s , apenas um prot otipo. Isto signica que para que o c odigo da fun ca o seja efetivamente escrito, a fun ca o template precisa ser instanciada. Um template da forma Exemplo: template< typename T > T f(T x) { return ( x*x ); } para ser instanciado precisa receber em tempo de compila c ao o argumento T, e o par ametro x. Ou seja Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
note que passamos dentro de <> o argumento do template (o tipo T) e dentro de () o par ametro da fun ca o f(). No exemplo acima o compilador vai criar uma vers ao da fun ca o f() da seguinte forma: Exemplo: int f(int x) { return ( x*x ); }
note que o uso de f<int>(x);, embora seja simples e claro, inclui a necessidade de se passar o argumento <int>. Para reduzir a necessidade de digita ca o os compiladores de C++ podem, em alguns casos, deduzir automaticamento o tipo a ser passado para o template. No exemplo a seguir o tipo <int> e deduzido automaticamente. Exemplo: int x = 4; int resultado = f(x); Note que em alguns casos o template precisa receber v arios argumentos, e nem todos poder ao ser automaticamente identicados. Nestes casos os argumentos mais a esquerda precisam ser passados. Funciona de forma semelhante ao que ocorre com fun co es/m etodos com par ametros pr e-denidos (se ca o 13.6.4). Exemplo: template< typename T1, typename T2> T1 f(T1 x, T2 y) { std::cout < < x < < " " < < y < < std::endl; } .. char c = C; f(5, c); // Argumentos <int,char> identificados automaticamente Poder amos chamar f() da seguinte forma Exemplo: char c = C; f<int>(5, c); note que o argumento <int> e passado explicitamente e o argumento char e deduzido automaticamente pelo compilador. Quando a deni ca o da fun ca o gabarito apresentar v arios par ametros abstratos e houver necessidade de instanci a-los explicitamente, n ao e preciso especicar todos os tipos de dados na chamada, mas somente aqueles que puderem apresentar problemas (Ornellas et al. 2002).
27.2.3
Vimos que a fun ca o template s o ser a implementada para inteiros quando o compilador encontrar uma chamada da fun ca o que utilize inteiros. Se voc e deseja que uma fun ca o template tenha obrigatoriamente uma vers ao para inteiros, basta declarar explicitamente a fun ca o para inteiros. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
27.2. FUNC OES TEMPLATES Exemplo: int f(int); // Declara c~ ao explicita da fun c~ ao f() para int
495
Observe que voc e est a apenas declarando a fun ca o; sua deni ca o ser a dada automaticamente pelo compilador, tendo como base a deni ca o da fun ca o template. No exemplo a seguir, criamos um operador < < utilizando um tipo gen erico T. A seguir, instanciamos o operator< < para o tipo efetivo int, depois para float e depois para char. Observe nesse exemplo que o segundo argumento const int size n ao muda. Exemplo: // Defini c~ ao da fun c~ ao template template < typename T > void operator< <(const T * vetor, const int size) { for ( int i = 0; i < size; i++ ) cout < < vetor[i] < < endl; } // Declara c~ ao expl cita da fun c~ ao operator< <() para int, float e char* void operator< <(const int* vetor, const int size); void operator< <(const float*vetor, const int size); void operator< <(const char** vetor, const int size);
27.2.4
Quando uma chamada a uma fun ca o template n ao puder ser resolvida pelas convers oes padr oes (ou do usu ario), voc e precisa informar explicitamente a vers ao a ser utilizada. Veja o exemplo. Exemplo: int Minimo(int x, int y) { return x < y ? x:y; } // (1)
// (2) unsigned int Minimo(unsigned int x, unsigned int y) { return x < y ? x : y; } unsigned int x = 18; unsigned int minimo = Minimo(x,19); // Ambiguidade, usar (1) ou (2)? O n umero 19 e convertido para int. Como existem duas vers oes para Minimo(), uma para int (1) e outra para unsigned int (2), o compilador ca confuso e n ao sabe qual fun ca o Minimo() chamar, causando uma ambig uidade. Voc e pode resolver este problema especicando diretamente, dentro de <> a vers ao a ser utilizada, veja exemplo abaixo. Exemplo: unsigned int minimo = Minimo< unsigned int >(x,19); // (2)
27.2.5
Se voc e deseja que uma fun ca o tenha o mesmo nome de uma fun ca o denida como template, mas que receba um n umero de par ametros diferente, n ao h a problema, visto que voc e est a sobrecarregando a fun ca o template. Observe, entretanto, que o n umero de par ametros de entrada deve ser diferente, sen ao o compilador vai acusar ambig uidade. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
496
27.3. CLASSES TEMPLATES OU TIPOS PARAMETRICOS Exemplo: template< typename T > T f(T a, T b) // (1) { return a + b; } template< typename T > T f(T a, T b, T c) // (2) Sobrecarga { return a + b + c; }
Note que as fun co es (1) e (2) s ao fun co es com mesmo nome, mas n umero de par ametros diferentes. Veja a seguir exemplo de uso das fun co es (1) e (2). Exemplo: int xi = 3, yi = 4, zi = 5; f(xi,yi); // Cria uma c opia da fun c~ ao float xf = 3.1, yf = 4.2, zf = 5.3; f(xf,yf); // Cria uma c opia da fun c~ ao f(xi,yi,zi); // Cria uma c opia da fun c~ ao f(xf,yf,zf); // Cria uma c opia da fun c~ ao
(1) para o tipo int (1) para o tipo float (2) para o tipo int (2) para o tipo float
27.2.6
Dentro de uma fun ca o template, voc e pode denir um objeto est atico do tipo T. Ao criar uma fun ca o para inteiros, cria um int est atico. Ao criar uma fun ca o para float, cria um float est atico. Esses objetos n ao se interferem, pois est ao em fun co es distintas. Exemplo: template< typename T > T f(T a, T b) { static T c = 0.0; // Vari avel T est atica, com valor pr e-definido ...resto da fun c~ ao... } Nota: veremos na se ca o 28.1 o uso avan cado de fun co es template.
27.3
A id eia de funcionamento de classes templates e semelhante ao de fun co es template, mas neste caso, v arios atributos e m etodos ser ao denidos a partir dos tipos gen ericos. Ou seja, uma classe template implementa o conceito de uma classe gen erica. Uma classe que pode ser constru da para mais de um tipo, mas que tem a mesma forma (estrutura, gabarito). Uma classe template tamb em pode ser chamada de classe parametrizada ou classe gabarito. Veja a seguir o prot otipo para declarar e denir uma classe template.
27.3.1
Veja a seguir o prot otipo para classes templates. Observe que na deni ca o dos m etodos da classe template e preciso especicar novamente cada tipo gen erico. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
27.3. CLASSES TEMPLATES OU TIPOS PARAMETRICOS Prot otipo: // Declara ca o da classe template template < typename Tipo1, typename Tipo2,.... > class TCNome { public: // Declara atributos Tipo1 atributo1; Tipo2 atributo2; // Declara e dene o construtor default TCNome(){....}; // Declara m etodos Tipo1 NomeM etodo(Tipo1 & obj,...); Tipo2 NomeM etodo(Tipo2 & obj,...); }; // Deni ca o dos m etodos da classe template template < typename Tipo1, typename Tipo2,.... > Tipo1 TCNome::NomeM etodo(Tipo1 & obj,...) {...} template < typename Tipo1, typename Tipo2,.... > Tipo2 TCNome::NomeM etodo(Tipo2 & obj,...) {...} // Utiliza ca o da classe template TCNome< Tipo1, Tipo2,.... > nomeObjeto;
497
27.3.2
Uma das id eias b asicas do uso de templates e que o tipo gen erico T, passa a se comportar, sob certos aspectos, como sendo um argumento do template. Funcionando de forma semelhante ao par ametro de um m etodo. Isto signica que o resultado da execu ca o do programa vai depender al em das vari aveis/atributos denidos pelo usu ario, do tipo T das classes criadas e utilizadas como argumentos dos templates. Se novos tipos T forem denidos, isto e, novas classes do usu ario, os mesmos poder ao ser utilizados para instancia ca o de novas classes templates. Neste caso o programa precisa ser recompilado, e as novas classes devem ser efetivamente instanciadas. Para construir o template, para um u nico tipo gen erico T, devemos iniciar a deni ca o da classe template usando a seguinte linha. Exemplo: template <typename T> class TCNome { ..uso de T... }; Para criar um objeto da classe TCNome, devemos passar o tipo T a ser utilizado. Ou seja, T funciona como um argumento. Exemplo: TCNome<int> obj; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
498
Se o tipo gen erico n ao for passado dentro de <>, o compilador acusa o erro Exemplo: TCNome obj; // Erro ...class template require template argument list. TCNome<> obj; // Erro ...wrong number of template arguments. Dentro da classe TCNome podemos criar criar atributos e m etodos que usam o tipo gen erico T. Exemplo: template <typename T> class TCNome { // M etodos T& Atributo1() { return atributo1; } const T& Atributo1() const { return atributo1; } // Atributos T atributo1; T atributo2; }; Para construir o template, para mais de um tipo gen erico T, devemos iniciar a deni ca o da classe template usando a seguinte linha. Exemplo: template <typename T1, typename T2, typename T3,..., typename Tn> class TCNome { ..uso de T1, T2, T3, ...Tn... }; Sempre que refer enciarmos, dentro da classe TCNome, um objeto do tipo TCNome, devemos usar TCNome<T>. Observe a forma como declaramos o operador de atribui ca o. Exemplo: template <typename T> class TCNome { public: T atributo1 , atributo2; // Construtor TCNome():atributo1(0), atributo2(0){} void IgualaAtributos() { atributo1 = atributo2; }; // Operador de atribui c~ ao TCNome<T>& operator=(const TCNome<T>& src); }; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
499
No m etodo IgualaAtributos(), igualamos os atributos T atributo1 e T atributo2 (atributo1 = atributo2;). Mas o que acontece se o tipo a ser efetivamente utilizado n ao tiver o operador de igualdade? Neste caso, quando IgualaAtributos() for instanciada, o compilador ir a acusar o erro. Exemplo: TCNome<int> objInt; objInt.IgualaAtributos(); // ok, int tem sobrecarga para = TCNome<TEndereco> objEndereco; objEndereco.IgualaAtributos(); // Erro, TEndere co n~ ao tem o operador = Quando compilamos o arquivo de implementa ca o da classe (*.cpp), todos os atributos e m etodos s ao inclu dos no arquivo objeto (*.o). Entretanto, quando linkamos v arios arquivos para gerar um programa execut avel, somente os trechos de c odigo efetivamente utilizados s ao inclu dos no execut avel nal. Isto signica que se n ao chamarmos objEndereco.IgualaAtributos();, ent ao o c odigo abaixo ir a funcionar. Exemplo: TCNome<int> objInt; objInt.IgualaAtributos(); // ok, int tem sobrecarga para = TCNome<TEndereco> objEndereco; // ok, n~ ao vamos usar IgualaAtributos Alguns compiladores exigem que todo c odigo de uma classe template seja denido na classe .h. Exemplo // Arquivo TCNome.h // Inclui defini c~ ao da classe e dos m etodos da classe. Para estes compiladores, pode-se usar o truque abaixo. Note que o arquivo TCNome.cpp e inclu do dentro do arquivo TCNome.h, Exemplo: // Arquivo TCNome.h, defini c~ ao da classe #ifndef TCNome_h #define TCNome_h template <typename T> class TCNome { public: void M(); }; #include "TCNome.cpp" #endif O arquivo TCNome.cpp, inclui a deni ca o dos m etodos da classe: template <typename T> void TCNome<T>::M() Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
500 {
std::cout < < "Usando m etodo M()." < < std::endl; } No Cap tulo 30 - As Classes <complex>, <bitset> e as Fun co es Matem aticas de <cmath>, descreveremos a classe template <complex>. Um objeto da classe <complex> representa um n umero complexo que pode ser constru do para n umeros float, double e long double, ou seja, se voc e quiser um n umero complexo com precis ao de float, utilize complex<float>, e se quiser um n umero complexo com precis ao de double, utilize complex<double>.
27.3.3
Uma classe template tamb em pode ser denida com argumentos pr e-denidos, de forma semelhante a fun co es com par ametros pr e-denidos (veja se ca o 13.6.4). Veja no prot otipo a seguir que se o Tipo2 n ao for passado, vai assumir Tipo2 = Tipo1. Prot otipo: template <typename Tipo1, typename Tipo2 = Tipo1> class TCNome {... }; Neste prot otipo, a classe TCNome pode ser constru da passando-se os dois tipos (Tipo1 e Tipo2), como no exemplo abaixo: TCNome<int, double> obj1; Ou passando-se apenas o tipo mais a esquerda (Tipo1), como em: TCNome<int> obj2; O exemplo da listagem 27.1 mostra a deni ca o de uma classe template que tem argumentos pr e-denidos. Listing 27.1: Deni ca o de classe template com argumentos pr e-denidos .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /* * @ c o p y r i g h t ( C ) Andre Duarte Bueno , Vitor S e r a p h i m */ # include < iostream > using namespace std ; // Cria classe t e m p l a t e para p o l i n ^ omios. // Usa p a r ^ a m e t r o com valor pr e - definido , por padr~ a o size e 3 template < typename T , const int size = 3 > class TCPolinomi o { T p [ size ]; public : TCPolinom i o () ; // (1) TCPolinom i o ( const TCPolinomio <T , size > & src ) ; // (2) const int Size () { return size ;} // (3) const T & operator () ( T x ) const ; // (4) T& operator []( int i ) ; // (5) const T & operator []( int i ) const ; // (6) TCPolinomio <T , size >& operator =( const TCPolinomio <T , size > & src ) ; // (7) }; # include " C l a s s e T e m p l a t e C o m A r g u m e n t o s P r e - Definidos . cpp "
501
Observe na listagem 27.2 a forma de implementa ca o dos m etodos da classe template. Note que os argumentos do template devem ser utilizados tamb em na deni ca o dos m etodos da classe (devem ser passados para cada m etodo). Isto e necess ario, mesmo quando os argumentos do template n ao s ao tipos gen ericos (no exemplo, o segundo argumento tem tipo denido, const int). Observe ainda que utilizamos o conceito de argumento com valor pr e-denido, no caso, size = 3. Listing 27.2: Deni ca o dos m etodos da classe template com argumentos pr e-denidos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 /* * @ c o p y r i g h t ( C ) Andre Duarte Bueno , Vitor S e r a p h i m M o n t a d o tendo como base tipos f l u t u a n t e s */ // (1) C o n s t r u t o r d e f a u l t template < typename T , const int size > TCPolinomio <T , size >:: TCPolinomi o () { for ( int i =0; i < size ; i ++) p [ i ] = i ;}; // (2) C o n s t r u t o r de c o pia template < typename T , const int size > TCPolinomio <T , size >:: TCPolinomi o ( const TCPolinomio <T , size > & src ) { for ( int i =0; i < size ; i ++) p [ i ] = src . p [ i ];}; // (4) S o b r e c a r g a do o p e r a d o r () // o b s e r v e que pow recebe long double template < typename T , const int size > const T & TCPolinomio <T , size >:: operator () ( T x ) const { T * y = new T (0) ; for ( int i = 0 ; i < size ; i ++) (* y ) += p [ i ] * pow ( static_cast < long double > ( x ) , i ) ; return * y ; }; // (5) S o b r e c a r g a do o p e r a d o r [] template < typename T , const int size > T& TCPolinomio <T , size >:: operator []( int i ) { return p [ i ]; }; // (6) S o b r e c a r g a do o p e r a d o r [] template < typename T , const int size > const T & TCPolinomio <T , size >:: operator []( int i ) const { return p [ i ]; }; // (7) S o b r e c a r g a do o p e r a d o r = template < typename T , const int size > TCPolinomio <T , size >& TCPolinomio <T , size >:: operator =( const TCPolinomio <T , size > & src ) { for ( int i =0; i < size ; i ++) p [ i ] = src . p [ i ]; return * this ; }
Observe na listagem 27.3 a forma de uso dos m etodos da classe template. Listing 27.3: Usando a classe template com argumentos pr e-denidos.
1 2 3 4 5 6 # include < cmath > # include < iostream > using namespace std ; # include " C l a s s e T e m p l a t e C o m A r g u m e n t o s P r e - Definidos . h " // Usando a classe T C P o l i n o m i o
502
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
int main () { const int size = 3; int x = 5; cout << " x = " << x << endl ; cout << " Criando polin^ o mio TCPolinomio < int > pInt1 ; " << endl ; TCPolinomio < int > pInt1 ; // (1) cout << " C o e f i c i e n t e s de pInt1 = " ; for ( int i =0; i < size ; i ++) cout << pInt1 [ i ] << \ t ; // (5) cout << endl ; cout << " pInt1 ( x ) = " << pInt1 ( x ) << endl ; // (3) int r = pInt1 [0]; cout << " r = " << r << endl ; const int rc = pInt1 [0]; cout << " rc = " << rc << endl ; // (5) // (6)
cout << " Criando polin^ o mio TCPolinomio < int > pInt2 ; " << endl ; TCPolinomio < int , size > pInt2 ( pInt1 ) ; // (2) pInt2 [0] = 1; cout << " C o e f i c i e n t e s de pInt2 = " ; for ( int i =0; i < size ; i ++) cout << pInt2 [ i ] << \ t ; // (5) cout << endl ; cout << " pInt2 ( x ) = " << pInt2 ( x ) << endl ; // (3) cout << " \ nCriando polin^ o mio TCPolinomio < int , size > pInt3 ( pInt2 ) ; " " usa construto r copia " << endl ; TCPolinomio < int , size > pInt3 ( pInt2 ) ; // (2) cout << " C o e f i c i e n t e s de pInt3 = " ; for ( int i =0; i < size ; i ++) cout << pInt3 [ i ] << \ t ; // (5) cout << endl ; cout << " \ nIgualand o polin^ o mios pInt1 = pInt2 ; " << endl ; pInt1 = pInt2 ; // (7) cout << " C o e f i c i e n t e s de pInt1 = " ; for ( int i =0; i < size ; i ++) cout << pInt1 [ i ] << \ t ; // (5) cout << endl ; cout << " \ nCriando polin^ o mio TCPolinomio < float , size > pFloat1 ; " << endl ; TCPolinomio < float , size > pFloat1 ; // (1) cout << " C o e f i c i e n t e s de pFloat1 = " ; for ( int i =0; i < size ; i ++) cout << pFloat1 [ i ] << \ t ; // (5) cout << endl ; cout << " pFloat1 ( x ) = " << pFloat1 ( x ) << endl ; // (3) // cout << " I g u a l a n d o p o l i n ^ o m i o s de tipos d i f e r e n t e s " // pInt1 = p F l o a t 1 ; // (6) // Erro return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ a . out x = 5 Criando polin^ o mio TCPolinomio < int > pInt1 ; C o e f i c i e n t e s de pInt1 = 0 1 2 pInt1 ( x ) = 55 r = 0 rc = 0
503
Criando polin^ o mio TCPolinomio < float , size > pFloat1 ; C o e f i c i e n t e s de pFloat1 = 0 1 2 pFloat1 ( x ) = 55
Veja outros exemplos de classes template nas listagens 33.2 e 33.4. Nota: a STL usa o mecanismo de argumentos pr e-denidos extensivamente. Por exemplo, a classe <vector> espera como argumento o tipo de objeto a ser armazenado no vetor e o tipo de alocador de mem oria a ser utilizado. Normalmente passamos apenas o primeiro argumento, isto e, o tipo do objeto a ser armazenado no container <vector>.
27.4
N ao e aconselh avel a utiliza ca o de fun co es globais; isso tamb em e v alido para fun co es template globais. N ao crie classes com templates antes de ter total conan ca no c odigo, isto e, primeiro crie classes normais e fa ca todos os testes que forem necess arios. Lembre-se que uma fun ca o pode ter mais de uma declara ca o, mas somente uma deni ca o. O mesmo conceito e v alido para fun co es template. O conceito de friend tamb em pode ser utilizado com templates (se ca o 28.1.5). Observe que com a utiliza ca o de templates, voc e pode desenvolver programas gen ericos, com tipos gen ericos. Para diferenciar classes comuns de classes gabaritos, costuma-se colocar o nome das classes gabaritos dentro de <>, como em <complex>, <vector>. A alguns anos us avamos template<class T>, como a palavra-chave class j a e utilizada para declarar uma classe, prera typename para declarar os templates. Um template de fun ca o (ou classe) pode aceitar argumentos com tipo pr e-denido. No exemplo a seguir const int, e o tipo pr e-denido. Exemplo: template<typename T1, const int n> class TCNome{...}; // Para criar um objeto de TCNome usa-se: TCNome<double, 20> nomeObjeto; Os argumentos com tipo denido em um template (como o int n do exemplo anterior) ser ao sempre const. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
504
Como uma classe template e apenas reescrita para cada tipo, esta ir a aceitar heran ca de uma classe comum, heran ca de uma classe gabarito e heran ca de uma classe gabarito para uma classe comum. Veja no exemplo a seguir a deni ca o de uma classe template TCPolinomioDerivado. A mesma acrescenta uma hipot etica fun ca o de deslocamento (os coecientes do polin omio s ao deslocados). // TCPolinomioDerivado.h template<typename T, const int size = 3> class TCPolinomioDerivado: public TCPolinomio<T,size> { ... T* p; void Shift(int deslocamento); // Novidade }; // TCPolinomioDerivado.cpp #include "TCPolinomioDerivado.h" template<typename T, const int size > void TCPolinomioDerivado<T,size>::Shift(int d) { T cp[size]; for(int i = 0; i < size ; i++) cp[i] = p[i]; for(int i = 0; i < size ; i++) { if( i + d < size) p[i] = cp[i + d]; else p[i] = cp[size - i - d ] } } 2 Nas classes templates, os m etodos devem ser denidos dentro da classe, ou em arquivos .cpp (inclu dos no .h), ou ainda usando a palavra-chave export. Embora os m etodos sejam inclu dos dentro da classe, e aconselh avel o uso da palavra-chave inline quando voc e deseja que o m etodo seja em linha. 2 Na deni ca o de uma classe template podemos incluir argumentos com valores pr edenidos (como o tipo int no exemplo abaixo). Mas na implementa ca o dos m etodos da classe template somente o tipo dos argumentos devem ser denidos, os valores pr edenidos n ao. Observe no exemplo abaixo que o argumento T2 tem como valor pr e-denido o tipo int. Exemplo: template<typename T1 , typename T2 = int > class TCNome { // Declara c~ ao do construtor TCNome(T1, T2); }; Mas na deni ca o do m etodo construtor, o tipo pr e-denido n ao deve ser passado. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
27.5. RESUMO DO CAP ITULO // Defini c~ ao do construtor template<typename T1 , typename T2 TCNome<T1,T2>::TCNome(T1, T2) {};
505
>
Se o argumento pr e-denido for inclu do na deni ca o, ocorrer a erro na compila ca o, veja abaixo mensagem de erro. XXX.cpp:19: error: default template arguments may not be used in function templates
27.5
Agora o leitor pode compreender as vantagens da programa ca o orientada a objeto com C++. A utiliza ca o de conceitos abstratos como classes, que permitem a cria ca o de tipos do usu ario, adequados ` a solu ca o de seus problemas, do polimorsmo, que permitem que o c odigo que altamente gen erico e pequeno, da sobrecarga de operadores, que possibilitam ao programador denir opera co es conhecidas como + - * /, e de templates, que tornam o c odigo gen erico, fazem de C++ uma linguagem de programa ca o extremamente poderosa e moderna. Neste cap tulo aprendemos a usar o conceito de fun co es e classes templates, e suas diversas varia co es. Vimos o prot otipo e o uso de fun co es template. Aprendemos que podemos estanciar explicitamente as fun co es e classes template. Como uma fun ca o template e um prot otipo, podemos implementar conceitos como argumentos pr e-denidos, sobrecarga de fun ca o template, uso de objetos est aticos. Aprendemos ainda a usar classes templates ou tipos param etricos, vimos seu prot otipo e um conjunto de regras para uso de classes templates. Classes template tamb em podem ter argumentos pr e-denidos. Dica: a biblioteca STL utiliza extensivamente o conceito de templates, veja Cap tulo 31 Introdu ca o a Biblioteca Padr ao de Gabaritos de C++.
27.6
Exerc cios
1. Transformar a hierarquia da classe CPonto em uma hierarquia de classes template. O tipo T dos valores de x, y, r1, r2 deve poder ser int, float, double, long double. 2. O exemplo que usa o m etodo Shift() na se ca o 27.4, pode ser otimizado, substitua o vetor cp por uma vari avel tempor aria. 3. No exemplo da listagem 27.1, incluir sobrecarga para operador< < e operador> >. Fa ca com que na sa da o polin omio seja escrito da forma: y = p[0] + p[1]x + p[2]x 2 + .... Dica: veja maiores detalhes de templates na refer encia Nicolai M. Josuttis e David Vandevoordes, C++ Templates - The Complete Guide, [Vandevoorde and Josuttis, 2002].
506
Cap tulo 28
28.1
28.1.1
Como vimos, um template de fun ca o ou classe e uma deni ca o gen erica. A quest ao e, esta deni ca o geral e v alida em todas as situa co es? Em algumas situa co es, um dado template funcionar a para a maioria dos tipos e falhar a para um tipo espec co. Vamos a um exemplo, uma fun ca o Menor() da forma: 507
508 Exemplo: template < typename Tipo > bool Menor(Tipo obj1, Tipo obj2) { return obj1 < obj2; }
Funcionar a para int, float e double, e falhar a para char* (cstring). Pois para comparar uma cstring devemos utilizar a fun ca o strcmp()1 da biblioteca de C. Neste caso, poderemos criar uma especializa ca o para a fun ca o template. A especializa ca o ir a tratar especicamente do caso de char*. Observe no exemplo a seguir o uso de template<> sem argumentos e ap os o nome da fun ca o o tipo especializado dentro de <, ou seja, < const char* >. Exemplo: // Especializa c~ ao de Menor para o tipo const char* template<> bool Menor< const char* >(const char* cstring1,const char* cstring2) { return strcmp(cstring1,cstring2) < 0; } A especializa ca o nada mais e do que a redeni ca o da fun ca o/classe template para um tipo espec co. Veja a seguir prot otipo para especializa ca o de fun ca o template. Prot otipo: template<> Retorno NomeFun ca o < TipoEspecializado > (par ametros) { ...fun ca o em s ... } Note que a fun ca o especializada pode ser totalmente diferente da original. Veja exemplo na listagem 28.1. Embora fun co es template possam ser especializadas, seu uso deve ser evitado, por quest oes de robustes e portabilidade do sistema. [Sutter, 2006], apresenta exemplos em que o uso de fun co es template especializadas apresenta problemas apenas em fun ca o da ordem em que as mesmas foram declaradas. Isto ocorre em fun ca o da ordem em que as fun co es s ao consideradas na avalia ca o da chamada da fun ca o: i) primeiro s ao chamadas as fun co es sem template, ii) a seguir s ao chamadas as fun co es com template, iii) em terceiro lugar s ao consideradas as fun co es com template que foram especializadas. A solu ca o para este problema e simples, como fun co es comuns se encaixam em (i), em vez de especializar a fun ca o template para um tipo X, reescreva a fun ca o para o tipo X usando uma fun ca o comum (n ao template). Outro problema do uso de especializa co es de fun co es template e que eles viabilizam a quebra do encapsulamento da classe. Pois se temos uma fun ca o template f, um outro programador - com m as inten co es - sempre poder a especializar a fun ca o por n os denida para uma tipo denido por ele (uma classe criada por ele). Como a fun ca o especializada ser a reescrita pelo outro programador, o mesmo poder a acessar atributos e m etodos privados da classe, pois a fun ca o especializada esta no mesmo escopo da classe. Veja maiores detalhes em [Sutter, 2006].
1 A fun ca o strcmp() e uma fun ca o de C que compara duas strings no formato const char*. Veja Ap endice K - Arquivos de Cabe calho.
509
Apresentam-se a seguir dois exemplos de otimiza ca o de programas utilizando-se conceitos avan cados de templates.
28.1.2
Voc e pode utilizar templates e especializa ca o de templates para criar fun co es que s ao expandidas em tempo de compila ca o. No exemplo da listagem 28.1, a fun ca o f<>() tem como argumento um int N e chama a si mesma passando N-1 (chamadas recursivas). Quando N = 0, chama a vers ao especializada da fun ca o f<>(), que termina o processo recursivo. Observe que a fun ca o f<>() e criada em tempo de compila ca o pela expans ao recursiva da fun ca o template. Este mecanismo torna a fun ca o muito r apida, pois elimina a chamada recursiva. A contrapartida e o aumento do tamanho do programa execut avel. Observe na sa da que os valores aparecem na ordem 0,1,2....,10, pois colocamos cout < < N= < < N < < \t; depois da chamada de f<N-1>();. Listing 28.1: Exemplo de fun ca o expandida em tempo de compila ca o.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # include < iostream > using namespace std ; // Fun c~ ao template recursiva template < int N > void f () { f <N -1 >() ; // Recurs~ a o , chama a si mesma cout << " N = " << N << \ t ; } // E s p e c i a l i z a c~ a o da fun c~ a o t e m p l a t e para o tipo int == 0 template < > void f <0 >() { cout << " N = " << 0 << \ t ; // Aqui f i n a l i z a a r e c u r s ~ ao } int main () { f <10 >() ; cout << endl ; return 0; } bash -3.00 $ ./ a . out N =0 N =1 N =2 N =3
N =4
N =5
N =6
N =7
N =8
N =9
N =10
No exemplo da listagem 28.2, adaptado de [Lischner, 2003], a fun ca o Arredondar() e usada para arredondar um n umero utuante para n casas decimais, e este processo e feito em tempo de compila ca o. A fun ca o, double floor(double x);, denida no arquivo de cabe calho <cmath> (se ca o 30.1.1), retorna o maior inteiro n ao maior que x (arredonda para baixo). A estrutura power_xy<> cria uma enumera ca o cujo valor e o resultado de xy . Observe que a chamada a power_xy<> e recursiva. Note que o programa cria vers oes especializadas para x0 , 0y e 00 . Observe na sa da que o n umero 1.23456789 e arredondado para 2, 4 e 6 casas decimais. Listing 28.2: Fun ca o pot encia expandida em tempo de compila ca o.
1 2 3 // A d a p t a d o de C ++ in a n u t s h e l l de Ray L i s c h n e r # include < cmath > # include < iostream >
510
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
// Fun c~ ao template - defini c~ a o geral - x ^ y template < int x , unsigned y > struct power_xy { enum { valor = x * power_xy <x , y -1 >:: valor }; }; // Fun c~ ao template - especializa c~ a o para x ^0 template < int x > struct power_xy <x , 0 > { enum { valor = 1 }; }; // Fun c~ ao template - especializa c~ a o para 0^ y template < unsigned y > struct power_xy <0 , y > { enum { valor = 0 }; }; // Fun c~ ao template - especializa c~ a o para 0^0 template < > struct power_xy <0 , 0 > {}; // A fun c~ a o abaixo a r r e d o n d a um n u mero f l u t u a n t e // c o n s i d e r a n d o n casas d e c i m a i s template < unsigned n , typename T > T Arredondar ( T x ) { if ( x < 0.0) return std :: floor ( x * power_xy <10 , n >:: valor - 0.5) / power_xy <10 , n >:: valor ; else return std :: floor ( x * power_xy <10 , n >:: valor + 0.5) / power_xy <10 , n >:: valor ; } int main () { std :: cout << Arredondar <2 >(1.23456789) << std :: endl ; std :: cout << Arredondar <4 >(1.23456789) << std :: endl ; std :: cout << Arredondar <6 >(1.23456789) << std :: endl ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ a . out 1.23 1.2346 1.23457
28.1.3
Em alguns casos, a deni ca o de um template pode ser correta, mas amb gua para o compilador. Veja o exemplo: Exemplo: template < typename T > void f( T obj ) {... Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
28.1. FUNC OES TEMPLATE USO AVANCADO T::X(par^ ametro); T::X* ptr; }
511
Se X for um tipo (uma classe aninhada de T), o comando T::X(par^ ametro) e uma chamada de construtor. Neste caso, vai criar um objeto an onimo (sem atribu -lo a algu em). Mas X tamb em pode ser uma fun ca o membro est atica. Assim, o compilador car a em d uvida: X e um tipo e devo chamar seu construtor ou X e uma fun ca o membro est atica? Da mesma forma, se X for um tipo ptr e um ponteiro para o tipo X. Se X for um atributo est atico de T, T::X *ptr; e a multiplica ca o de X por ptr. Para resolver estas ambig uidades o compilador assume por padr ao (default ) que X n ao e um tipo. Para que X seja considerado um tipo, voc e deve usar a palavra-chave typename. Veja o exemplo: Exemplo: template < typename T > void f( T obj) {... typename T::X obj(par^ ametro); } Veja outro exemplo na listagem 28.3.
28.1.4
Voc e pode mapear vari aveis de fun co es template utilizando especializa co es. No exemplo a seguir, uma fun ca o Media() recebe um vetor e determina a m edia de seus elementos. Exemplo: double Media (const double* vetor, int numeroElementos) { double soma = 0; for( int i = 0; i < numeroElementos; i++) soma += vetor[i]; return soma / numeroElementos; } Pode-se criar um template para esta fun ca o da forma: Exemplo: template< typename T > T Media (const T* vetor, int numeroElementos) { T soma = 0; for(int i = 0; i < numeroElementos; i++) soma += vetor[i]; return soma / numeroElementos; } Entretanto, quando a fun ca o template anteriormente denida for criada para int, ir a apresentar um erro, pois a divis ao soma / numeroElementos ser a truncada (a divis ao entre dois n umeros inteiros e sempre truncada, por exemplo 3/2 = 1). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
512
Pode-se resolver este problema criando-se um template de uma estrutura que inclua um typedef de um tipo T que ser a especializado para double quando o tipo T for int. O exemplo da listagem 28.3 esclarece melhor este caso. Observe que a vari avel double_trait< T > ser a do tipo correto. Se T for double, T_double ser a do tipo double, se T for int T_double tamb em ser a do tipo double. Veja na sa da que a fun ca o Media() funciona para int e para double. Listing 28.3: Exemplo de mapeamento de tipo com templates.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 # include < iostream > using namespace std ; // A e s t r u t u r a d o u b l e _ t r a i t cria um t y p e d e f para o tipo T template < typename T > struct d o u b l e _ t r a i t { typedef T T_double ; }; // E s p e c i a l i z a c~ a o da e s t r u t u r a d o u b l e _ t r a i t para int // Se o tipo T for int , T _ d o u b l e deve ser do tipo double template < > struct double_trait < int > { typedef double T_double ; }; // Uma fun c~ a o t e m p l a t e que usa a e s t r u t u r a d o u b l e _ t r a i t acima d e f i n i d a // o r e t o r n o e double_trait <T >:: T _ d o u b l e // o nome e Media // e os p a r ^ a m e t r o s const T * vetor , int n u m e r o E l e m e n t o s template < typename T > typename double_trait < T >:: T_double Media ( const T * vetor , int n u m e r o E l e m e n t o s ) { typename double_trait <T >:: T_double soma = 0; for ( int i =0; i < n u m e r o E l e m e n t o s ; i ++) soma += vetor [ i ]; return soma / n u m e r o E l e m e n t o s ; } // Usando a fun c~ a o t e m p l a t e Media () int main () { int * vetor_int = new int (4) ; for ( int i = 0; i < 4; i ++) vetor_int [ i ] = i ; double media ; media = Media ( vetor_int , 4) ; cout << " M e dia do vetor_int = " << media << endl ; delete [] vetor_int ; double * v e t o r _ d o u b l e = new double (4) ; for ( int i = 0; i < 4; i ++) vetor_double[i] = i; media = Media ( v e t o r _ d o u b l e , 4) ; delete [] v e t o r _ d o u b l e ; cout << " M e dia do v e t o r _ d o u b l e = " << media << endl ; cout << " ( int 3) /( int 2) = " << 3/2 << endl ; return 0; }
513
28.1.5
Uma fun ca o template pode ser indicada como uma fun ca o amiga, veja o exemplo: Exemplo: void F_Global(); template<typename T> void G_Global(T obj); namespace N1 { template<typename T> void f(T& c) {...} } // Declara fun c~ ao global F // // // // Declara fun c~ ao template global G Define um namespace Define um template Define uma fun c~ ao dentro do namespace
class CNome{ friend void F_Global(); template<typename T> friend void G_Global(T obj); friend void N1::f(CNome&); plate como amiga ...};
// Define uma classe // F_Global() e amiga // G_Global() e amiga // Declara uma fun c~ ao tem-
Neste exemplo denimos uma fun ca o template f(), e informamos que a mesma e amiga de CNome. Embora dentro dos padr oes, alguns compiladores n ao aceitam esta declara ca o da fun ca o friend. Uma das poss veis solu co es e usar: Exemplo: // Declara uma fun c~ ao template como amiga friend void N1::f<CNome>(CNome& c);
28.2
28.2.1
A listagem 28.4 mostra a cria ca o de um m etodo template dentro de uma classe normal. Note que criamos dois m etodos, um normal e outro est atico. Listing 28.4: Problema na chamada a m etodos template.
1 2 3 4 5 6 7 8 # include < iostream > class TCNome { public : template < int n > int M () { std :: cout << " normal : "
514
9 10 11 12 13 14 15 16 17 18 19 20
template < int n > static int SM () { std :: cout << " estatica : " << n << std :: endl ; } }; int main () { TCNome obj ; obj . M <3 >() ; TCNome :: SM <4 >() ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ a . out normal :3 estatica :4
Usando as listagens 27.1 e 27.2 podemos criar objetos polin omios usando int, float, etc. Podemos igualar objetos. Exemplo: TCPolinomio< int > TCPolinomio< int > p1Int = p2Int; p1Int; p2Int; // Cria polin^ omio para tipo inteiro // Cria polin^ omio para tipo inteiro // ok, iguala polin^ omios
Mas se em algum momento quis essemos igualar dois polin omios com tipos diferentes, ter amos um erro. O erro ocorre mesmo tendo implementado o operador igualdade, pois o mesmo e v alido para TCPolinomio< int > = TCPolinomio< int > ou TCPolinomio< float > = TCPolinomio< float >. Mas n ao pode ser usado para pFloat = pInt;. Observe na listagem 27.2, no nal da fun ca o main(), que colocamos o seguinte c odigo: Exemplo: TCPolinomio< float,size > pFloat; // pInt1 = pFloat1; // Cria polin^ omio para tipo float // Erro, tipos diferentes
Se retirarmos o coment ario da linha // pInt1 = pFloat1;, o compilador ir a apresentar a mensagem de erro apresentada na listagem ??.
[ b u e n o @ l d s c 0 5 Parte - II ] $ g ++ T e m p l a t e s C o m E r r o . cpp : In function int main () : :102: error : no match for operator = in pInt1 = pFloat1 :44: note : candidates are : TCPolinomio <T , size >& TCPolinomio <T , size >:: operator =( const TCPolinomio <T , size >&) [ with T = int , int size = 3] : In member function const T & TCPolinomio <T , size >:: operator () ( T ) const [ with T = int , int size = 3] : :63: i n s t a n t i a t e d from here :27: warning : converting to int from long double
Para resolver este problema, devemos criar uma camada adicional de template. Um template extra dentro da deni ca o da classe TCPolinomio, veja exemplo nas listagens 28.5 e 28.6. Observe no nal da deni ca o da classe TCPolinomio, a inclus ao de um construtor de c opia e de um operador de atribui ca o. Listing 28.5: Deni ca o de classe template com template adicional.
1 2 3 4 /* * Inclui t e m p l a t e s a d i c i o n a i s */ // Cria classe t e m p l a t e para polinomios , // Usa p a r ^ a m e t r o com valor pr e - definido , por padr~ a o size e 3 template < typename T , const int size = 3 >
515
Listing 28.6: Implementa ca o dos m etodos da classe template com template adicional.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 // (1) C o n s t r u t o r d e f a u l t template < typename T , const int size > TCPolinomio <T , size >:: TCPolinomi o () { for ( int i = 0; i < size ; i ++) p [ i ] = i ;}; // (2) C o n s t r u t o r de c o pia template < typename T , const int size > TCPolinomio <T , size >:: TCPolinomi o ( const TCPolinomio <T , size > & src ) { for ( int i = 0; i < size ; i ++) p [ i ] = src [ i ];}; // (4) S o b r e c a r g a do o p e r a d o r () // o b s e r v e que pow recebe long double template < typename T , const int size > const T & TCPolinomio <T , size >:: operator () ( T x ) const { T * poli = new T (0) ; for ( int i = 0 ; i < size ; i ++) (* poli ) += p [ i ] * pow ( static_cast < long double > ( x ) , i ) ; return * poli ; }; // (5) S o b r e c a r g a do o p e r a d o r [] template < typename T , const int size > T& TCPolinomio <T , size >:: operator []( int i ) { return p [ i ]; }; // (6) S o b r e c a r g a do o p e r a d o r [] template < typename T , const int size > const T & TCPolinomio <T , size >:: operator []( int i ) const { return p [ i ]; }; // (7) S o b r e c a r g a do o p e r a d o r = template < typename T , const int size > TCPolinomio <T , size >& TCPolinomio <T , size >:: operator =( const TCPolinomio <T , size > & src ) { for ( int i = 0; i < size ; i ++) p [ i ] = src [ i ];
516
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 return * this ; }
// (8) C o n s t r u t o r de c o pia - T e m p l a t e a d i c i o n a l template < typename T , const int size > template < typename E > TCPolinomio <T , size >:: TCPolinom i o ( const TCPolinomio <E , size > & src ) { for ( int i = 0; i < size ; i ++) p [ i ] = src [ i ];}; // (9) O p e r a d o r de a t r i b u i c~ ao - Template adicional template < typename T , const int size > template < typename E > TCPolinomio <T , size >& TCPolinomio <T , size >:: operator =( const TCPolinomio <E , size > & src ) { for ( int i = 0; i < size ; i ++) p [ i ] = src [ i ]; return * this ; }
Veja na listagem 28.7 o uso da classe template criada. Listing 28.7: Uso de classe template com template adicional.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # include < iostream > # include < cmath > # include " T e m p l a t e C o m T e m p l a t e A d i c i o n a l . h " using namespace std ; // Usando a classe T C P o l i n o m i o int main () { const int size = 3; int x = 5; cout << " x = " << x << endl ; cout << " Criando polin^ o mio TCPolinomio < int > pInt1 ; " << endl ; TCPolinomio < int > pInt1 ; // (1) cout << " C o e f i c i e n t e s de pInt1 = " ; for ( int i =0; i < size ; i ++) cout << pInt1 [ i ] << \ t ; // (5) cout << endl ; cout << " pInt1 ( x ) = " << pInt1 ( x ) << endl ; // (4) cout << " \ nCriando polin^ o mio TCPolinomio < float , size > pFloat1 ; " << endl ; TCPolinomio < float , size > pFloat1 ; // (1) cout << " C o e f i c i e n t e s de pFloat1 = " ; for ( int i =0; i < size ; i ++) cout << pFloat1 [ i ] << \ t ; // (5) cout << endl ; cout << " pFloat1 ( x ) = " << pFloat1 ( x ) << endl ; // (4) cout << " Igualando polin^ o mio s de tipos diferentes ... pInt1 = pFloat1 ; // (9) cout << " ... ok \ n " ; cout << " pInt1 ( x ) = " << pInt1 ( x ) << endl ; // (4) ";
517
28.2.2
Podemos usar especializa co es para reescrever toda uma classe para um tipo espec co, em fun ca o deste n ao ter o comportamento esperado (ou padr ao). A especializa ca o customiza a classe template para um tipo espec co. Veja a seguir o prot otipo utilizado na especializa ca o de classes templates. Prot otipo: // Deni ca o da classe template padr ao template< typename Tipo > class TCNome {...}; // Deni ca o da classe template especializada template<> class TCNome< TipoEspecializado > {...}; Com o uso de especializa co es, voc e pode criar vers oes otimizadas da fun ca o/classe template. Note, entretanto, que se voc e especializar uma classe template, ter a de especializar todos os m etodos da classe. Ou seja, ao criar uma especializa ca o de uma classe, a classe ter a de ser totalmente reescrita. Veja no exemplo a seguir como criar uma classe template TCNome que e especializada para o tipo Tipo* (ponteiro gen erico) e para o tipo void* (ponteiro espec co void*). Veremos o uso de ponteiros void* na se ca o F.2. Exemplo // Defini c~ ao da classe template template< typename Tipo > class TCNome {...}; // Especializa c~ ao para Tipo* (qualquer ponteiro) template< typename Tipo > class TCNome< Tipo * > {....}; // Especializa c~ ao espec fica para void* template<> class TCNome< void * > {.....}; Se uma classe com atributos est aticos foi especializada, n ao se esque ca de denir externamente cada atributo est atico para o tipo especializado. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
518
28.2. CLASSES TEMPLATE USO AVANCADO Exemplo: // Defini c~ ao da classe template template < typename T > class TCNome { static T atributoEstatico; }; // Defin c~ ao do atributoEstatico template < typename T > T TCNome<T>::atributoEstatico = 0; // Especializa c~ ao da classe para o tipo int // Defini c~ ao da classe template template < int > class TCNome { static int atributoEstatico; }; // Defin c~ ao do atributoEstatico especializado template<> int TCNome<int>::atributoEstatico = 0;
28.2.3
O c odigo da listagem 28.8, adaptado de [Lischner, 2003], mostra o uso de fun co es e classes template, como as mesmas podem ser instanciadas. Listing 28.8: Exemplo: Instanciando fun co es e classes template.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // A d a p t a d o de C ++ in a nutshell , de Ray L i s c h n e r // I n s t a n c i a n d o f u n c~ oes e classes templates # include < iomanip > # include < iostream > # include < ostream > const double pi = 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 2 ; // Fun c~ ao template template < typename T > void Saida ( T obj ) { std :: cout << obj << \ n ; } // Fun c~ ao template template < typename T > T sqr ( T x ) { return x * x ; } // I n s t a n c i a c~ ao expl c i t a de sqr para o tipo int template int sqr < int >( int ) ; // Erro : ap os instancia c~ a o de sqr < double > , uso ilegal do mesmo . template < > double sqr ( double x )
519
520
28.3
A inclus ao da palavra-chave export, foi alvo de grandes debates no comit e Ansi/ISO C++. Isto ocorreu porque, de um modo geral, primeiro os programadores desenvolvem novos conceitos que s ao posteriormente incorporados nos compiladores e na linguagem padr ao. Com export, o processo foi invertido. Os membros do comit e aprovaram o uso de export sem que nenhum compilador o suporta-se. Somente recentemente alguns poucos compiladores come caram a suportar o uso de export. A id eia por tr as do uso de export e fornecer dois modelos distintos de organiza ca o do c odigo fonte. O primeiro, cl assico, e conhecido como modelo de inclus ao. O segundo, novo, e conhecido como modelo de separa ca o. Veremos as diferen cas nesta se ca o. No modelo atual podemos declarar um m etodo n ao template no arquivo .h e den -lo do .cpp. Podemos compilar o programa tendo apenas a informa ca o disponibilizada no arquivo .h. Mas isto n ao e poss vel com templates. No modelo de inclus ao o c odigo fonte completo do template deve estar vis vel para quem vai o utilizar. Isto tem sido feito incluindo todo c odigo do template no arquivo .h ou incluindo no nal do arquivo .h o arquivo .cpp. No modelo de separa ca o pretende-se permitir a compila c ao separada de templates. Neste caso, a deni ca o do template n ao precisa estar vis vel para quem o chama. A id eia e permitir que um arquivo que use o template seja compilado sem ter sua deni ca o. Mas o que esta por tr as desta mudan ca e porque isto ainda n ao foi colocado em pr atica? Um dos objetivos desta mudan ca e eliminar a necessidade do c odigo-fonte (*.cpp). Seria fornecido diretamente o arquivo .h e o arquivo objeto. Desta forma impede-se o acesso do usu ario da biblioteca ao c odigo-fonte da biblioteca (templates), sendo este um claro interesse da ind ustria de software propriet ario. O segundo objetivo, este sim v alido, consiste em aumentar a velocidade de compila ca o. A segunda quest ao, esta associada ao fato de que pouqu ssimos compiladores tem suporte a export. Em resumo, evite usar export. Espere a pr oxima vers ao do C++, C++0x, e o posicionamento dos gurus de C++, para ver se export, vai ou n ao ser adotado pela comunidade. Para maiores detalhes, consulte [Sutter, 2006].
28.4
No in cio, C++ permitia o uso de fun co es template e de classes template globais. Voc e n ao podia declarar uma classe normal com um m etodo template. Agora isto e permitido, isto e, um m etodo membro da classe pode ser denido como template. Neste caso, os argumentos do template s ao denidos mediante a an alise dos par ametros do m etodo (listagem 28.4). A instancia ca o de uma classe template n ao garante que todos os membros sejam instanciados. Os membros ser ao instanciados se forem efetivamente utilizados ou se forem necess arios para resolu ca o de alguma sobrecarga de operador. Se numa classe template temos um m etodo M() que tem erros de sintaxe, mas o m etodo n ao e utilizado, ent ao alguns compiladores acusam o erro, outros n ao. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
521
Quando uma classe e especializada, teremos a vers ao padr ao e as vers oes especializadas. Quando criamos um objeto da classe template, passando seus argumentos, o compilador procura dentro das vers oes especializadas qual tem maior coincid encia. Se n ao for encontrada uma vers ao especializada, ent ao a vers ao padr ao e utilizada. Se duas vers oes especializadas tiverem o mesmo grau de coincid encia ent ao o compilador acusa uma ambiguidade, [Lischner, 2003]. Quando criamos m etodos template dentro de classes, a chamada ao m etodo pode car inviabilizada pois o compilador, em alguns casos, confunde o operador < como sendo o operador menor que. A solu ca o e informar explicitamente que estamos tratando com um m etodo template. Exemplo: class CNome { public: template< int n > int M(); template< int n > static int SM(); }; int main() { CNome obj; obj.template M<3>(); CNome::template SM<4>(); return 0; } Note que um atributo privado pode ser acessado por qualquer m etodo da classe, incluindo os m etodos/fun co es amigas. Na pr atica, isto signica que estes m etodos podem repassar - de forma oculta - este acesso para terceiros. Por exemplo, um m etodo da classe pode retornar uma refer encia para um atributo privado, violando o conceito de invari ancia da classe. Como um template de fun ca o pode ser especializado, o mesmo pode ser utilizado para violar o conceito de invari ancia da classe. Veja se ca o 28.1.1. 3 Segundo [Meyers, 2005], em classes templates derivadas use refer encias a nomes da classebase utilizando this, usando declara co es using, ou via qualica ca o explicita da classebase. 3 Um template dentro de uma classe normal ou de uma classe template e conhecido como membro template. Segundo [Lischner, 2003], um membro template tem as seguintes restri co es: classes locais n ao podem ter membro template. uma fun ca o membro template n ao pode ser um construtor. uma fun ca o membro template n ao pode ser virtual. se a classe-base tem um m etodo virtual, um m etodo membro template com o mesmo nome e par ametros numa classe-derivada n ao oculta o m etodo da classe-base.
3 Segundo [Sutter, 2006], export n ao implica em compila ca o separada, export apenas oculta depend encias, n ao as elimina. 3 Como export, ainda n ao e devidamente compreendido e n ao e suportado em v arios compiladores, seu uso deve ser evitado. Principalmente em c odigos multiplataforma. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
522
28.5
Neste cap tulo aprendemos a utilizar conceitos avan cados de templates, o uso de fun co es e classes template especializadas. Para atender a casos espec cos, aprendemos a criar especializa co es de fun co es template. Tamb em aprendemos a otimizar o programa utilizando fun co es expandidas em tempo de compila ca o. Vimos ainda que podemos mapear fun co es template utilizando especializa co es, e que em casos especiais precisamos usar a palavra-chave typename para identicar com clareza o que queremos. Aprendemos ainda a criar templates dentro de classes template e a especializa ca o de classes. Finalmente, vimos que ainda n ao devemos usar export. Dica: a biblioteca boost (veja Cap tulo ?? - A biblioteca Boost ), e a biblioteca Blitz++ (veja Cap tulo ?? - A biblioteca Blitz++ ), usam extensivamente os conceitos avan cados de templates, sendo boas refer encias para aprendizado e uso de templates. Dica: veja maiores detalhes de templates na refer encia Nicolai M. Josuttis e David Vandevoordes, C++ Templates - The Complete Guide, [Vandevoorde and Josuttis, 2002].
28.6
Exerc cios
1. Implementar a fun ca o Media(), da se ca o 28.1.4, usando o conceito de especializa ca o, se ca o 28.2.2. Ou seja, sem usar a struct double_trait. 2. Comentar o c odigo da listagem 28.8. 3. Na listagem 28.1, fazer com que a sa da seja em ordem decrescente. 4. Explique o funcionamento da listagem 28.2. 5. Leia o manual da biblioteca Blitz++ (se ca o ??). 6. Usu arios avan cados devem ler o livro C++ Templates - The Complete Guide, [Vandevoorde and Josuttis, 2002].
Cap tulo 29
29.1
Uma associa ca o pode ser unidirecional, bidirecional e pode (ou n ao) ter atributos. De um modo geral, pode ser implementada de tr es formas: Implementar a associa ca o por meio de ponteiros para os objetos. A cria ca o de uma classe que representa a associa ca o; neste caso, ser ao necess arios ponteiros para a classe associa ca o partindo dos objetos associados (veja se ca o 6.4.5). Utiliza ca o de fun co es friend (veja Cap tulo 20 - Friend).
29.2
Se a associa ca o for unidirecional e sem atributo de associa ca o, poder a ser implementada com um ponteiro na classe que faz o acesso. No exemplo a seguir a classe A acessa a classe B. Exemplo: class B; class A {... B* ptr_para_b; }; class B {... }; 523
524
Se a associa ca o for bidirecional, ser ao necess arios ponteiros em ambas as classes. No exemplo a seguir, a classe A acessa a classe B e a classe B acessa a classe A. Exemplo: class B; class A {... B* ptr_para_b; }; class B {... A* ptr_para_a; }; Se a associa ca o entre as duas classes for do tipo um para muitos, cardinalidade um A para muitos Bs, ent ao na classe que acessa muitos deve ser implementado um vetor de ponteiros. Exemplo: class B; class A { vector< B* > vetor_b(N); }; class B { A* ptr_para_a; }; Se a associa ca o tiver uma cardinalidade muitos para muitos, uma das solu co es e criar um dicion ario. Veremos como implementar um dicion ario usando <map> na se ca o 34.4. Dica: no programa umbrello, quando modelar uma associa ca o, indicar na linha da associa ca o o nome do papel.
29.3
Vimos na se ca o 6.4.5 que uma associa ca o entre duas classes pode gerar uma classe de associa ca o. Veremos na listagem 29.1 como implementar uma classe de associa ca o. Observe que a classe de associa ca o pode ser declarada como amiga de A e B. Listing 29.1: Associa ca o com atributo de liga ca o.
1 2 3 4 5 6 7 8 9 10 11 12 # include < iostream > using namespace std ; class Associacao ; class A { int a ; public : Associacao * p t r A s s o c i a c a o ; friend class Associaca o ; };
525
class B { int b ; public : Associacao * p t r A s s o c i a c a o ; friend class Associacao ; }; class Associacao { int a t r i b u t o A s s o c i a c a o ; A * ptr_A ; B * ptr_B ; public : Associacao () : a t r i b u t o A s s o c i a c a o (0) , ptr_A (0) , ptr_B (0) int A t r i b u t o A s s o c i a c a o () { return a t r i b u t o A s s o c i a c a o ; }; friend class A ; friend class B ; }; int main () { B b; Associacao associacao ; b . p t r A s s o c i a c a o = & associacao ; cout << " b . ptrAssociacao - > A t r i b u t o A s s o c i a c a o () = " << b . ptrAssociacao - > A t r i b u t o A s s o c i a c a o () << endl ; return 0; } [ b u e n o @ l d s c 0 5 ] $ ./ a . out b. ptr_associacao - > A t r i b u t o A s s o c i a c a o () =0
};
29.4
Neste cap tulo aprendemos a implementar associa co es em C++, associa co es sem atributo e associa co es com atributo.
29.5
Exerc cios
1. Modique a listagem 29.1. 2. Monte um diagrama de classes no umbrello que inclua diferentes tipos de associa co es. N ao se esque ca de nomear as associa co es, pois o umbrello usa o nome da associa ca o para gerar o c odigo. Gere os c odigos, veja se ca o 6.8.2. A seguir fa ca uma an alise dos c odigos gerados pelo umbrello.
526
Cap tulo 30
30.1
Veremos nesta se ca o a utiliza ca o da biblioteca <cmath> de C, a mesma fornece fun co es matem aticas.
30.1.1
Veja a seguir as fun co es de <cmath>. Observe que nos prot otipos abaixo utilizamos o tipo double, mas estas fun co es s ao denidas para float, double e long double. Prot otipo: double abs(double); Fun ca o valor absoluto. double ceil(double x); Fun ca o menor inteiro n ao menor que x (arredonda para cima). double oor(double x); Fun ca o maior inteiro n ao maior que x (arredonda para baixo). 527
double pow(double x, int y); Fun ca o x elevado a pot encia de y. double cos(double x); Fun ca o cosseno. double sin(double x); Fun ca o seno. double tan(double x); Fun ca o tangente. double acos(double x); Fun ca o arco cosseno. double asin(double x); Fun ca o arco seno. double atan(double x); Fun ca o arco tangente. double atan2(double x, double y); Fun ca o atan de x/y. double cosh(double x); Fun ca o cosseno hiperb olico. double sinh(double x); Fun ca o seno hiperb olico. double tanh(double x); Fun ca o tangente hiperb olico. double exp(double x); Fun ca o expoente na base e de x. double log(double x); Fun ca o logaritmo neperiano, x > 0. double log10(double x); Fun ca o logaritmo na base 10, x > 0. double modf(double x, int* y); Fun ca o parte fracion aria em x, parte inteira em y. Nota: podemos utilizar <math.h> (escopo global, usado por programas em C) ou <cmath> (escopo da std, formato utilizado por programas em C++). Com <math.h>, podemos chamar sin(30), cos(45) diretamente (pois as fun co es sin() e cos() est ao no escopo global). Com <cmath>, estamos no escopo da std, da precisamos usar std::sin(30), std::cos(45). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
529
30.1.2
Veja na listagem 30.1 exemplo de uso da biblioteca <cmath> de C. Listing 30.1: Usando fun co es matem aticas de <cmath>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 # include < iostream > # include < iomanip > # include < cmath > using namespace std ; int main () { cout << setiosfla g s ( ios :: fixed | ios :: showpoint ) << s e t p r e c i s i o n ( 1 ) << " Raiz quadrada sqrt (700.0) = " << sqrt ( 700.0 ) << " \ n " << " Exponencia l neperiana ( e ^ x ) << s e t p r e c i s i o n (6) exp (1.0) = " << exp (1.0) << " \ n "
<< " logaritmo neperiano log (2.718282) = " << s e t p r e c i s i o n (1) << log (2.718282) << " \ n " << " Logaritmo na base 10 log10 (1.0) = " << log10 ( 1.0 ) << " , log10 (10.0) = " << log10 ( 10.0 ) << " , log10 (100.0) = " << log10 ( 100.0 ) << " \ n " << " Fun ca ~ o valor absoluto , m o dulo fabs (13.5) = " << fabs ( 13.5 ) << " \ n " << " , fabs (0.0) = " << fabs ( 0.0 ) << " , fabs ( -13.5) = " << fabs ( -13.5 ) << " \ n " << " Truncament o ceil (9.2) = " << " , ceil ( -9.8) = " << " A r r e d o n d a m e n t o floor (9.2) = " << " , floor ( -9.8) = " << " Potencia ca ~ o x ^ y pow (2.0 ,7.0) = " << " fmod (13.675 , 2.333) = " << s e t p r e c i s i o n ( 1 ) << " \ n " << ceil ( 9.2 ) << ceil ( -9.8 ) << " \ n " << floor ( 9.2 ) << floor ( -9.8 ) << " \ n " << pow ( 2.0 , 7.0 ) << fmod ( 13.675 , 2.333 )
<< " Fun co ~ es trigonom e trica s , sin , cos , tan \ n " << " sin (0.0) = " << sin ( 0.0 ) << " , cos (0.0) = " << cos ( 0.0 ) << " , tan (0.0) = " << tan ( 0.0 ) << endl ; return 0; }
Raiz quadrada sqrt (700.0) = 26.5 Exponenci al neperiana ( e ^ x ) exp (1.0) = 2.718282 logaritmo neperiano log (2.718282) = 1.0 Logaritmo na base 10 log10 (1.0) = 0.0 , log10 (10.0) = 1.0 , log10 (100.0) = 2.0 Fun ca ~ o valor absoluto , m o dulo fabs (13.5) =13.5 , fabs (0.0) =0.0 , fabs ( -13.5) =13.5 Truncamen to ceil (9.2) = 10.0 , ceil ( -9.8) = -9.0 A r r e d o n d a m e n t o floor (9.2) = 9.0 , floor ( -9.8) = -10.0 Potencia ca ~ o x ^ y pow (2.0 ,7.0) = 128.0 fmod (13.675 , 2.333) = 2.0 Fun co ~ es trigonom e tric as , sin , cos , tan sin (0.0) = 0.0 , cos (0.0) = 1.0 , tan (0.0) = 0.0
530
30.2
A classe <complex> e uma classe que suporta n umeros complexos, com a parte real e a imagin aria. Com a classe <complex>, voc e pode trabalhar com n umeros complexos diretamente, utilizando os operadores e m etodos sobrecarregados. Pode igualar dois n umeros complexos, fazer compara co es, realizar opera co es aritm eticas (+-*/), exponencia ca o, obter logaritmos, pot encia, entre outros. Os objetos <complex> podem ter precis ao float, double e long double. Para criar um n umero complexo, voc e precisa incluir o arquivo de cabe calho <complex> e, a seguir, denir a precis ao do n umero complexo. Veja o exemplo. Exemplo: #include <complex> int main() { complex <float> cf; complex <double> cd; complex <long double> cld; return 0; }
30.2.1
M etodos de <complex>
Veja a seguir os m etodos da classe <complex>. Construtores e destrutor Como a classe <complex> representa um n umero complexo, voc e pode construir um n umero complexo a partir da parte real, ou a partir da parte real e da imagin aria. complex (const Tipo& real = Tipo(), const Tipo & img = Tipo()); Recebe como par ametro a parte real e a parte imagin aria. Observe que o construtor tem par ametros pr e-denidos, de forma que se os mesmos n ao forem passados, assume o valor default para o tipo, 0 para os tipos num ericos. Note ainda que podemos construir um n umero complexo apenas com a parte real. complex (const complex<Tipo2>&); Construtor de c opia. complex (); Destrutor. Veja o exemplo. Exemplo: // Cria um n umero complexo, do tipo float com nome cf complex <float> cf; // Cria um n umero complexo, do tipo double e passa parte real double parteReal = 3.4; complex <double> cd( parteReal ); // Cria um n umero complexo e passa a parte real e a parte imagin aria double parteImg = 21.5; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
A ` CLASSE <COMPLEX> 30.2. INTRODUC AO complex <long double> cld( parteReal , parteImg ); // Construtor de c opia, cria c opia de cf complex <float> cf2( cf ); M etodos utilit arios
531
A classe <complex> fornece um conjunto de m etodos que possibilitam a obten ca o de propriedades deste, como o m odulo, o argumento, a norma, o conjugado, entre outros. Tipo& real(); Retorna a parte real de um n umero complexo. Tipo& imag(); Retorna a parte imagin aria de um n umero complexo. Tipo abs(const complex<Tipo>&); Retorna magnitude. Tipo arg(const complex<Tipo>&); Retorna angulo de fase. Tipo norm(const complex<Tipo>&); Retorna magnitude ao quadrado. complex<Tipo> conj(const complex<Tipo>&); Retorna n umero complexo conjugado. complex<Tipo> polar(const Tipo& rho, const Tipo& theta= 0); Retorna n umero complexo com magnitude rho e angulo theta. Veja a seguir um exemplo. Exemplo: float real = cf.real(); // Retorna parte real float img = cf.imag(); // Retorna parte imagin aria float abs = cf.abs( ); // Retorna m odulo float arg = cf.arg(); // Retorna argumento // Soma dos quadrados da parte real e da imagin aria float norm = cf.norm(); // A magnitude e o ^ angulo de fase const float magnitude =3; const float fase =45; float p = cf.polar (magnitude, fase); // Retorna o conjugado complex <float> cf_conjugado = cf.conj(); M etodos trancendentais A classe <complex> fornece um conjunto de m etodos transcendentais, como acos, asin, atan, atan2, cos, cosh, exp, log, log10, pow, sin, sinh, sqrt, tan, tanh. Veremos na listagem 30.3 um resumo da classe <complex> fornecida pela biblioteca padr ao de C++, o que inclui o prot otipo dos m etodos trancendentais. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
Diversos operadores foram sobrecarregados para a classe <complex>, a lista e dada por: +, -, *, /, += ,-= , *= , -, * ,+ , -. Tamb em foram denidos operadores de compara ca o (==, !=) e operadores de inser ca o e extra ca o (stream), ou seja, podemos enviar n umeros complexos diretamente para tela com cout. Veremos na listagem 30.2 exemplos de uso dos operadores que foram sobrecarregados. template plex<X>& template plex<X>& <class X> istream& operator > > (istream& is, comx); <class X> ostream& operator < < (ostream& os, const comx);
30.2.2
Veja na listagem 30.2 um exemplo da utiliza ca o da classe <complex>, observe a forma como a classe complexo sobrecarregou os operadores < < e > >. O n umero complexo aparece dentro de par enteses. Listing 30.2: Usando <complex>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # include < iostream > # include < complex > using namespace std ; int main () { complex < double > c1 (1.2 , 3.4) ; complex < double > c2 ( -9.8 , -7.6) ; cout << " c1 = " << c1 << " , c2 = " << c2 << endl ; c1 += c2 ; c2 /= sin ( c2 ) * cos ( c1 ) ; cout << " c1 = " << c1 << " , c2 = " << c2 << endl ; c2 *= log ( c1 ) + pow ( c2 , c1 ) ; c1 -= c1 / c2 ; cout << " c1 = " << c1 << " , c2 = " << c2 << endl ; cout << " Entre com o complexo c1 ( real , imag ) : " ; cin >> c1 ; cin . get () ; cout << " Conte u do de c1 = " << c1 << endl ; return 0; } [ b u e n o @ l d s c 0 5 Parte - II ] $ ./ a . out c1 = (1.2 ,3.4) , c2 = ( -9.8 , -7.6) c1 = ( -8.6 , -4.2) , c2 = (7.77139 e -05 , -0.000364079) c1 = ( -8.6 , -4.2) , c2 = (3.37075 e +23 , -1.75436 e +23) Entre com o complexo c1 ( real , imag ) : (3 ,4) Conte u do de c1 = (3 ,4)
30.2.3
Veja na listagem 30.3 um resumo da classe <complex> fornecida pela biblioteca padr ao de C++. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
A ` CLASSE <COMPLEX> 30.2. INTRODUC AO Listing 30.3: A classe <complex> da biblioteca padr ao.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 // Resumo do a r q u i v o c o m p l e x da b i b l i o t e c a padr~ a o de C ++ // As d e f i n i c~ o e s de t e m p l a t e foram t i r a d a s para maior b r e v i d a d e // Cria v e r s ~ o e s de n u m e r o s c o m p l e x o s para float , double , long double class complex ; template < > class complex < float >; template < > class complex < double >; template < > class complex < long double >; // A classe c o m p l e x struct complex { private : Tipo _M_real ; // / Parte real Tipo _M_imag ; // / Parte i m a g i n aria public : // / D e f i n i c~ a o do t y p e d e f para v a l u e _ t y p e . typedef Tipo value_type ; // / C o n s t r u t o r padr~ ao . O primeiro par^ ametro e a parte real , // / o s e g u n d o a parte i m a g i n aria. // / P a r ^ a m e t r o s n~ a o d e f i n i d o s a s s u m e m valor 0. complex ( const Tipo & = Tipo () , const Tipo & = Tipo () ) ; // / C o n s t r u t o r de c o pia . complex ( const complex < Tipo2 >&) ; // / R e t o r n a parte real do n u mero c o m p l e x o Tipo & real () ; const Tipo & real () const ; // / R e t o r n a parte i m a g i n a r i a do n u mero c o m p l e x o Tipo & imag () ; const Tipo & imag () const ; // / O p e r a d o r e s complex < Tipo >& complex < Tipo >& complex < Tipo >& complex < Tipo >& complex < Tipo >& complex < Tipo >& complex < Tipo >& complex < Tipo >& complex < Tipo >& complex < Tipo >& sobrecarregados ( m e t o d o s membro ) operator =( const Tipo &) ; operator +=( const Tipo &) ; operator -=( const Tipo &) ; operator *=( const Tipo &) ; operator /=( const Tipo &) ; operator =( const complex < Tipo2 >&) ; operator +=( const complex < Tipo2 >&) ; operator -=( const complex < Tipo2 >&) ; operator *=( const complex < Tipo2 >&) ; operator /=( const complex < Tipo2 >&) ;
533
// / O p e r a d o r e s s o b r e c a r r e g a d o s ( f u n c~ o e s amigas ) operator +( const complex < Tipo >& __x , const complex < Tipo >& __y ) ; operator +( const complex < Tipo >& __x , const Tipo & __y ) ; operator +( const Tipo & __x , const complex < Tipo >& __y ) ; operator -( const complex < Tipo >& __x , const complex < Tipo >& __y ) ; operator -( const complex < Tipo >& __x , const Tipo & __y ) ; operator -( const Tipo & __x , const complex < Tipo >& __y ) ; operator *( const complex < Tipo >& __x , const complex < Tipo >& __y ) ; operator *( const complex < Tipo >& __x , const Tipo & __y ) ; operator *( const Tipo & __x , const complex < Tipo >& __y ) ; operator /( const complex < Tipo >& __x , const complex < Tipo >& __y ) ; operator /( const complex < Tipo >& __x , const Tipo & __y ) ;
534
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
operator /( const Tipo & __x , const complex < Tipo >& __y ) ; operator +( const complex < Tipo >& __x ) ; operator -( const complex < Tipo >& __x ) ; operator > >( basic_istream < _CharT , _Traits >& __is , complex < Tipo >& __x ) ; operator < <( basic_ostream < _CharT , _Traits >& __os , const complex < Tipo >& __x ) ; // F u n c~ oes matem a t i c a s para n umeros complexos // / R e t o r n a m a g n i t u d e Tipo abs ( const complex < Tipo >&) ; // / R e t o r n a angulo de fase Tipo arg ( const complex < Tipo >&) ; // / R e t o r n a m a g n i t u d e ao q u a d r a d o Tipo norm ( const complex < Tipo >&) ; // / R e t o r n a n u mero c o m p l e x o c o n j u g a d o complex < Tipo > conj ( const complex < Tipo >&) ; // / R e t o r n a n u mero c o m p l e x o com m a g n i t u d e rho e angulo theta . complex < Tipo > polar ( const Tipo & , const Tipo & = 0) ; // / M etodos transcendentais: complex < Tipo > cos ( const complex < Tipo >&) ; complex < Tipo > cosh ( const complex < Tipo >&) ; complex < Tipo > exp ( const complex < Tipo >&) ; complex < Tipo > log ( const complex < Tipo >&) ; complex < Tipo > log10 ( const complex < Tipo >&) ; complex < Tipo > pow ( const complex < Tipo >& , int ) ; complex < Tipo > pow ( const complex < Tipo >& , const Tipo &) ; complex < Tipo > pow ( const complex < Tipo >& , const complex < Tipo >&) ; complex < Tipo > pow ( const Tipo & , const complex < Tipo >&) ; complex < Tipo > sin ( const complex < Tipo >&) ; complex < Tipo > sinh ( const complex < Tipo >&) ; complex < Tipo > sqrt ( const complex < Tipo >&) ; complex < Tipo > tan ( const complex < Tipo >&) ; complex < Tipo > tanh ( const complex < Tipo >&) ; };
30.3
Apresentaremos nesta se ca o a classe <bitset>, uma classe criada para manipula ca o de vetores de bits. Voc e vai aprender a criar e usar um vetor de bits com tamanho denido durante a compila ca o. Veja a seguir algumas dicas para uso de <bitset>. O tamanho do vetor de bits deve ser denido em tempo de compila ca o, ou seja, um objeto <bitset> e um objeto est atico. O valor default de cada bit e 0. Um <bitset> pode ser constru do a partir de uma string de zeros (0) e um (1). Todo acesso b[i] e vericado; se i est a fora do intervalo, uma exce ca o do tipo out_of_range e lan cada. N ao confunda um operador sobre bits (& e |) com operadores l ogicos (&& e ||). A grande vantagem de <bitset> e a possibilidade de manipular um vetor de ags (0, 1), consumindo pouca mem oria. Para criar um objeto <bitset>, inclua o arquivo de cabe calho <bitset>. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
535
30.3.1
M etodos de <bitset>
void set(n); Seta o bit n para true. void reset(n); Seta o bit n para false. void ip(n); Inverte o valor do bit n. void set(); Seta todos os bits para true. void reset(); Seta todos os bits para false. void ip(); Inverte o valor de todos os bits. int size(); Retorna a dimens ao do <bitset>. int count(); Retorna o n umero de bits ativos. bool any(); Retorna true se tiver pelo menos um bit ativo. bool none(); Retorna true se todos inativos operator< <(); Rotaciona os bits para esquerda. operator> >(); Rotaciona os bits para direita. operator[] (int i); Retorna o valor do bit na posi ca o i.
30.3.2
Veremos uma breve descri ca o de cada m etodo da classe <bitset> no exemplo da listagem 30.4. A listagem e auto-explicativa. Na sa da mostramos que o <bitset> b consome 8 bytes em uma plataforma de 64 bits. Listing 30.4: Exemplo descritivo da classe <bitset>.
1 2 3 4 5 6 7 8 # include < bitset > # include < iostream > using namespace std ; int main () { const int size = 5; cout << " Cria objeto do tipo bitset com tamanho size " << size
536
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 << " e nome b . " << endl ; std :: bitset < size > b ; long unsigned int n ;
cout << " Entre com o bit que deseja modificar n = " ; cin >> n ; cin . get () ; cout << " Seta o bit n = " << n << " para true --> " ; b . set ( n ) ; cout << b << endl ; cout << " Seta o bit n = " << n << " para false - - > " ; b . reset ( n ) ; cout << b << endl ; cout << " Seta todos os bits para true - - > " ; b . set () ; cout << b << endl ; cout << " Seta todos os bits para false - - > " ; b . reset () ; cout << b << endl ; cout << " Inverte o bit n = " << n << " --> " ; b . flip ( n ) ; cout << b << endl ; cout << " Inverte todos os bits - - > " ; b . flip () ; cout << b << endl ; cout << " Usa m e todo teste ( n ) , com n = " << n ; bool t = b . test ( n ) ; cout << " bool t = b . test ( n ) ; t = " << t << endl ; cout << << << << << << cout << " Tamanho do bitset - - > b . size () = " << b . size () " \ nN u mero de bits ativados b . count () = " << b . count () " \ nRetorna true se tem pelo menos um bit esta ativo b . any () = " b . any () " \ nRetorna true se todos os bits est~ a o inativos b . none () = " b . none () << endl ; " Cria bitset b1 e b2 e faz b1 [ n ] = 1; " << endl ;
std :: bitset < size > b1 ; std :: bitset < size > b2 ; b1 [ n ] = 1; if ( b1 cout if ( b1 cout == << != << b2 ) " b1 == b2 " << endl ; b2 ) " b1 != b2 " << endl ;
cout << " Realiza um AND bit a bit e armazena em b1 : b1 &= b2 ; " << endl ; b1 &= b2 ; cout << " b1 - - > " << b1 << " b2 - - > " << b2 << endl ; cout << " Realiza um OR bit a bit e armazena em b1 : b1 [1] = 1; b1 != b2 ; " << endl ; b1 [1] = 1; b1 != b2 ; cout << " b1 - - > " << b1 << " b2 - - > " << b2 << endl ;
537
cout << " Realiza um XOR bit a bit e armazena em b1 : b1 ^= b2 ; " << endl ; b1 ^= b2 ; cout << " b1 - - > " << b1 << " b2 - - > " << b2 << endl ; b1 . reset () ; b1 [ n ] = 1; b1 > >= n ; cout << " Ap o s b1 . reset () ; b1 [ n ] = 1; b1 > >= n ; " << " b1 - - > " << b1 << endl ; b1 < <= n ; cout << b1 << endl ; cout << " Ap o s b1 < <= n ; " << " b1 - - > " << b1 << endl ; cout << " Veja que o bitset b consome apenas " << sizeof ( b ) << " bytes \ n " ; return 0; } [ b u e n o @ l d s c 0 5 Cap -30] $ ./ E x e m p l o D e s c r i t i v o D a C l a s s e b i t s e t Cria objeto do tipo bitset com tamanho size 5 e nome b . Entre com o bit que deseja modificar n =1 Seta o bit n =1 para true - - >00010 Seta o bit n =1 para false - - >00000 Seta todos os bits para true - - >11111 Seta todos os bits para false - - >00000 Inverte o bit n =1 - - >00010 Inverte todos os bits - - >11101 Usa m e todo teste ( n ) , com n =1 bool t = b . test ( n ) ; t = 0 Tamanho do bitset - - > b . size () =5 N u mero de bits ativados b . count () =4 Retorna true se tem pelo menos um bit esta ativo b . any () =1 Retorna true se todos os bits est~ a o inativos b . none () =0 Cria bitset b1 e b2 e faz b1 [ n ] = 1; b1 != b2 Realiza um AND bit a bit e armazena em b1 : b1 &= b2 ; b1 - - >00000 b2 - - >00000 Realiza um OR bit a bit e armazena em b1 : b1 [1] = 1; b1 != b2 ; b1 - - >00010 b2 - - >00000 Realiza um XOR bit a bit e armazena em b1 : b1 ^= b2 ; b1 - - >00010 b2 - - >00000 Ap o s b1 . reset () ; b1 [ n ] = 1; b1 > >= n ; b1 - - >00001 00010 Ap o s b1 < <= n ; b1 - - >00010 Veja que o bitset b consome apenas 8 bytes
30.3.3
Apresenta-se na listagem 30.5 o uso da classe <bitset> com a classe container <vector>. O container <vector> e descrito em detalhes no Cap tulo 32 - Os Containers Sequ enciais <vector>, <list>, <deque>. O programa cria um vetor com dimens ao nbitsets, sendo cada c elula do vetor um bitset com tamanho nbits. Lembre-se que para criar um vetor de 50 inteiros, utiliza-se vector<int> v(50);. Para criar um vetor de 50 objetos do tipo bitset<nbits>, deve-se fazer vector< bitset<nbits> > v(50);. Com v[i], acessa o objeto bitset [i], e com v[i][j] acessa-se objeto <bitset> [i], bit [j]. Usamos um for para setar os valores de cada elemento da matriz de bits que criamos. No nal o programa solicita a posi ca o do vetor e a posi ca o do bit que deve ser alterado.
538
A ` CLASSE <BITSET> 30.3. INTRODUC AO Listing 30.5: Usando <bitset> com <vector>, criando uma matriz de bits.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
# include < iostream > # include < cmath > # include < bitset > # include < vector > using namespace std ; int main () { // Dimens~ a o fixa do vetor de bits const int nbits = 24; // Dimens~ a o vari a vel do vetor cout << " Entre com o numero de bitsets :"; int nbitsets ; cin >> nbitsets ; cin . get () ; // Cria o vetor de bitsets , observe que nbits e constante vector < bitset < nbits > > v ( nbitsets ) ; // v [ i ] acessa o bitset i , v [ i ][ j ] acessa o bitset i posi ca ~o j for ( int i = 0; i < v . size () ; i ++) for ( int j = 0; j < nbits ; j ++) v [ i ][ j ] = ( rand () % 2) ; for ( int i = 0; i < v . size () ; i ++) cout << v [ i ] << ; cout << endl ; int d ; do { int bitset_i , bit_j ; cout << "\ nEntre com o bitset que deseja alterar 0 - >" << v . size () -1 << ": "; cin >> bitset_i ; cout << " Entre com o bit que deseja alterar de 0 - >" << nbits - 1 << ": "; cin >> bit_j ; cout << " Entre com o novo valor do bit (0 ou 1) , >1 encerra programa : "; cin >> d ; cin . get () ; v [ bitset_i ][ bit_j ] = d ; cout << "\ nbitset " << bitset_i << " bit " << bit_j << " valor =" << v [ bitset_i ][ bit_j ] << endl ; for ( int i = 0; i < v . size () ; i ++) cout << v [ i ] << " "; } while ( d <= 1) ; return 0; } [ b u e n o @ l d s c 0 5 ] $ ./ a . out Entre com o numero de bitsets :3 110100000110101100111101 001011110101110001111000 101110101011100010010101 Entre com o bitset que deseja alterar 0 - >2: 1 Entre com o bit que deseja alterar de 0 - >23: 3 Entre com o novo valor do bit (0 ou 1) , >1 encerra programa : 0
539
bitset 1 bit 3 valor =0 110100000110101100111101 001011110101110001110000 101110101011100010010101 Entre com o bitset que deseja alterar 0 - >2:
Dica: a STL criou uma especializa ca o para vector<bool> que e utilizada para armazenar verdadeiro/falso (true/false). A vantagem de vector<bool> em rela ca o a <bitset> e que o mesmo pode ser redimensionado, quando <bitset> n ao.
30.4
Neste cap tulo aprendemos a usar a classe <complex> da biblioteca padr ao de C++. A classe <complex> e muito u til para solu ca o de problemas matem aticos e de engenharia, e o fato da classe <complex> ter diversos operadores e m etodos trancendentais facilita seu uso. Adicionalmente, os m etodos real(); imag(); abs(); arg() norm(); conj(); polar(); s ao f aceis de usar, o que pode ser vericado atrav es dos exemplos apresentados. Vimos que a classe <bitset> representa um vetor de bits com tamanho denido em tempo de compila ca o. Os m etodos de <bitset>, set(n); reset(n); flip(n); set(); reset(); flip(); size(); count(); any(); none(); tamb em s ao bastante simples. Finalmente vimos as fun co es matem aticas denidas no arquivo de cabe calho <cmath>, seus prot otipos e exemplos de uso.
30.5
Exerc cios
1. Modique a listagem 30.2 , acrescentando novos usos de <complex>. 2. Modique as listagens 30.4, acrescentando novos usos de <bitset>. 3. Monte um programa que utilize as fun co es matem aticas de <cmath>. 4. Implementar a hieraraquia de classes da Figura 30.1. Observe que temos tr es hierarquias de classes, Solver, Funcao e Integral. A classe de teste vai criar um objeto fun ca o e a seguir usar um objeto do tipo Solver para achar o zero de equa co es.
540
Figura 30.1: Pequena hierarquia de m etodos num ericos (solver e integral num erica de fun co es do tipo polin omios).
T t e s l P / N T I t t S l P / N t a c o e a m e s p a c e n e g r a a c o e a m e s p a c e o v e r f * 1 T F u n c a o : V 2 ( ) t e s l t n e g r a i l + n g r I r ~ i f d b l I m n o u : S V l ( ) b l T I l i f d b l I a n e g r a o : m n o u e : l S u p V S S o v p d x e i t t e r i t t e r r v a o s n : l s o v e r d x d b l a o : V b l l t o u n e g r a : ( * ) d b l A F F p u n c u c a o o u e : V I + y ) I t n g a f 1 t p r v f ( i d b l i S d b l ) d b l Z I e m n o u e m u p o u e o u e + : : : , + _ _ ) d b l o o u e : i t n m s o n I S p ( * ) d b l A F F t r e a p r u c a o u c a o u e : : f + u n c a o d t l a y p e o v e r S i T t f 1 n r a z o r v I p ( * ) d b l A F F t r e a p r u c o u n c a o u e : : i + t t e s r e o p F u n c a T F u n c a o l i G T P 1 l i B o n m o o v e r s e c a o d b l x o e : S V d b l 1 a o u e : y u V ( l i f d b l S d b l ) d b l Z I e r o m n u m u p u e o u e : : : 2 , + _ _ ( ) d b l ) d b l t p r a x o e o u e : : + 0 T F n c # ( ) d b l ) d b l t p e r x o u e o u e : : o + ~ l i G 0 d b l ) T P 1 1 o n m a a o u e : i i b A , u e s l h N R t _ _ o v e r w o n a s o n S p a ( ) d b l ) d b l t o p e r a x o u e o u e : : + G ( lim f d b l, im S d b le ) d b le Z I u : e r o n u u u o u : : : f ( d l x : + _ _ ) X o l b ) v u u e l i 2 G T P o n m o Y + 3 d b l a o u e ( d l : a e : V 2 # ( ) d b l ) d b l t p e r x o u e u e : : + i 2 G 0 d b le 2 d b le ) P / N T P 1 t n m a o o u a o u c o a m e s p a c e : : , , _ _ _ T F u no a o G u :a
Andr e Duarte Bueno
Parte III
Introdu c ao a STL
541
Cap tulo 31
31.1
O que e a STL?
A STL, ou Standard Template Library, e uma biblioteca de objetos avan cada e u til, desenvolvida por Alexander Stepanov, Meng Lee e David Musser, utilizando os conceitos mais modernos da programa ca o orientada a objeto. Todo desenvolvimento da STL foi acompanhado e aprovado pelo comit e de padroniza ca o do C++, o ANSI C++ (veja se ca o 7.3). A biblioteca-padr ao de C++ inclui as classes string, streams, internacionaliza ca o, exce co es, classes matem aticas (complex, valarray), utilit arios (auto_ptr), gerenciamento de mem oria (new e delete) e as classes da STL. Ou seja, a STL e uma parte da biblioteca-padr ao de C++. Veja na Figura 31.1 uma ilustra ca o da biblioteca padr ao de C++. Nota: as classes <bitset>, <basic_string>, string, wstring, valarray, e vector<bool> s ao pseudo-container, porque suportam apenas parte dos algoritmos gen ericos. 543
544
<sstreambuf> <iomanip>
<ostream>
<sstream>
matemticas
<bitset>
<complex>
<valarray>
<stringstream>
<fstream>
excees
exception
logic_error
bad_alloc
bad_cast
bad_exception
bad_typeid
runtime_error
out_of_range
lenght_error
invalid_argument
domain_error
ios_base::failure
underflow_error
overflow_error
range_error
31.1.1
N ao utiliza polimorsmo em fun ca o do desempenho. Utiliza extensivamente os templates (veja Cap tulo 27 - Templates). Constru da basicamente sobre tr es conceitos: containers, iteradores e programa ca o gen erica (se ca o 31.1.2).
31.1.2
Componentes da STL
Containers: objeto utilizado para armazenar grupos de objetos (como <vector>). Veja introdu ca o aos containers na se ca o 31.2 e detalhes nos Cap tulos 32, 33 e 34. Iteradores: Vimos no Cap tulo 15 - Utiliza ca o de Ponteiros e Refer encias o uso de ponteiros. Veremos na se ca o 31.3 que iteradores s ao ponteiros inteligentes. Programa c ao gen erica: conjunto de fun co es que podem ser utilizadas com objetos e containers com os mais variados e gen ericos tipos de dados. Inclui fun co es para preenchimento, compara ca o, remo ca o, troca, mistura, pesquisa, ordena ca o, classica ca o e Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
545
transforma ca o dos containers e de seus elementos (veja Cap tulo 35 - Programa ca o Gen erica).
31.2
Se voc e tem um grupo de objetos do mesmo tipo ou de uma mesma hierarquia, pode organiz a-los por meio de um container. Um container e uma esp ecie de caixa onde objetos do mesmo tipo podem ser armazenados. Existem diferentes tipos de containers e a escolha do container mais adequado vai depender do que voc e pretende realizar sobre o seu grupo de objetos. Os containers podem ser divididos em tr es categorias: os seq uenciais (se ca o 31.2.1), os associativos (se ca o 31.2.2) e os adaptativos (se ca o 31.2.3). Estes containers e suas principais caracter sticas s ao descritos a seguir.
31.2.1
Os containers seq uenciais s ao <vector>, <list> e <deque>. Estes s ao u teis para armazenar estruturas de dados (ou objetos) que est ao normalmente em seq u encia. Ser ao descritos no Cap tulo 32 - Containers Seq uenciais <vector>, <list> e <deque>. Veja na Figura 31.2 uma ilustra ca o dos containers seq uenciais. Figura 31.2: Containers seq uenciais - <vector>, <list>, <deque>.
Containers vector
0 1 2
Sequenciais
3 ... n-2 n-1
list
...
n-2
n-1
deque
...
n-2 n-1
Descrevemos a seguir o nome do container, suas caracter sticas b asicas e os iteradores suportados. <vector> O container <vector> funciona como um vetor comum permitindo acesso aleat orio (Figura 31.2). Tem r apida inser ca o de objetos no nal do vetor e lenta no meio. Suporta iterador de acesso rand omico. Ser a descrito na se ca o 32.1. <list> Utilize o container <list> quando precisar de uma lista de objetos em que novos objetos podem ser inclu dos em qualquer posi ca o, ou seja, tem inser ca o e dele ca o r apida em qualquer posi ca o (Figura 31.2). Lento para acesso rand omico. Suporta iterador de acesso bidirecional. Ser a descrito na se ca o 32.2. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
546
AOS CONTAINERS 31.2. INTRODUC AO <deque> Utilize o container <deque> quando precisar de uma lista de objetos em que novos objetos podem ser inclu dos em qualquer posi ca o (Figura 31.2). Tem as vantagens de <vector> uma la com duas pontas. Permite acesso aleat e <list>. E orio. Suporta iterador de acesso rand omico. Ser a descrito na se ca o 32.3.
31.2.2
Containers associativos
Os containers associativos funcionam com o conceito de chaves (keys ). Estes podem ser utilizados para armazenar um grupo de objetos que est ao sempre ordenados (container <set>), ou para relacionar uma determinada chave com um valor (container <map>). Os containers associativos est ao sempre ordenados; por default, o operador < e utilizado para ordena ca o. Ser ao descritos no Cap tulo 31 - Containers Associativos <set>, <multiset>, <map> e <multimap>. Veja na Figura 31.3 uma ilustra ca o dos containers associativos. Figura 31.3: Containers associativos - <set>, <multiset>, <map>, <multimap>.
Containers Associativos
<set> <map>
<multiset> <multimap>
<set> Um container <set> armazena um conjunto de chaves (sem repeti co es) e tem pesquisa r apida. Suporta iterador de acesso bidirecional. Ser a descrito na se ca o 34.2. <multiset> Um container <multiset> armazena um conjunto de chaves (com repeti co es) e tem pesquisa r apida. Suporta iterador de acesso bidirecional. Ser a descrito na se ca o 34.3. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
547
<map> Um container <map> armazena um conjunto de pares [chave, objeto] (sem repeti co es). Suporta iterador de acesso bidirecional. Ser a descrito na se ca o 34.4. <multimap> Um container <multimap> armazena um conjunto de pares [chave,objeto] (com repeti co es dos objetos, isto e, relacionamentos um para muitos, uma chave para muitos objetos). Suporta iterador de acesso bidirecional. Ser a descrito na se ca o 34.5.
31.2.3
Containers adaptativos
S ao containers criados a partir da adapta ca o de um container de seq u encia, ou seja, pode ser constru do tendo como base um <vector>, um <list> ou um <deque>. Ser ao descritos no Cap tulo 30 - Containers Adaptativos <stack>, <queue> e <priority_queue>. <stack> Um container <stack> funciona como uma pilha LIFO (last in, rst out ) (o u ltimo que entra e o primeiro que sai). Semelhante ` a pilha de uma calculadora HP. Pode ser constru do tendo como base um <vector>, <list> (default ) ou <deque>. N ao suporta iteradores. Ser a descrito na se ca o 33.1. <queue> Um container <queue> funciona como uma la FIFO (rst in, rst out ) (o primeiro que entra e o primeiro que sai). Pode ser constru do tendo como base um <vector>, <list> (default ) ou <deque>. N ao suporta iteradores. Ser a descrito na se ca o 33.2. <priority queue> Um container <priority_queue> funciona como uma la ordenada, onde quem sai e sempre o maior valor. Os elementos est ao sempre ordenados. Pode ser constru do tendo como base um <list> ou um <deque> (default ). N ao suporta iteradores. Ser a descrito na se ca o 33.3. J a descrevemos os diferentes tipos de containers, vamos descrever a seguir alguns m etodos/func o es e operadores que s ao comuns e est ao presentes em diversos containers.
31.2.4
Alguns m etodos e operadores est ao presentes em todos os containers. Esses m etodos e operadores s ao listados na Tabela 31.1 e s ao ilustrados na Figura 31.4. Observe a presen ca de m etodos para inclus ao e elimina ca o de objetos, m etodos que retornam a dimens ao e capacidade do container. Os m etodos push_front() e push_back() s ao utilizados para adicionar ao container objetos no in cio e no m do container, respectivamente. Os m etodos pop_front(), erase() e pop_back() s ao utilizados para apagar objetos do container. Voc e pode obter c opias dos objetos utilizando front(), at() e back(). Para vericar o tamanho alocado do container, utilize capacity(), para obter o n umero de elementos utilizados, use size(), e para obter o limite m aximo que o container pode ter, utilize max_size().
31.2.5
Alguns m etodos s ao v alidos apenas para os containers seq uenciais e associativos. Esses m etodos s ao listadas a seguir. Os m etodos begin(), end(), rbegin() e rend() retornam iteradores. Veremos na se ca o 31.3 que iteradores s ao objetos ponteiros.
548
Tabela 31.1: M etodos e operadores comuns a todos os containers. M etodo construtor default construtor de c opia destrutor empty() max_size() size() swap() operator= operator< operator<= operator> operator>= operator== operator!= Descri ca o Cada container tem um conjunto de construtores v alidos. Cria um container novo, uma c opia de um existente. Destr oi o container. Retorna true se o container estiver vazio. Retorna o n umero m aximo de elementos do container (valor alocado). Retorna o n umero de elementos utilizados. Troca todos os elementos do container. Atribue os elementos de um container a outro. Retorna true se C A e menor que C B (C A e o container A e C B o container B). Uso C A < C B. Retorna true se C A e menor ou igual a C B. Uso C A <= C B. Retorna true se C A e maior que C B. Uso C A > C B. Retorna true se C A e maior ou igual a C B. Uso C A >= C B. Retorna true se C A e igual a C B. Uso C A == C B. Retorna true se C A e diferente de C B. Uso C A != C B.
31.2.6
Vimos na se ca o 9.5.1 que podemos usar typedefs para criar apelidos. Como as classes templates s ao usadas para criar tipos gen ericos (ex.: complex<float> c1;), para criar um objeto de uma classe template, tenho de usar NomeClasseGabarito<Tipo1, Tipo2,..> nomeObjeto; como no exemplo set< double, less<double> > objeto_double_set; posso criar um typedef para o comando anterior, typedef set< double, less<double> > double_set; podendo criar um objeto double_set usando: double_set objeto_double_set; Ou seja, com o uso de typedefs, podemos criar apelidos abreviados, o que facilita a digita ca o do programa. Pensando nisso, os elaboradores da STL inclu ram dentro das classes containers v arias instru co es do tipo typedef, estando algumas delas presentes em todos os containers. Estes typedefs s ao listados na Tabela 31.3. No exemplo a seguir usamos um typedef pr e-denido para criar um iterador para os elementos do container. A seguir usamos o iterador criado para varrer o container criado do in cio at e o m e enviar os valores do vetor para tela. Observe que o typedef, vector<int>::iterator e um apelido para im iterador. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
549
push_front()
push_back()
Eliminao de Objetos:
0 1 2 3 ... i n-2 n-1
pop_front()
erase(i)
pop_back()
Obteno de Objetos:
0 1 2 3 ... n-2 n-1
Dimenses e capacidades:
Exemplo: vector<int> v(10); // Cria vetor vector<int>::iterator it; // Cria iterador for(it = v.begin(); it != v.end(); it++) // Usa iterador cout < < *it < < endl; Nota: os iteradores ser ao descritos na se ca o 31.3.
31.3
O que e um iterador? Um iterador e um ponteiro inteligente, um objeto ponteiro. Os iteradores foram desenvolvidos para dar suporte aos containers j a descritos (veja se ca o 31.2). Lembre-se de que um ponteiro aponta para determinada posi ca o da mem oria, podendo ser utilizado para percorrer um vetor de objetos. Um iterador funciona da mesma maneira. Veja a seguir os diferentes tipos de iteradores e os operadores que s ao sobrecarregados para os iteradores.
31.3.1
Tipos de iteradores
Existe uma certa hierarquia entre os iteradores. Os dois mais simples s ao o input e o output, pois permitem apenas opera co es de leitura e escrita (respectivamente). A seguir vem o forward, que permite leitura e escrita (mas somente para frente). O iterador bidirecional permite leitura Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
550
Tabela 31.2: Iteradores e m etodos dos containers sequenciais. M etodo begin() end() Descri ca o Retorna um iterador (iterator ou const_iterator) para o primeiro objeto do container (posi ca o 0). Retorna um iterador (iterator ou const_iterator) para uma posi ca o posterior ao u ltimo objeto do container (este elemento n ao e utilizado e est a na posi ca o n). Retorna um iterador (iterator ou const_iterator) para o u ltimo objeto do container (posi ca o n - 1). Retorna um iterador (iterator ou const_iterator) para uma posi ca o anterior ao primeiro objeto do container (elemento n ao utilizado localizado na posi ca o -1). Apaga um ou mais objetos do container. Apaga todos os objetos do container.
rbegin() rend()
erase() clear()
e escrita tanto para frente quanto para tr as. O iterador mais poderoso e o random, que permite a leitura e escrita randomicamente.
input
forward output
bidirecional
random
Veja a seguir as caracter sticas dos iteradores: InputIterator: L e um objeto do container, move-se do in cio para o m do container (suporta somente uma passagem). OutputIterator: Escreve um objeto no container, move-se do in cio para o m do container (suporta somente uma passagem). ForwardIterator: Leitura e escrita somente para frente (suporta somente uma passagem). BidirecionalIterator: Leitura e escrita para frente e para tr as (suporta m ultiplas passagens). RandomAcessIterator: Leitura e escrita acessando randomicamente qualquer objeto do container. Dica: o acesso aos elementos de um container (como <list>, <map>, <set>) e mais r apido quando se usa um iterador. A excess ao e <vector> que e acessado mais rapidamente utilizando-se o operator[].
31.3.2
Algumas opera co es comuns aos diferentes tipos de iteradores s ao listadas a seguir: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
551
Tabela 31.3: Typedefs comuns aos diversos containers. typedef value_type size_type reference pointer iterator reverse_iterator alocator_type difference_type Descri ca o O tipo de elemento armazenado no container. Tipo usado para contar itens no container e indexar uma seq u encia de containers. Inv alido para <list>. Uma refer encia para o tipo armazenado no container. Um ponteiro para o tipo armazenado no container. Um iterador para o tipo armazenado no container. Um iterador reverso para o tipo armazenado no container. Tipo de gerenciamento de mem oria utilizado. N umero de elementos entre dois iteradores. N ao denido para os containers <list> e adaptativos (<stack>, <queue>, <priority_queue>). Um ponteiro constante para o tipo armazenado no container. Um iterador constante para o tipo armazenado no container. Um iterador reverso constante para o tipo armazenado no container.
Iteradores de leitura (InputIterator) ++it it++ *it it = it1 it == it1 it != it1 Pr e-incremento (avan ca para pr oximo elemento do container). P os-incremento (avan ca para pr oximo elemento do container). Retorna objeto (desreferencia ponteiro). Atribue um iterador a outro. Compara se dois iteradores s ao iguais. Compara se dois iteradores s ao diferentes.
Iteradores de escrita (OutputIterator) ++it it++ *it it = it1 Pr e-incremento. Pos-incremento. Retorna objeto (desreferencia ponteiro). Atribue um iterador a outro.
Iteradores de avan co (ForwardIterator) ++it it++ *it it = it1 Pr e-incremento. Pos-incremento. Retorna objeto (desreferencia ponteiro). Atribue um iterador a outro. Andr e Duarte Bueno
Iteradores bidirecionais (BidirecionalIterator) ++it it++ - -it it- Pr e-incremento. Pos-incremento. Pr e-decremento (retorna para elemento anterior do container). P os-decremento.
Iteradores randomicos (RandomAcessIterator) ++it it++ it += i it -= i it + i it - i it[i] it1 < it2 Pr e-incremento. Pos-incremento. Iterador avan ca i posi co es. Iterador recua i posi co es. Retorna iterador avan cado i posi co es de it. Retorna iterador recuado i posi co es de it. Retorna refer encia ao objeto i. Verdadeiro, se it1 aponta para elemento anterior a it2.
it1<= it2 Verdadeiro, se it1 aponta para elemento anterior/igual a it2. it1 > it2 Verdadeiro, se it1 aponta para elemento acima de it2.
it1 >= it2 Verdadeiro, se it1 aponta para elemento acima/igual a it2. A utiliza ca o dos iteradores ser a esclarecida por meio dos exemplos, veja listagens 32.1, 34.2, 32.3, 35.1.
31.4
31.4.1
Iteradores de inser c ao
Algoritmos gen ericos como copy() n ao inserem novos elementos no container, os mesmos substituem os elementos antigos pelos novos. Com o objetivo de possibilitar a inclus ao de novos elementos em um container, a STL inclui iteradores espec cos para inser ca o de elementos, s ao eles: insert iterator(); Chama insert(pos,valor), para inserir o valor na posi ca o pos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
553
back insert iterator(); Chama push_back(valor), para inserir o valor no nal do container. front insert iterator(); Chama push_front(valor), para inserir o valor no in cio do container. O exemplo da listagem ?? mostra o uso de insert_iterator e de fun ca o predicado. Criamos a fun ca o predicado bool MaiorQue50(int valor), que retorna verdadeiro se valor for maior que 50. A seguir denimos uma fun ca o SeparaValores(), a mesma usa o iterador it do tipo back_insert_iterator. A fun ca o gen erica remove_copy_if() recebe v1, o iterador it e a fun ca o predicado, quando MaiorQue50() retorna verdadeiro, o valor de v1 e copiado para v2. Observe na sa da que os valores de v1 que n ao satisfazem a fun ca o predicado s ao inseridos em v2. Listing 31.1: Usando insert_iterator e fun ca o predicado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 # include < iostream > # include < iomanip > # include < vector > # include < algorithm > # include < iterator > # include < functional > using namespace std ; // Fun c~ a o predicado , r e t o r n a true se valor > 50 bool MaiorQue50 ( int valor ) { return valor > 50; } // Recebe um vetor v1 e r e t o r n a v2 . vector < int > S e p a r a V e t o r e s ( vector < int >* v1 ) { vector < int > v2 ; // Cria i t e r a d o r de i n s e r c~ a o para v2 back_insert _ it e ra t o r < vector < int > > it ( v2 ) ; r e m o v e _ c o p y _ i f ( v1 - > begin () , v1 - > end () , it , MaiorQue50 ) ; return v2 ; } // S o b r e c a r g a operador < < como fun c~ ao template template < typename T > ostream & operator < <( ostream & os , vector <T > v ) { for ( int i = 0; i < v . size () ; i ++) os << v [ i ] << endl ; return os ; } int main () { // T e s t a n t o a fun c~ ao predicado cout << " MaiorQue50 (100) = " << MaiorQue50 (100) << " \ nMaiorQue5 0 ( 10) = " << MaiorQue50 ( 10) << endl ; // Cria v1 e a d i c i o n a v a l o r e s vector < int > v1 ; int data ; do { cout << " \ nEntre com o dado ( " << setw (3) << v1 . size () << " ) : " ; cin >> data ; cin . get () ;
554
46 47 48 49 50 51 52 53 54 55 if ( cin . good () ) v1 . push_back ( data ) ; } while ( cin . good () ) ;
cout << " \ nVetor v1 antes de S e p a r a V e t o r e s () :\ n " << v1 << endl ; vector < int > v2 ( S e p a r a V e t o r e s (& v1 ) ) ; cout << " Vetor v1 depois de S e p a r a V e t o r e s () :\ n " << v1 << " Vetor v2 depois de S e p a r a V e t o r e s () :\ n " << v2 << endl ; return 0; } [ b u e n o @ l d s c 0 5 Parte - III ] $ ./ a . out MaiorQue5 0 (100) = 1 MaiorQue5 0 ( 10) = 0 Entre Entre Entre Entre Entre com com com com com o o o o o dado dado dado dado dado ( ( ( ( ( 0) :50 1) :100 2) :150 3) :30 4) : S e p a r a V e t o r e s () :
31.5
Sempre compare iteradores usando != e n ao <, pois o operador < s o esta sobrecarregado para iteradores rand omicos. Ao usar incremento e decremento com iteradores, prera as vers oes pr e-xadas. Isto e, troque it++ por ++it e it- - por - -it. Pode-se iterar do u ltimo elemento para o primeiro elemento do container usando-se um reverse_iterator ou um const_reverse_iterator. Os containers que suportam o uso de iteradores bidirecionais aceitam o uso de insert_iterator, back_insert_iterator e front_insert_iterator para inserir elementos em um container. Veja listagem listagm 31.1. Como a STL faz parte da biblioteca-padr ao de C++, todas as distribui co es de C++ devem inclu -la, de forma que usar a STL garante maior portabilidade aos seus programas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
555
31.6
Fun c ao predicado
Um predicado e uma fun ca o que recebe como par ametro um elemento do container, realiza determinada opera ca o e retorna o valor true/false. O prot otipo e um exemplo de uso de uma fun ca o predicado e apresentado a seguir: Prot otipo: bool fun c~ aoPredicado(Tipo x); Exemplo: bool MaiorQue10(int x) { return x > 10; }
31.7
Apresentamos neste cap tulo a STL, a biblioteca padr ao de gabaritos de C++, suas caracter sticas e componentes. Iniciamos com uma introdu ca o aos diferentes tipos de containers: os containers seq uenciais <vector>, <list>, <deque>, os containers adaptativos <stack>, <queue>, <priority_queue>, e os containers associativos <set>, <multiset>, <map>, <multimap>. Aprendemos a diferenciar os containers e a identicar qual devemos utilizar. Vimos ainda os m etodos e operadores que s ao comuns aos diversos containers, isto e, os m etodos que est ao presentes em todos os containers, sendo muito utilizados. Observe que o fato de terem os mesmos nomes nos diferentes containers facilita seu uso, pois temos de decorar poucos nomes. Aprendemos que alguns m etodos s ao v alidos apenas para os containers seq uenciais. Vimos ainda as deni co es de tipo - typedefs - que s ao comuns aos diversos containers. No nal do cap tulo vimos uma introdu ca o aos iteradores (iterators), os famosos - ponteiros inteligentes - seus tipos e opera co es comuns. Nos pr oximos cap tulos iremos aprender a utilizar em detalhes os containers, os iteradores e os c odigos gen ericos. Nota: veja no Ap endice I - Links para Sites em C++, um conjunto de endere cos de sites que descrevem a STL em detalhes.
31.8
Exerc cios
1. Comente as caracter sticas da STL. 2. Para um sistema de processamento de dados de uma conta corrente de um banco, qual tipo de container deve ser utilizado? 3. Qual o container ideal para acesso aleat orio? 4. Preciso incluir e eliminar objetos o tempo todo, qual container devo selecionar? 5. Vou montar um programa que simula uma calculadora HP, qual container devo utilizar? 6. Quais os m etodos comuns a todos os containers? 7. O que faz o m etodo begin(). 8. Qual a vantagem do uso de typedefs com containers? 9. Fa ca uma lista dos iteradores e suas caracter sticas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
556
Cap tulo 32
32.1
J a apresentamos brevemente a classe container <vector> nas se co es 9.4.2 e 31.2.1. O container <vector> funciona como um vetor comum, ou seja, os blocos com os elementos est ao cont guos, permitindo acesso aleat orio (iteradores rand omicos). Como em vetores comuns de C, <vector> n ao verica os ndices. Para usar um objeto container do tipo <vector>, inclua o arquivo de cabe calho <vector>. Exemplo: #include <vector> A classe container <vector> e uma classe template declarada da forma: template < typename Tipo, typename Allocator=allocator<Tipo> > class vector{...}; ou seja, recebe o tipo de elemento a ser armazenado e o tipo de aloca ca o a ser utilizada. Veja a seguir os diversos m etodos disponibilizados por <vector>. Primeiro, veremos os construtores, os iteradores e as refer encias, e, depois, os m etodos usuais de <vector>. A Figura 32.1 apresenta um diagrama mostrando os m etodos para inclus ao, obten ca o e elimina ca o de objetos em um container <vector>. 557
558
Nota: na descri ca o dos m etodos, nos prot otipos e exemplos apresentados nesta parte do livro procuramos adotar um padr ao. T e um tipo qualquer, um sin onimo para Tipo; size_type e a dimens ao dos objetos armazenados no container; x,y,z, e e1,e2,e3, s ao elementos do container; n,pos indica uma posi ca o a ser acessada; c,co,c1,c2,c3 s ao objetos containers; cd, d, dest e o container destino; it, it1, it2 s ao iteradores que apontam para elementos do container no intervalo [first, last), ou seja, inclui first e exclue last. O iterador first aponta para o primeiro elemento do container (o mesmo que v.begin()). O iterador last aponta para o elemento n do container, elemento inv alido (o mesmo que v.end()). fpred e uma fun ca o predicado, e uma fun ca o que recebe um elemento do container, realiza determinada opera ca o e retorna 0 ou 1. Alloc e um objeto do tipo allocator_type, usado para aloca ca o de mem oria.
push_back()
Eliminao de Objetos:
0 1 2 3 i n-2 n-1
erase(i)
pop_back()
Obteno de Objetos:
0 1 2 3 ... n-2 n-1
espao reservado
Dimenses e capacidades:
size() capacity() max_size() reserve()
32.1.1
Construtores e destrutor
vector<Tipo> (); Cria um vetor para o tipo T com tamanho zero. Complexidade constante. Exemplo: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
559
vector<Tipo> (size type n, const T& x = T()); Cria um vetor para o tipo com tamanho n, com n c opias do valor T(). Se o valor do elemento x n ao for passado, utiliza o construtor default da classe para construir o objeto. Complexidade linear. No exemplo a seguir v_float1 tem 17 elementos, todos iguais a 3.55. Exemplo: vector< int > v_int2 (15); vector< float > v_float1 (17,3.55); vector<Tipo> (const vector<T>& v); Construtor de c opia, cria uma c opia do vetor v. Exemplo: vector< float > v_float2 (v_float1); vector<Tipo> (InputIterator rst, InputIterator last); Cria um vetor com o tamanho dado pela diferen ca last-rst, com os valores a partir de rst. Observe que rst se refere ao primeiro elemento do container a ser considerado, e last se refere ao ultimo elemento (last n ao e inclu do no container). Complexidade linear. Exemplo: vector< float > v_float3 (v_float1.begin(), v_float1.end()); vector (); Destrutor de < vector >. Complexidade linear.
32.1.2
Iteradores de <vector>
A chamada a um m etodo que retorna um iterador, como begin(), ou end() (veja Figura 32.2), ir a retornar um const_iterator se o objeto destino e do tipo const. Um const_iterator pode ser utilizado para acessar os elementos do container no modo ready-only. A Figura 32.2 apresenta um diagrama mostrando os m etodos que retornam iteradores. Por exemplo, o m etodo begin() retorna um iterator que aponta para o primeiro elemento do container. A maioria das fun co es gen ericas recebe como par ametros os iteradores begin() e end() e usa-os para varrer todo o container. Observe que as fun co es s ao executadas para begin(), porque begin() aponta para o primeiro elemento do container, e n ao s ao executadas para end(), porque end() aponta para um elemento inv alido (veja Figura 32.2). Nota: todos os m etodos abaixo tem complexidade constante. iterator begin(); Retorna um iterador rand omico para o primeiro objeto do container (veja Figura 32.2). iterator end(); Retorna um iterador rand omico para posi ca o n (elemento inv alido). reverse iterator rbegin(); Retorna um iterador rand omico reverso para o u ltimo objeto v alido (posi ca o n-1). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
560
-1
...
n-2
n-1
reverse iterator rend(); Retorna um iterador rand omico para posi ca o -1 (elemento inv alido). const iterator begin() const; Retorna um iterador rand omico e constante para posi ca o 0. const iterator end() const; Retorna um iterador rand omico e constante para posi ca o n (elemento inv alido). const reverse iterator rbegin() const; Retorna um iterador rand omico reverso constante para o u ltimo objeto v alido (posi ca o n-1). const reverse iterator rend() const; Retorna um iterador rand omico e constante para posi ca o -1 (elemento inv alido).
32.1.3
reference front(); Retorna uma refer encia ao primeiro elemento (veja Figura 32.1). operator[] (size type n); Retorna uma refer encia ao objeto armazenado na casa n (n ao verica o intervalo). S o e v alido para <vector> e <deque>. at(size type n); Retorna uma refer encia ao objeto n; at() testa o intervalo. reference back(); Retorna uma refer encia ao u ltimo elemento. const reference front() const; Retorna uma refer encia constante ao primeiro elemento. const reference operator[] (size type n) const; Retorna uma refer encia constante ao objeto n (veja Figura 32.1). const reference at(size type n) const; Retorna uma refer encia constante ao objeto n (veja Figura 32.1). const reference back() const; Retorna uma refer encia constante ao u ltimo elemento (veja Figura 32.1). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
561
32.1.4
Operadores
vector<T>& operator= (const vector<T>& v); Operador de atribui ca o. Apaga todos os elementos do container e depois copia os valores de v para o container this. Retorna uma refer encia para o conjunto. Complexidade linear.
32.1.5
Capacidade e redimensionamento
Todos os m etodos desta se ca o tem complexidade constante. size type size() const; Retorna o n umero de elementos utilizados pelo container (veja Figura 32.1). size type capacity() const; Retorna o tamanho alocado do container (mem oria alocada) (veja Figura 32.1). size type max size() const; Retorna o tamanho do maior vetor poss vel. Depende da quantidade de mem oria dispon vel em seu computador (veja Figura 32.1). void reserve(size type sz); Dene a capacidade do container em sz elementos. Muda a capacidade do container mas u n ao muda o size. E til quando voc e sabe que ir a adicionar um determinado n umero de elementos ao container, pois evita a realoca ca o do container a cada nova inclus ao. Se sz for menor que a capacidade atual do container, a realoca ca o n ao e realizada (veja Figura 32.1). void resize(size type sz, T e = T()); Altera o tamanho do container (o size). Se o novo tamanho (sz) for maior que o atual, os novos elementos s ao inseridos no nal do vetor. Se o novo tamanho for menor que o atual, os elementos excedentes s ao eliminados. bool empty() const; Retorna true se o container est a vazio.
32.1.6
A Figura 32.1 apresenta um diagrama mostrando os m etodos para inclus ao, obten ca o e elimina ca o de objetos em um container <vector>. iterator insert(iterator pos, const T& x = T()); Insere o objeto x, antes da posi ca o pos denida pelo iterador. void insert(iterator pos, size type n, const T& x = T()); Insere n c opias de x antes da posi ca o pos. void insert(iterator pos, InputIterator rst, InputIterator last); Insere c opia dos elementos no intervalo [rst, last) antes da posi ca o pos. void push back(const T& x); Insere uma c opia de x no nal do container. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
562 void erase(iterator pos); Remove o elemento da posi ca o pos. Exemplo: v.erase ( v.begin() + 5 );
void erase(iterator rst, iterator last); Remove os elementos no intervalo [inclusive rst, excluindo last), ou seja, de rst a last-1. A complexidade e fun ca o do tipo de container. void pop back(); Remove o u ltimo elemento (sem retorno). void clear(); Apaga todos os elementos do container. Complexidade linear. void assign(InputIterator rst, InputIterator last); Apaga todos os elementos do container e insere os novos elementos do intervalo [rst, last). void assign(Size n, const T& x = T()); Apaga todos os elementos do container e insere os n novos elementos com o valor de x. void swap(vector<T>& v); Troca os elementos dos dois containers ( e mais r apida que a swap gen erica). Complexidade constante. Exemplo: v1.swap(v2);
32.1.7
Operadores sobrecarregados
bool operator== (const vector<T>& v1, const vector <T>& v2); O operador == retorna true se o container v1 e igual ao container v2 (se cada elemento e igual). bool operator< (const vector<T>&v1, const vector<T>& v2); O operador < retorna true se os elementos contidos em v1 s ao lexicographically menores que os elementos contidos em v2. Os outros operadores sobrecarregados s ao: !=, <=, >=. Dica: para que qualquer um dos operadores ==, !=, possam ser utilizados, e necess ario que o tipo armazenado tenha suporte ao operador (==). Para que qualquer um dos operadores >, <, >=, <=, possam ser utilizados e necess ario que o tipo armazenado tenha suporte ao operador <.
32.1.8
Exemplo de <vector>
Neste momento, voc e pode rever o exemplo de <vector> apresentado na listagem 9.8. A listagem 32.1 mostra a utiliza ca o de <vector>.
563
int data ; cout << " No DOS um ctrl + z encerra a entrada de dados .\ n " << " No Mac um ctrl + d encerra a entrada de dados .\ n " << " No GNU / Linux um ctrl + d encerra a entrada de dados .\ n " ; do { cout << " \ nEntre com o dado ( " << setw (3) << v . size () << " ) : " ; cin >> data ; cin . get () ; if ( cin . good () ) v . push_back ( data ) ; } while ( cin . good () ) ; cout << " \ n " << v << endl ; v [0] = 23427; v . insert ( v . begin () + 2 , 5463) ; cout << " \ nAp o s v [ 0 ] = 23427; e v . insert ( v . begin () + 2 , 5463 ) ;\ n " << v << endl ; // Chama fun c~ a o erase () do objeto v p a s s a n d o p o s i c~ a o v . begin () v . erase ( v . begin () ) ; cout << " \ nAp o s v . erase ( v . begin () ) ;\ n " << v << endl ; // Chama v . erase ( cout << << fun c~ a o erase () do objeto v p a s s a n d o v . begin () +1 e v . end () -1 v . begin () +1 , v . end () -1) ; " \ nAp o s v . erase ( v . begin () +1 , v . end () -1 ) ;\ n " " o vetor esta " << ( v . empty () ? " vazio " : " com elementos " ) << endl ;
// Chama fun c~ a o clear () v . clear () ; cout << " o vetor esta " << ( v . empty () ? " vazio " : " com elementos " ) << endl ; return 0; } // D e f i n i c~ a o da s o b r e c a r g a do o p e r a d o r << para m o s t r a r e l e m e n t o s do vetor . ostream & operator < < ( ostream & os , const vector < int >& v ) { for ( int i = 0; i < v . size () ; i ++) os << " v [ " << setw (3) << i << " ]= " << setw (5) << v [ i ] << ; return os ; }
[ a n d r e @ m e r c u r i o Cap4 - STL ] $ g ++ ex - vector -2. cpp [ a n d r e @ m e r c u r i o Cap4 - STL ] $ ./ a . out No DOS um ctrl + z encerra a entrada de dados . No Mac um ctrl + d encerra a entrada de dados . No GNU / Linux um ctrl + d encerra a entrada de dados . Entre com o dado ( 0) :0 Entre com o dado ( 1) : -1
564
Entre com o dado ( 2) : -2 Entre com o dado ( 3) : -3 Entre com o dado ( 4) : v [ 0]= 0 v [ 1]= -1 v [
2]=
-2 v [
3]=
-3
Ap o s v [ 0 ] = 23427; e v . insert ( v . begin () + 2 , 5463 ) ; v [ 0]=23427 v [ 1]= -1 v [ 2]= 5463 v [ 3]= -2 v [ 4]= Ap o s v . erase ( v . begin () ) ; v [ 0]= -1 v [ 1]= 5463 v [
-3
2]=
-2 v [
3]=
-3
Ap o s v . erase ( v . begin () +1 , v . end () -1 ) ; o vetor esta com elementos o vetor esta vazio
Reveja agora a listagem 30.5 que mostra o uso de <vector> com <bitset>.
32.1.9
Se n ao for mudar o container, utilize iteradores do tipo const. Note que v.begin() retorna um iterador normal ou constante, veja o exemplo: Exemplo: vector<int> v(10); // Retorna iterador normal vector<int>::iterator it = v.begin(); // Retorna iterador constante vector<int>::const_iterator cit = v.begin(); Sempre reserve um espa co inicial para o vetor, ou seja, procure evitar a realoca ca o a cada inser ca o, alocando todo o bloco que ir a utilizar de uma u nica vez. Os m etodos devem receber <vector> como refer encia para evitar c opias desnecess arias. Exemplo: void funcao(vector<int> & v); Se a classe n ao tem um construtor default, um <vector> s o pode ser criado passando-se o construtor com par ametros. Exemplo: // Construtor com par^ ametros class TUsuario{ TUsuario(int x){...}; }; vector< TUsuario > vet( 200, TUsuario(5) ); Os m etodos assign() s ao utilizados complementarmente aos construtores. O n umero de elementos do vetor ser a aquele passado para assign(). Se o m etodo espera um iterator, voc e n ao deve passar um reverse_iterator. Para converter um reverse_iterator em um iterator, utilize o m etodo base(). Exemplo: reverse_iterator ri; iterator it = ri.base(); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
32.2. A CLASSE CONTAINER <LIST> Se for inserir objetos no meio do vetor, pense em utilizar uma lista (<list>). A classe <vector> n ao possui os m etodos push_front(), pop_front() e front(). Para retornar um vetor de inteiros como refer encia: Exemplo: vector<int>& NomeM etodo(vector<int>& v) {... return v;}
565
O operador ++it retorna uma refer encia ao elemento do container. O operador it++ retorna uma c opia do elemento do container. Para evitar aloca co es desnecess arias ao usar push_back(), reverve um espa co m nimo com reserve(). Para saber o n umero de elementos alocados mas n ao utilizados use capacity()-size(). Observe que a classe string se comporta como um vetor de caracteres. Os containers j a v em com os operadores < e == sobrecarregados. Voc e pode sobrecarregar >, !=, <= e >=, ou utilizar o comando using namespace std::rel_ops; para incluir a sobrecarga desses operadores. Exemplo: #include <utility> using namespace std::rel_ops; Observe que <vector> e <deque> s ao acessados mais rapidamente com o operador[], <list>, <map>, e <set> s ao acessados mais rapidamente utilizando um iterador.
32.2
Utilize <list> quando precisar de um container em que novos objetos podem ser inclu dos em qualquer posi ca o. A Figura 32.3 mostra os m etodos disponibilizados para <list>. O container <list> e lento para acesso rand omico, mas e otimizado para inser ca o e remo ca o de elementos em qualquer posi ca o (<list> suporta iterador bidirecional). Um <list> fornece todos os m etodos de um <vector>, com exce ca o de at[], capacity() e reserve(), e acrescenta m etodos novos, como front(), push_front(), pop_front() e insert(pos,elem). <list> n ao tem o operador[], e os iteradores de <list> n ao suportam opera co es aritm eticas, como it+5.
32.2.1
Construtores e destrutor
list(); Cria uma lista vazia. list(size type n, const T& x = T()); Cria uma lista com tamanho n, com n c opias do valor x. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
566
...
n-2
n-1
front() push_front()
back()
push_back()
Eliminao de Objetos:
0 1 n-2 n-1
pop_back() pop_front()
Dimenses e capacidades:
size() max_size()
list(InputIterator rst, InputIterator last); Cria uma lista do tamanho de last-rst, com os valores de [rst a last). list(const list<T>& l); Cria uma c opia da lista l (construtor de c opia). list(); Destrutor de <list>.
32.2.2
Operadores
list<T>& operator= (const list<T>& l) Operador de atribui ca o. Apaga todos os elementos do container e depois copia os valores de l para o container this. Retorna uma refer encia para o conjunto.
32.2.3
reference front(); Retorna uma refer encia para o primeiro elemento. Veja Figura 32.3. void pop front(); Remove o primeiro elemento. Veja Figura 32.3. push front(const T& x); Adiciona uma c opia de x no in cio da lista (novo primeiro elemento). Veja Figura 32.3.
32.2.4
void splice(iterator pos, list<T>& l); Insere a lista l antes da posi ca o pos denida pelo iterador. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
32.2. A CLASSE CONTAINER <LIST> void splice(iterator pos, list<T>& l, iterator it); Move de list[i] para posi ca o pos.
567
void splice(iterator pos, list<T>& l, iterator rst, iterator last); Move os elementos no intervalo [rst, last) da lista l para esta lista, inserindo o elemento antes da posi ca o pos. void merge(list<T>& l); Mistura esta lista com a lista l, os valores s ao ordenados com o operador <. Se existirem elementos iguais nas duas listas, os elementos desta lista precedem, a lista l car a vazia. void merge(list<T>& l, Compare comp); Mistura esta lista com a lista l; usando fun ca o de compara ca o. Se existirem elementos iguais nas duas listas, os elementos desta lista (this) precedem, e a lista l car a vazia. void sort(); Ordena de acordo com o operador <. Elementos iguais s ao mantidos na mesma ordem. void sort(Compare comp); Ordena a lista de acordo com a fun ca o de compara ca o comp. void insert(iterator pos, Tipo obj); Insere na posi ca o pos o objeto.
32.2.5
void unique(); Move todos os elementos repetidos para o m do container e seta size como sendo o ndice do u ltimo elemento n ao duplicado. Antes de executar unique(), execute um sort(). void unique(Fun c aoPredicado fpred); Apaga elementos consecutivos com a condi ca o true dada pela fun ca o predicado fpred. A primeira ocorr encia n ao e eliminada. Exemplo: bool MaiorQue10(int x) { return x > 10; } ... lista.unique(MaiorQue10); void remove(const T& x); Remove os elementos do container que t em o valor x. c aoPredicado fpred); void remove if(Fun Remove os elementos do container que satisfazem ` a fun ca o predicado fpred. Exemplo: // Remove da lista os objetos que tem a primeira letra ==p. list.remove_if( initial(p) ); void reverse(); Inverte a ordem dos elementos do container. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
568
32.2.6
Exemplo de <list>
Veja na listagem 32.2 um exemplo de utiliza ca o de <list>. Observe na fun ca o de sobrecarga do operador de extra ca o (< <) o uso de um iterador. A listagem 32.2 inicia-se declarando a fun ca o de sobrecarga do operador < <; esta recebe uma ostream (como cout) e uma refer encia para um container do tipo lista para n umeros float (const std::list<float>& list). Como dito anteriormente, cada container fornece iteradores para acesso aos seus elementos. Neste exemplo, a linha std::list<float>::const_iterator it; e utilizada para criar um iterador do tipo std::list<float>::const_iterator com o nome it. Dentro do for, o iterador it que inicialmente aponta para o primeiro elemento do container it=lista.begin(); e utilizado para percorrer os elementos do container usando it++ e envi a-los para a sa da os < < *it < < ;. Quando o iterador it chegar ao m do container, isto e, it != lista.end(), o for e encerrado. Listing 32.2: Usando <list>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 # include # include # include # include < iostream > < string > < list > < algorithm > // Listas // A l g o r i t m o g e n erico
using namespace std ; // D e c l a r a c~ a o da s o b r e c a r g a do o p e r a d o r de e x t r a c~ a o << para list // Mostra lista . Com vector foi p o s s v e l usar v [ i ] , uma lista n~ a o aceita l [ i ] , // p r e c i s a de um iterator , como a seguir . template < typename T > ostream & operator << ( ostream & os , const std :: list < T >& lista ) { typename std :: list < T >:: c o n s t _ i t e r a t o r it ; for ( it = lista . begin () ; it != lista . end () ; it ++) os << * it << ; return os ; } // D e f i n i c~ a o da fun c~ a o main () int main () { string linha = " \n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\ n " ; // C r i a c~ a o de uma lista para float std :: list < float > clist ; clist . push_front (312.1 f ) ; // Inclui v a l o r e s na lista clist . push_back (313.4 f ) ; clist . push_back (316.7 f ) ; clist . push_front (312.1 f ) ; clist . push_front (313.4 f ) ; clist . push_front (314.1 f ) ; clist . push_front (315.1 f ) ; cout << linha << " Conte u do do container : \ n " << clist << linha << endl ; // E l i m i n a p r i m e i r o e l e m e n t o da lista clist . pop_front () ; cout << " Conte u do do container ap o s : clist . pop_front () ; \ n " << clist << linha << endl ; // E l i m i n a u ltimo e l e m e n t o da lista clist . pop_back () ; cout << " Conte u do do container ap o s : clist . pop_back () ; \ n " << clist << linha << endl ;
569
// Ordena o c o n t a i n e r clist . sort () ; cout << " Conte u do do container ap o s : clist . sort () ; \ n " << clist << linha << endl ; // Move os e l e m e n t o s r e p e t i d o s para o final do c o n t a i n e r // e seta como u ltimo e l e m e n t o v a lido , o u ltimo e l e m e n t o n~ ao repetido. clist . unique () ; cout << " Conte u do do container ap o s : clist . unique () ; \ n " << clist << linha << endl ; return 0; }
[ a n d r e @ m e r c u r i o Cap4 - STL ]# ./ a . out -------------------------------------------------Conte u do do container : 315.1 314.1 313.4 312.1 312.1 313.4 316.7 -------------------------------------------------Conte u do do container ap o s : c o n t a i n e r _ l i s t . pop_front () ; 314.1 313.4 312.1 312.1 313.4 316.7 -------------------------------------------------Conte u do do container ap o s : c o n t a i n e r _ l i s t . pop_back () ; 314.1 313.4 312.1 312.1 313.4 -------------------------------------------------Conte u do do container ap o s : c o n t a i n e r _ l i s t . sort () ; 312.1 312.1 313.4 313.4 314.1 -------------------------------------------------Conte u do do container ap o s : c o n t a i n e r _ l i s t . unique () ; 312.1 313.4 314.1 --------------------------------------------------
Na listagem 32.3 apresentamos o uso de m etodos de <list> como sort(), splice(), merge(), unique(), swap(), assign(), e remove(). No Cap tulo 22 - Entrada e Sa da, aprendemos que as streams s ao utilizadas para enviar e receber dados. Que uma ostream e uma stream utilizada para sa da de dados (output stream ). Vimos que um iterator e uma esp ecie de ponteiro inteligente utilizado para acessar os diversos objetos armazenados no container. Da , conclu mos que um ostream_iterator e um iterador que ser a utilizado para percorrer os elementos do container e os enviar para uma sa da. No exemplo da listagem 32.3, criamos um ostream_iterator na linha: std::ostream_iterator < float > output (cout, " "); e usamos a fun ca o gen erica copy(), para copiar todos os elementos do container para a sa da out. O caracter " " e utilizado como separador. copy (clist1.begin(), clist1.end(), output); A fun ca o copy() e uma fun ca o gen erica (apresentada no Cap tulo 35 - Algoritmos Gen ericos), que ir a percorrer o container do in cio (cset.begin()) ao m (cset.end()), utilizando o iterador out, que envia cada objeto do container para a tela usando cout. Listing 32.3: Usando <list> com as fun co es gen ericas (algoritmos gen ericos).
1 2 3 4 # include < iostream > # include < list > # include < iterator > using namespace std ; // Classe de listas // I t e r a d o r e s // Uso do n a m e s p a c e std
570
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
int main () // D e f i n i c~ a o da fun c~ a o main () { // Cria um i t e r a d o r para ostream , usa cout para enviar floats para tela o s t r e a m _ i t e r a t o r < float > output ( cout , " " ) ; // C r i a c~ a o de duas listas para float std :: list < float > clist1 , clist2 ; // Inclui v a l o r e s na lista clist1 . push_front (312.1 f ) ; clist1 . push_front (312.1 f ) ; clist1 . push_back (313.4 f ) ; clist1 . push_back (316.7 f ) ; // Mostra lista cout << " \ nConte u do do container clist1 : " ; copy ( clist1 . begin () , clist1 . end () , output ) ; // Ordena lista clist1 . sort () ; cout << " \ nConte u do do container clist1 ap o s sort () : " ; copy ( clist1 . begin () , clist1 . end () , output ) ; // A d i c i o n a e l e m e n t o s a lista2 clist2 . push_front (22.0) ; clist2 . push_front (2222.0) ; cout << " \ nConte u do do container clist2 ap o s push_front () : " ; copy ( clist2 . begin () , clist2 . end () , output ) ; // Fun c~ a o splice ( A d i c i o n a ao final de clist1 os v a l o r e s de clist2 ) clist1 . splice ( clist1 . end () , clist2 ) ; cout << " \ nConte u do do container clist1 ap o s splice () : " ; copy ( clist1 . begin () , clist1 . end () , output ) ; // M i s t u r a as duas listas , c o l o c a n d o tudo em clist2 clist1 . merge ( clist2 ) ; cout << " \ nConte u do do container clist1 ap os copy ( clist1 . begin () , clist1 . end () , output cout << " \ nConte u do do container clist2 ap os copy ( clist2 . begin () , clist2 . end () , output clist1 e e l i m i n a n d o tudo de
// E l i m i n a v a l o r e s d u p l i c a d o s clist1 . unique () ; cout << " \ nConte u do do container clist1 ap o s unique () : " ; copy ( clist1 . begin () , clist1 . end () , output ) ; // Chama f u n c~ oes pop_front e pop_back clist1 . pop_front () ; // E l i m i n a p r i m e i r o e l e m e n t o da lista clist1 . pop_back () ; // E l i m i n a ultimo e l e m e n t o da lista cout << " \ nConte u do do container clist1 ap o s pop_front () e pop_back () : " ; copy ( clist1 . begin () , clist1 . end () , output ) ; // Troca tudo entre as duas listas clist1 . swap ( clist2 ) ; cout << " \ nConte u do do container clist1 ap os copy ( clist1 . begin () , clist1 . end () , output cout << " \ nConte u do do container clist2 ap os copy ( clist2 . begin () , clist2 . end () , output // A t r i b u i v a l o r e s de clist2 em clist1
571
";
32.2.7
Uma lista n ao aceita (iterator + n). Voc e precisa fazer iterator++, n vezes. Objetos eliminados de <list> s ao deletados. <list> n ao aceita subscript[], reserve() e capacity(). <list> inclui splice(pos,& x); move o objeto x para a posic ao pos. Utilize <list> sempre que precisar de inser ca o e remo ca o r apida. Utilize merge(list & ); para mesclar listas. Para criar uma lista de vetores: Exemplo: std::list< std::vector<int> > nomeLista;
32.3
Um container <deque> e uma la com duas extremidades. Une parte das vantagens das listas <list> e dos vetores <vector>. Tem r apida inser ca o na frente e atr as. De uma maneira geral s ao alocados blocos de mem oria que s o s ao deletados quando o container e destru do. Tem os mesmos m etodos de <vector>, mas adiciona push_front() e pop_front() e suporta iteradores rand omicos. A Figura 32.4 mostra os m etodos disponibilizados para <deque>. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
572
push_front()
push_back()
Eliminao de Objetos:
0 1 2 3 i ...n-2 n-1
pop_front() erase(i)
pop_back()
Obteno de Objetos:
0 1 2 3 ... n-2 n-1
front()
back()
Dimenses e capacidades:
size() capacity() max_size() reserve()
32.3.1
Construtores e destrutor
deque(); Construtor default, cria container vazio. deque(size type n, const T& x = T()); Cria container com n elementos contendo n c opias de x. deque(const deque<T>& d); Construtor de c opia, cria uma c opia do deque d. deque(InputIterator rst, InputIterator last); Cria um deque do tamanho de last - rst, preenchido com os valores de [rst a last). deque(); Destrutor. Nota: os m etodos v alidos para <vector> s ao v alidos para <deque>. Veja se ca o 32.1.
32.3.2
Exemplo de <deque>
Veja na listagem 32.4 exemplo de uso de <deque>. A listagem inicia com a cria ca o de uma fun ca o global template que sobrecarrega o operador< <. A fun ca o e usada para enviar os elementos do <deque> para sa da. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
573
// A d i c i o n a r no inicio // A d i c i o n a r no fim
cout << " Dimens~ a o do container deque = " << cdeque . size () << " \ nConte u do do container deque : \ n \ t " << cdeque << endl ; // S e t a n d o um e l e m e n t o do c o n t a i n e r d i r e t a m e n t e cdeque [2] = string ( " e mar com belezas sem par . " ) ; cout << " Conte u do do container deque ap o s atribui ca ~ o direta :\ n \ t " << cdeque << endl ; // R e t i r a n d o p r i m e i r o e l e m e n t o do deque cdeque . pop_front () ; cout << " Conte u do do container deque ap o s um pop_front () :\ n \ t " ; for ( int i = 0; i < cdeque . size () ; ++ i ) cout << cdeque [ i ] << ; cout << endl ; return 0; }
Dimens~ a o do container deque = 3 Conte u do do container deque : Floriano p o l i s Cidade de sol e mar . Conte u do do container deque ap o s atribui ca ~ o direta : Floriano p o l i s Cidade de sol e mar com belezas sem par . Conte u do do container deque ap o s um pop_front () : Cidade de sol e mar com belezas sem par .
32.4
Neste cap tulo aprendemos a utilizar os containers seq uenciais <vector>, <list> e <deque>. O container <vector> foi apresentado em detalhes. Aprendemos a criar um <vector> utilizando o construtor default ou o construtor de c opia. Vimos que os iteradores mais utilizados s ao retornados pelos m etodos begin(); e end();. Com front(); obtemos uma refer encia ao primeiro elemento, e com at(n); obtemos uma refer encia ao objeto n;. N ao podemos nos esquecer que podemos acesssar um <vector> exaPrograma ca o Orientada a Objeto com C++ Andr e Duarte Bueno
574
tamente da mesma forma que um vetor em C, utilizando o operator[](); que retorna uma refer encia ao objeto armazenado na casa n. Apredemos ainda a utilizar os m etodos: size() que retorna o n umero de elementos utilizados pelo container, capacity() que retorna o tamanho alocado pelo container, e max_size() que retorna o tamanho do maior vetor poss vel (o que depende da quantidade de mem oria dispon vel em seu computador). Vimos que podemos utilizar reserve(); para denir a capacidade do container, ou resize(); para alterar o tamanho do container. Lembre-se ainda que empty() retorna true se o container estiver vazio. Note que temos diversas vers oes de insert(), as memas s ao utilizadas para inserir novos objetos no container. Um m etodo de inser ca o especial e fornecido por push_back();, o mesmo insere um objeto no nal do container. Tamb em podemos eliminar objetos do container utilizando erase(n); para eliminar o elemento n, ou pop_back(); para remover o u ltimo elemento do container. J a clear(); apaga todo container. O container <list> deve ser utilizado quando precisamos inserir novos elementos em qualquer posi ca o do container. Lembre-se <list> e lento para acesso rand omico, mas e otimizado para inser ca o e remo ca o de elementos em qualquer posi ca o. Um <list> fornece todos os m etodos de um <vector>, com exce ca o de at[], capacity() e reserve(), e acrescenta m etodos novos, como front(), push_front(), pop_front() e insert(pos,elem). Vimos que um container <deque> e uma la com duas extremidades, unindo vantagens de <list> e <vector>. Como exemplo a r apida inser ca o na frente e atr as do container. Um <deque> tem os mesmos m etodos de <vector>, mas adiciona push_front(), pop_front() e suporta iteradores rand omicos. Dica: como o conjunto de m etodos fornecidos por cada container e grande, n ao tente decorar nada, apenas preste aten ca o no conceito. Com o tempo voc e ir a aprender a utilizar as classes container com facilidade.
32.5
Exerc cios
1. Diga em poucas linhas, quais as principais diferen cas entre os containers <vector>, <list>, <deque>, <set>, <multiset>, <map>, <multimap>, <stack>, <queue>. 2. Explique o porque da senten ca Uma lista n ao aceita (iterator + n). Voc e precisa fazer iterator++ n vezes.? 3. Porque <list> n ao aceita subscript[]. 4. Comente cada linha da listagem 32.1. 5. Modique a listagem 32.1. Use streans_iterators para entrada dos dados. Transforme o operador < <, em um operador com template, isto e, com tipo a ser denido. Inclua localiza ca o do maior e menor elemento do container. 6. Modique a listagem 32.2. Mostre na tela o conte udo da lista antes e depois de unique(). Verique que os elementos repetidos n ao s ao eliminados, apenas movidos para o m do conteiner. Monte um algoritmo para realmente eliminar os elementos repetidos. 7. Modique a listagem 32.3. Substitua o uso de push_front() e push_back(), por m etodo que possibilite a entrada de dados pelo usu ario. Monte um menu em que o usu ario vai poder selecionar uma das seguintes op co es: Incluir novo elemento; Eliminar elemento; Mostrar elemento; Localizar elemento. Mostrar toda lista; Apagar toda lista. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
575
8. 2 Modique a listagem 32.4. Substitua o operador< < (que usa template) por um operador sem template, fazendo o inverso de um de nossos exerc cios anteriores. Possibilite ao usu ario a entrada de dados. Use fun co es rand omicas para embaralhar o texto, como exemplo as fun co es next_permutation.
576
Cap tulo 33
33.1
Um <stack> e um container adaptado que trabalha como uma pilha LIFO (last in, rst out ). O u ltimo elemento colocado na pilha e o primeiro a ser removido, da mesma forma que ocorre com a pilha de uma calculadora HP (veja Figura 33.1). A Figura 33.1 mostra os m etodos disponibilizados para <stack>. Figura 33.1: M etodos disponibilizados para <stack>.
push() top() pop()
size()
Um <stack> e um container adaptado porque e constru do sobre um container <vector>, <list> ou <deque>. Se n ao for fornecido um container, por default e utilizado um <deque>. A Figura 33.2 mostra que a realiza ca o da classe <stack> e feita por <deque>, <vector>, ou 577
578
<list>. Veja a direita outra forma de representar este relacionamemto usando UML, a classe <stack> aparece como uma interface de acesso a <deque>. Figura 33.2: A classe <stack> funciona como uma interface de acesso a <deque>, <list> ou <vector>.
<<interface>>
deque vector
deque
stack
stack
list
Para utilizar um container <stack>, inclua o arquivo de cabe calho: #include <stack>
33.1.1
M etodos de <stack>
Apresenta-se a seguir alguns m etodos de <stack>. void push(const value type& x); Coloca elemento x na pilha. void pop(); Remove elemento da pilha. value type& top(); Retorna o elemento no topo da pilha, sem remover. const value type& top() const; Retorna o elemento no topo da pilha, como valor constante. size type size() const; Retorna o n umero de elementos da pilha. bool empty() ; Retorna true se a pilha estiver vazia.
33.1.2
Como a classe <stack> e pequena e simples, a mesma e apresentada na ntegra. Observe na listagem 33.1 que se voc e n ao passar o tipo de container a ser utilizado, <stack> usa por padr ao o tipo <deque>. Listing 33.1: A classe container <stack>.
1 2 3 4 5 6 7 8 // A classe c o n t a i n e r stack template < typename T , typename Container = deque <T > > class stack { typedef Container :: value_type value_type ; typedef Container :: size_type size_type ; protected : Container c ;
579
33.1.3
Exemplo de <stack>
Veja na listagem 33.2 um exemplo de utiliza ca o do container <stack>. Como novidades temos, o uso de push() para adicionar elementos e de top() para ver o elemento no topo da pilha. Finalmente, usamos pop() para retirar elementos da pilha. Observe na sa da que o primeiro a entrar eou ltimo a sair. Listing 33.2: Usando <stack>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 # include < iostream > # include < stack > # include < vector > # include < list > # include < string > using namespace std ; int main () { // Cria uma pilha a partir de stack < string > stack < int , vector < int > > stack < float , list < float > >
// A d i c i o n a n d o e l e m e n t o s ao c o n t a i n e r char resp ; do { cout << " Entre com o nome do politico : " ; string n o m e _ p o l i t i c o ; getline ( cin , n o m e _ p o l i t i c o ) ; politicos . push ( n o m e _ p o l i t i c o ) ; cout << " Entre com o n u mero do partido : " ; int n u m e r o P a r t i d o ; cin >> n u m e r o P a r t i d o ; cin . get () ; partidos . push ( n u m e r o P a r t i d o ) ; cout << " Entre com a nota do politico : " ; int nota ; cin >> nota ; cin . get () ; n o t a D o P o l i t i c o . push ( nota ) ; cout << " Continuar ( c ) ou sair ( q ) : " ; cin >> resp ; cin . get () ; } while ( resp != q && resp != Q ) ; cout << " \ nRetirando elementos do container : " << endl ; while (! politicos . empty () ) { cout << politicos . top () << ; politicos . pop () ; cout << partidos . top () << ;
580
44 45 46 47 48 49 50
} cout << endl ; return 0; } [ b u e n o @ l d s c 0 5 Parte - III ] $ ./ List_30_1 Entre com o nome do politico : Joao da Silva Entre com o numero do partido :456 Entre com a nota do politico :5 Continuar ( c ) ou sair ( q ) : c Entre com o nome do politico : Claudio Siqueira Entre com o numero do partido :654 Entre com a nota do politico :7 Continuar ( c ) ou sair ( q ) : c Entre com o nome do politico : Jos e Candido Medeiros Entre com o numero do partido :648 Entre com a nota do politico :8 Continuar ( c ) ou sair ( q ) : q Retirando elementos do container : Jos e Candido Medeiros 648 8 Claudio Siqueira 654 7 Joao da Silva 456 5
33.2
Um container <queue> e um container que trabalha como se fosse uma la do tipo FIFO (rst in, rst out ). O primeiro que entra e o primeiro que sai. Um <queue> n ao suporta iteradores. Veja Figura 33.3. Os tens s ao adicionados na parte de tr as (com push()) e removidos da parte da frente (com pop()). O tipo <queue> pode ser adaptado a partir de qualquer container que suporte as opera co es front(), back(), push_back() e pop_front(). Normalmente e utilizado com <list> e <deque> (default ), pois n ao suporta <vector>. Para usar <queue> inclua o header <queue>: #include <queue>
front()
size()
back()
581
33.2.1
M etodos de <queue>
Apresenta-se a seguir alguns m etodos de <queue>. value type& back(); Retorna o objeto do m da lista (o u ltimo elemento colocado). bool empty() const; Retorna true se a la estiver vazia. value type& front(); Retorna o elemento da frente da la. Primeiro tem que foi colocado na la. void push(const value type& x); Coloca x na parte de tr as da la. O primeiro que entra e o primeiro a sair. void pop(); Remove o elemento da frente da la. size type size () const; Retorna o n umero de elementos da la. const value type& back() const; Retorna o objeto do m da lista (o u ltimo elemento colocado) como const. const value type& front() const; Retorna o elemento da frente da la como const.
33.2.2
Veja a seguir a classe container <queue>. Listing 33.3: A classe container <queue>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template < class T , class Container = deque <T > > class queue { public : typedef typename Container :: value_type value_type ; typedef typename Container :: size_type size_type ; protected : Container c ; public : value_type & back () ; bool empty () const ; value_type & front () ; void push ( const value_type & x ) ; void pop () ; size_type size () const ; const value_type & back () const ; const value_type & front () const ; };
582
33.2.3
Exemplo de <queue>
Veja na listagem 33.4 um exemplo de uso do container <queue>. Listing 33.4: Usando <queue>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # include < iostream > # include < queue > # include < vector > # include < list > # include < iomanip > using namespace std ; int main () { // Cria queue a partir de deque , e list std :: queue < int > c o n t a i n e r Q u e u e D e q u e ; std :: queue < int , std :: list < int > > c o n t a i n e r Q u e u e L i s t ; // A d i c i o n a n d o e l e m e n t o s ao c o n t a i n e r for ( int i = 0; i < 10; ++ i ) { c o n t a i n e r Q u e u e D e q u e . push ( i ) ; c o n t a i n e r Q u e u e L i s t . push ( i * i ) ; } cout << " \ nRetirand o elementos do c o n t a i n e r Q u e u e D e q u e : " ; while (! c o n t a i n e r Q u e u e D e q u e . empty () ) { cout << setw (5) << c o n t a i n e r Q u e u e D e q u e . front () << ; c o n t a i n e r Q u e u e D e q u e . pop () ; } cout << " \ nRetirand o elementos do c o n t a i n e r Q u e u e L i s t : " ; while (! c o n t a i n e r Q u e u e L i s t . empty () ) { cout << setw (5) << c o n t a i n e r Q u e u e L i s t . front () << ; c o n t a i n e r Q u e u e L i s t . pop () ; } cout << endl ; return 0; } [ a n d r e @ m e r c u r i o Cap4 - STL ]# ./ a . out Retirando elementos do c o n t a i n e r _ q u e u e _ d e q u e : 0 1 2 3 4 5 6 7 8 9 Retirando elementos do c o n t a i n e r _ q u e u e _ l i s t : 0 1 4 9 16 25 36 49 64 81
33.3
Este container funciona da mesma forma que um <queue>, a diferen ca e que na <priority_queue> a la est a sempre ordenada, ou seja, o elemento retirado com pop() e sempre o maior. Um <priority_queue> compara seus elementos utilizando operador <. Utilize pop() para retornar o maior valor. Para utilizar <priority_queue>, inclua o arquivo de cabe calho: #include <queue> Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
583
33.4
Neste cap tulo aprendemos a utilizar os containers adaptativos <stack>, <queue> e <priority_queue>, containers que s ao constru dos a partir da adapta ca o de um outro container. Lembre-se um <stack> e um container adaptado que trabalha como uma pilha LIFO (last in, rst out ). O u ltimo elemento colocado na pilha e o primeiro a ser removido, da mesma forma que ocorre com a pilha de uma calculadora HP. Vimos que push() coloca o tem x na pilha, que pop() remove um tem da pilha, que top() retorna o tem no topo da pilha, sem o remover. Vimos que um container <queue> e um container que trabalha como se fosse uma la do tipo FIFO (rst in, rst out ), o primeiro que entra e o primeiro que sai. Os tens s ao adicionados na parte de tr as com push() e removidos da parte da frente com pop(). O tipo <queue> e normalmente utilizado com <list> e <deque> (default ), pois n ao suporta <vector>. Entre os m etodos de <queue> temos: back() que retorna o objeto do m da lista, empty() que retorna true se a la estiver vazia. front() que retorna o tem da frente da la. push() que coloca x na parte de tr as da la. pop() que remove o tem da frente da la e size() que retorna o n umero de elementos da la. As classes <stack>, <queue> e <priority_queue> s ao exemplos de classe de interface.
33.5
Exerc cios
1. Explique o funcionamento da listagem 33.2. 2. Modique a listagem 33.2. 3. Modique a listagem 33.4. 4. Implementar um exemplo que utilize <priority_queue>.
584
Cap tulo 34
34.1
A classe <pair>
Toda fun ca o ou m etodo retorna apenas um objeto. Em muitos casos, voc e pode querer que um m etodo retorne dois objetos. Nestes casos, podemos utilizar um objeto da classe <pair>. A classe <pair> e denida no arquivo de cabe calho <utility>. Um <pair> e um objeto composto de dois outros objetos. O mesmo e utilizado em alguns m etodos dos containers <set>, <map> e <multimap>. Veja a seguir o prot otipo para criar e utilizar um <pair>. Prot otipo: Para criar um <pair> pair <Tipo1, Tipo2> objPar (Tipo1 obj, Tipo2 obj); Para usar um <pair> cout < < Primeiro objeto = < < objPar->rst(); cout < < Segundo objeto = < < objPar->second(); Pode-se construir rapidamente um <pair> utilizando-se make_pair(). Veja o exemplo: Exemplo: pair<int,float> objPair = make_pair( 6 , 7.4 );
34.2
O container <set> e um container associativo utilizado para armazenar um conjunto de chaves. Veja a seguir algumas caracter sticas do contaier <set>. As chaves n ao podem ser repetidas. 585
586 Aceita acesso bidirecional, mas n ao rand omico. Dene value_type como sendo a chave.
Inclui sobrecarga para os operadores ==, !=, <, >, <=, >= e swap. N ao tem o operador []. Os objetos armazenados em <set> est ao sempre ordenados. Para utilizar o container <set>, inclua o arquivo de cabe calho <set>: #include <set> como um <map>, mas n E ao armazena um valor, somente a chave. A Figura 34.1 mostra os m etodos disponibilizados para <set>. Observe o uso de insert() para incluir uma chave e de erase() para eliminar uma chave. O container <set> inclui os m etodos find() para pesquisa de uma determinada chave, count() para contagem de objetos, al em de lower_bound(), upper_bound() e equal_range(). Figura 34.1: M etodos disponibilizados para <set>.
c 0 c 1 c 2 c 3 ... c n-2 c n-1
erase(chave) insert(chave)
34.2.1
Contrutores e destrutor
set (); Constr oe um set vazio (construtor default ). set (InputIterator rst, InputIterator last); Constr oe um set usando o intervalo [rst,last).
34.2.2
Trocas
void swap(set<Key, Compare, Alloc>& s); Troca o conte udo do container s com o conte udo deste container (de this).
34.2.3
Inser c ao e dele c ao
pair<iterator,bool> insert(const value type& x) ; Insere a chave x no container e retorna um par onde o primeiro elemento e um iterador para posi ca o do objeto no container e o segundo elemento um bool que indica sucesso ou fracasso na inser ca o. iterator insert(iterator pos, const value type& x); Insere a chave x no container no local indicado pelo iterador pos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
34.2. A CLASSE CONTAINER <SET> void erase(iterator pos); Elimina o objeto na posi ca o pos. size type erase(const key type& x); Elimina o objeto indicado pela chave x. void erase(iterator rst, iterator last); Elimina os elementos do container que est ao no intervalo [rst, last). void clear(); Elimina todos os elementos do container.
587
34.2.4
Pesquisa e contagem
iterator nd(const key type& x); Procura pelo elemento associado a chave x. size type count(const key type& x); Conta o n umero de elementos associados a chave x. Complexidade log(n)+count. iterator lower bound(const key type& x); Retorna iterador para o primeiro elemento associado a chave x. Complexidade log(n). iterator upper bound(const key type& x); Retorna iterador para o objeto imediatamente ap os o u ltimo objeto associado a chave x. Complexidade log(n). pair<iterator,iterator> equal range(const key type& x); Retorna um par de iteradores onde rst e o valor retornado por lower_bound() e last o valor retornado por upper_bound(). Complexidade log(n).
34.2.5
Operadores
34.2.6
Exemplo de <set>
Veja na listagem 34.1 um exemplo de utiliza ca o do container <set>. O programa cria um container <set>, para n umeros inteiros, com o nome cset. Note que passamos o operador a ser utilizado para ordena ca o do container, std::less<int>. A seguir acrescenta novas chaves no container. Finalmente, criamos um iterador para cout e usamos a fun ca o gen erica copy() para enviar os elementos do container para tela. Observe que na sa da os dados est ao ordenados, mesmo n ao tendo sido inclu dos de forma ordenada. Listing 34.1: Usando <set>.
1 2 3 4 5 6 7 8 9 10 # include < iostream > # include < set > # include < algorithm > # include < iterator > using namespace std ; int main () { // Cria um c o n t a i n e r set , para tipo int // usa o p e r a d o r de c o m p a r a c~ a o std :: less < int >
588
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 set < int , std :: less < int > > cset ;
// Insere o b j e t o s no c o n t a i n e r ( sem ordem ) cset . insert (10) ; cset . insert (1000) ; cset . insert (100) ; cset . insert (10000) ; // Cria i t e r a d o r para uma o s t r e a m std :: o s t r e a m _ i t e r a t o r < int > out ( cout , " \ t " ) ; // Copia o c o n t a i n e r para tela usanto o i t e r a d o r out copy ( cset . begin () , cset . end () , out ) ; cout << endl ; return 0; } [ a n d r e @ m e r c u r i o Parte - IV ] $ ./ a . out 10 100 1000 10000
Dica: a classe <set> da STL costuma ser implementada como uma arvore de pesquisa balanceada, em que cada elemento tem tr es ponteiros. Isto garante performance, mas implica em aumento do consumo de mem oria, [Meyers, 2005].
34.3
Um container <multiset> trabalha com um conjunto de chaves que podem ser repetidas. Veja a seguir as caracter sticas de <multiset> . O mesmo armazena e recupera o valor da chave rapidamente. O container <multiset> suporta iterador bidirecional. As chaves est ao sempre ordenadas, em ordem crescente. um container associativo. E Para utilizar <multiset>, inclua o arquivo de cabe calho: #include <set> A diferen ca para <set> e que insert() retorna um iterator e n ao um <pair>. A Figura 34.2 mostra alguns m etodos disponibilizados para <multiset>: Figura 34.2: M etodos disponibilizados para <multiset>.
c0 c1 c2 c4 c4
c[n-2] c[n-1]
insert(c3) repetidas
erase(ci)
589
34.3.1
Contrutores e destrutor
multiset (); Construtor default. multiset (InputIterator rst, InputIterator last); Cria um multiset utilizando os valores do intervalo [rst,last).
34.3.2
Operadores
34.4
Nesta se ca o descreveremos o container associativo <map>. Um container <map> trabalha com um conjunto de chaves e de objetos associados a essas chaves, ou seja, trabalha com pares onde a ordena ca o e tomada de decis oes e baseada nas chaves. Veja a seguir as caracter sticas do container <map>. um container associativo. E Em um <map> as chaves n ao podem ser repetidas. Um <map> fornece iteradores bidirecionais. Em um <map>, os dados s ao armazenados de forma ordenada, pelo operador menor que (<). Num <map>, value_type e um pair. Para usar <map> inclua seu arquivo de cabe calho: #include <map> A Figura 34.3 mostra alguns m etodos disponibilizados para <map>. O container <map> e muito u til, como veremos na listagem 34.2. Figura 34.3: M etodos disponibilizados para <map>.
c0 v[0] c1 v[1] c2 v[2] v[j] cj ... ... v[i]
c[n-2] c[n-1]
chave valor
v v [n-2] [n-1]
insert( cj , vj)
erase( ci )
590
34.4.1
Construtores e destrutor
map (); Constr oe um map vazio (construtor default ). Exemplo: map< int, string > meuMap; map (InputIterator rst, InputIterator last); Constr oe um map usando o intervalo denido por [rst,last).
34.4.2
Operadores
Os operadores de <map> s ao == e <. map<Key, T, Compare, Alloc>& operator=(const map<Key, T, Compare, Alloc>& x); Operador de atribui ca o.
34.4.3
Inser c ao e dele c ao
pair<iterator,bool> insert(const value type& x); Insere um pair no container (um par(chave,valor)). Exemplo: meuMap.insert(make_pair( 5 , "jo~ ao" ); iterator insert(iterator pos, const value type& x); Insere um pair no container na posi ca o indicada. void erase(iterator pos); Apaga elemento localizado na posi ca o pos. size type erase(const key type& x); Apaga os elementos com a chave x. void erase(iterator rst, iterator last); Apaga os elementos no intervalo [rst-last). void clear() ; Apaga todos os elementos do container.
34.4.4
Pesquisa e contagem
iterator nd(const key type& x) ; Localiza objeto com a chave x; se n ao achar, retorna end(). size type count(const key type& x) ; Conta o n umero de objetos com a chave x. iterator lower bound(const key type& x); Retorna um iterador para primeiro elemento igual a x. Se n ao encontrar x, retorna iterador para primeiro elemento maior que x (ou para end()). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
34.4. A CLASSE CONTAINER <MAP> iterator upper bound(const key type& x) ; Retorna um iterador para o primeiro elemento maior que x.
591
pair<iterator,iterator> equal range(const key type& x) ; Retorna um par onde o primeiro elemento (rst ) e o retorno de lower_bound() e o segundo elemento (second ), o retorno de upper_bound(). const iterator nd(const key type& x) ; Localiza objeto com a chave x; se n ao achar, retorna end(). Retorna iterador constante. const iterator lower bound(const key type& x) ; Retorna um iterador constante para primeiro elemento igual a x. Se n ao encontrar x, retorna iterador para primeiro elemento maior que x (ou para end()). const iterator upper bound(const key typ& x) ; Retorna um iterador constante para o primeiro elemento maior que x. pair<const iterator,const iterator> equal range(const key type& x) ; Retorna um par onde o primeiro elemento (rst ) e o retorno de lower_bound() e o segundo elemento (second ), o retorno de upper_bound(). Os iterador de pair s ao constantes.
34.4.5
Exemplo de <map>
Veja na listagem 34.2 um exemplo que inclui a utiliza ca o de <map>. O c odigo esta documentado. Observe na sa da que os objetos do container s ao listados em ordem alfab etica. Isto ocorre porque <map> e sempre ordenado; a ordena ca o e feita pela chave. Listing 34.2: Usando <map>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # include < iostream > # include < fstream > # include < iomanip > # include < string > # include < map > using namespace std ; class CTelefone // Tipo telefone , a r m a z e n a o p r e f i x o e o n u mero { private : int prefixo ; int numero ; public : // C o n s t r u t o r CTelefone () : prefixo (0) , numero (0) {}; // S o b r e c a r g a de friend istream & friend ostream & friend ofstream & }; istream & operator > >( istream & is , CTelefone & t ) { is >> t . prefixo ; is >> t . numero ; return is ; } s t r e a m s como fun c~ a o friend operator >> ( istream & is , CTelefone & t ) ; operator << ( ostream & os , const CTelefone & t ) ; operator << ( ofstream & os , const CTelefone & t ) ;
592
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
ostream & operator < <( ostream & os , const CTelefone & t ) { os . setf ( ios :: left ) ; os << " ( " << t . prefixo << " ) -" << t . numero << endl ; return os ; } ofstream & operator < <( ofstream & os , const CTelefone & t ) { os . setf ( ios :: left ) ; os << t . prefixo << << t . numero << endl ; return os ; } int main () { // Usa um typedef , um a p e l i d o para std :: map usando string e C T e l e f o n e // A string e a chave e o C T e l e f o n e o valor . typedef std :: map < string , CTelefone > c o n t a i n e r M a p ; // Cria c o n t a i n e r para a r m a z e n a r lista de t e l e f o n e s containerMap listatelefones; CTelefone telefone ; int resp = 0; string linha ( " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\ n " ) ; do { string nome ; cout << " Entre com o nome da pessoa / empresa : " << endl ; getline ( cin , nome ) ; cout << " Entre com o telefone ( prefixo n u mero ) " << " ( ctrl + d para encerrar entrada ) : " << endl ; cin >> telefone ; cin . get () ; // O b s e r v e a i n s e r c~ a o da chave ( o nome ) e do valor ( o t e l e f o n e ) . if ( cin . good () ) l i s t a t e l e f o n e s . insert ( c o n t a i n e r M a p :: value_type ( nome , telefone ) ) ; } while ( cin . good () ) ; cin . clear () ; cout << linha << " Conte u do do container :\ n " << linha << " \ nChave valor " << endl ; // Sa da para tela a l i n h a d a a e s q u e r d a cout . setf ( ios :: left ) ; // Cria i t e r a d o r c o n t a i n e r M a p :: c o n s t _ i t e r a t o r iter ; for ( iter = l i s t a t e l e f o n e s . begin () ; iter != l i s t a t e l e f o n e s . end () ; ++ iter ) { cout << setw (5) << iter - > first << << iter - > second ; } cout << endl ; // Sa da para disco ofstream fout ( " L i s t a _ t e l e f o n e s _ m a p . dat " ) ; if ( fout ) { for ( iter = l i s t a t e l e f o n e s . begin () ; iter != l i s t a t e l e f o n e s . end () ; ++ iter ) fout << iter - > first << << iter - > second ; fout . close () ;
593
34.4.6
Utilize um <map> para implementar um dicion ario. O m etodo begin() aponta para primeira chave ordenada (de forma crescente) e end(), para u ltima chave +1. O m etodo erase() retorna o n umero de objetos deletados. Se a chave n ao for localizada, <map> insere a chave da pesquisa no <map>, associando o valor a um valor default (zerado). Se voc e quer achar um par (chave,valor), mas n ao tem certeza de que a chave est a no <map>, use o m etodo find(). Pois, como dito na senten ca anterior, se a chave n ao for localizada, ela ser a inserida. A pesquisa no <map> utilizando a chave tem um custo da ordem de log(tamanhoDoMap). Um construtor de <map> pode receber um m etodo de compara ca o, de forma que voc e pode construir dois mapas e usar o mesmo m etodo de compara ca o em ambos. Na seq u encia AAAB, a chamada a lower_bound(A) retorna um iterator para o primeiro A e upper_ bound(A), um iterator para o primeiro elemento depois do u ltimo A, ou seja, para B. Assim, lower_bound() aponta para primeiro elemento na sequ encia e upper_bound() para u ltimo elemento +1. Utilize it->first para acessar a chave e it->second para acessar o valor. Exemplo: map<CChave,CValor>::const_iterator it; for(it = obj.begin(); it != obj.end(); it++) cout < < "chave=" < < it->first < < " valor=" < < it>second < < endl; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
594
34.5
O container <multimap> trabalha com um conjunto de chaves e de objetos associados a essas chaves, ou seja, trabalha com pares. Veja a seguir caracter sticas do container <multimap> . A ordena ca o e a tomada de decis oes s ao baseadas nas chaves. Em um <multimap>, as chaves podem ser repetidas. O container <multimap> n ao tem operador de subscrito (operator[]). um container associativo. E No container <multimap>, o m etodo insert() retorna um iterator e n ao um <pair>. E o uso de insert() sempre ocorre com sucesso pois <multimap> aceita valores repetidos. Para acessar os valores que t em a mesma chave, utilizam-se equal_range(), lower_bound() e upper_bound(). Exemplo: // Primeiro valor igual a x. lower_bound(x); // Primeiro valor maior que x. upper_bound(x); // Retorna um par // first = lower_bound(), second = upper_bound(). equal_range(x); Para utilizar um <multimap>, inclua o arquivo de cabe calho <map>: Exemplo: #include <map>
34.6
Neste cap tulo aprendemos a utilizar a classe <pair>, para armazenar pares de dados, e os containers associativos <set>, <multiset> , <map>, e <multimap>. Aprendemos a utilizar <set> para armazenar um conjunto de chaves sem repeti co es, e <map>, para armazenar conjuntos de dados com chaves e valores (sem repeti co es). Montamos um exemplo que implementa, mesmo que basicamente, uma agenda de telefones.
34.7
Exerc cios
1. Monte um exemplo que utilize make_pair(); 2. Modique a listagem 34.1, mudando a ordem de ordena ca o do container. Ou seja, substituir o operador de compara ca o por std::greater<int>. Ver o resultado. 3. Monte um exemplo que utilize <multiset>. 4. Modique a listagem 34.2, acrescente uma classe CEndereco (que deve incluir a cidade, cep, rua, telefone e e-mail). Desta forma o programa vai montar uma agenda com todos os dados de seus amigos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
595
5. No exemplo da listagem 34.2, substitua containerMap::value_type(nome, telefone) por make_pair(nome, telefone). 6. Modique o exemplo anterior, usando o endere co de e-mail como chave de acesso.
596
Cap tulo 35
598
35.1
Embora o conceito de programa ca o gen erica seja antigo (cerca de 30 anos), seu uso se intensicou com a inclus ao na STL de um conjunto de fun co es gen ericas. Ou seja, a STL fornece, al em de uma biblioteca de classes containers, um vasto conjunto de fun co es para pesquisa, ordena ca o, mistura, troca e transforma co es em um container. Cada fun ca o pode ser aplicada a um conjunto espec co de containers. Algumas fun co es gen ericas exigem que a classe container j a tenha sido ordenada. De uma maneira geral, as fun co es gen ericas utilizam iteradores para acessar e manipular os containers. As fun co es gen ericas foram constru das de forma a necessitar de um n umero reduzido de servi cos dos iteradores. O uso de gabaritos (templates) e de fun co es gen ericas permite a implementa ca o de algoritmos independentes do tipo de dados a ser utilizado.
35.2
Veja a seguir uma classica ca o das fun co es gen ericas quanto ` a mudan ca do container, quanto ao iterador necess ario e quanto ao tipo das opera co es.
35.2.1
Fun co es que n ao mudam o container: accumulate, nd, max, adjacent nd, nd if, max element, binary search, min, count, nd rst of, for each, min element, count if, includes, mismatch, equal, lexicographical compare, nth element, equal range, lower bound, mismatch, search, search n, nd end, upper bound. Fun co es que mudam o container: copy, remove if, copy backward, replace, ll, replace copy, ll n, replace copy if, generate, replace if, generate n, reverse, inplace merge, reverse copy, iter swap, rotate swap, make heap, rotate copy, merge, set dierence, nth element, next permutation, set intersection, set symmetric dierence, partial sort, set union, partial sort copy, sort, partition, sort heap, prev permutation, stable partition, push heap, stable sort, pop heap, swap, random shue, swap ranges, remove, transform, unique, unique copy, remove copy, remove copy if.
35.2.2
Algoritmos que n ao usam iterador: max, min, swap. Requer somente InputIterator: accumulate, nd, mismatch, count, nd if, count if, includes, equal, inner product, for each, lexicographical compare. Requer somente OutputIterator: ll n, generate n. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
599
L e de um InputIterator e escreve para um OutputIterator: adjacent dierence, replace copy, transform, copy, replace copy if, unique copy, merge, set dierence, partial sum, set intersedtion, remove copy, set symmetric dierence, remove copy if, set union. Requer um ForwardIterator: adjacent nd, lower bound, rotate, binary search, max element, search, equal range, unique, min element, swap ranges, ll, remove, nd rst of, remove if, upper bound, generate, replace, iter swap, replace if. L e de um ForwardIterator e escreve para um OutputIterator: rotate copy. Requer um BidirectionalIterator: copy backward, partition, inplace merge, prev permutation, next permutation, reverse, stable permutation. L e de um BidirectionalIterator e escreve em um OutputIterator: reverse copy. Requer um iterator rand omico, RandomAccessIterator: make heap, pop heap, sort, nth element, push heap, sort heap, partial sort, random shue, stable sort. L e de um InputIterator e escreve para um RandomAccessIterator: partial sort copy.
35.2.3
Opera co es de preenchimento: ll, ll n, copy, copy backward Opera co es de compara c ao: equal, mismatch, lexicographical compare, includes Opera co es de remo c ao: remove, remove if, remove copy, remove copy if Opera co es de troca (swap): swap, swap ranges, iter swap, replace, replace copy, replace copy if, replace if Opera co es de mistura: inplace merge, merge, reverse, reverse copy, random shue, rotate, rotate copy Opera co es de pesquisa: nd, adjacent nd, nd if, nd rst of, count if, search, nd, binary search, search n, lower bound, equal range, upper bound Opera co es de ordena c ao: sort, partial sort, stable sort, partial sort copy, nth element Opera co es de classica c ao: unique copy, unique Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
600
Opera co es de transforma c ao: generate n, generate, for each, transform, partition, stable partition Opera co es matem aticas: max, min, max element, min element, count, count if, accumulate Opera co es de set (conjuntos): set symmetric dierence, set dierence, set union, set intersection Opera co es de pilha: make heap, push heap, pop heap, sort heap, next permutation, prev permutation
35.3
Veremos a seguir uma breve descri ca o de cada fun ca o gen erica oferecida pela STL. Se o leitor n ao compreender determinada fun ca o, a dica e ver os exemplos apresentados no nal deste cap tulo. Observe que apresentamos a forma de uso e n ao o prot otipo; o prot otipo das fun co es gen ericas e encontrado no arquivo de cabe calho <algorithm> ou no site http: //www.sgi.com/tech/stl/.
35.3.1
Preenchimento
As fun co es fill() e copy() s ao utilizadas para preencher o container. ll (d.begin(), d.end(), valor); Utiliza ll para preencher o container de begin() a end() com o valor. Veja listagem 35.1. ll n (d.begin(), n, valor); A partir da posi ca o begin(), preencher n elementos do container com o valor. copy (orig.begin(), orig.end(), out); Copia de rst a last para out. Utilize copy() para gerar uma sa da do container ou para gerar um novo container. A fun ca o copy() e usada para copiar blocos de dados de um container para outro. Veja listagens 35.2 e 35.3. copy backward (orig.begin(), orig.end(), dest.end()); Copia os elementos de orig para dest; orig[0] e colocado no m de dest, e assim sucessivamente.
35.3.2
Compara c ao
Os algoritmos a seguir s ao utilizados para comparar containers ou elementos de containers. Para comparar elementos de containers do mesmo tipo use == ou <. equal (v1.begin(), v1.end(), v2.begin()); Compara a igualdade de cada elemento dos containers v1 e v2. Retorna true se for tudo igual. mismatch (v1.begin(), v1.end(), v2.begin()); Retorna um par de iteradores que apontam para objetos de v1 e v2 que s ao diferentes. Se v1 == v2, os iteradores apontam para end(). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
35.3. FUNC OES GENERICAS lexicographical compare (v1.begin(), v1.end(), v2.begin(), v2.end()); Retorna a posi ca o onde os containers v1 e v2 s ao diferentes.
601
includes (a, a+size, b, b+size); Compara os containers ordenados a e b; se qualquer elemento de b estiver presente em a, retorna true. Veja listagem 36.4.
35.3.3
Remo c ao
Os algoritmos a seguir s ao utilizados para remover elementos do container. Observe que os elementos n ao s ao de fato removidos, apenas movidos para o m do container (no intervalo de valores entre size() e capacity()). remove (v.begin(), v.end(), valor); Percorre todo o container (de begin() a end()) e remove os objetos que t em seu conte udo igual a valor. c aoPredicado); remove if (v.begin(), v.end(), Fun Remove de begin() a end() se a fun ca o predicado retornar true. remove copy (orig.begin(), orig.end(), d.begin(), valor); Remove de begin() a end() o valor e copia para d. Se o container d for pequeno, haver a estouro de pilha. remove copy if (o.begin(), o.end(), d.begin(), fpred); Remove de begin() a end() se a fun ca o predicado retornar true e copia para d.
35.3.4
Troca
Os algoritmos a seguir s ao utilizados para trocar elementos de containers. replace (v.begin(), v.end(), valor, novoValor); Troca de begin() a end() valor por novoValor. c aoPredicado, novoValor); replace if (v.begin(), v.end(), Fun Se a fun ca o predicado retornar true, troca pelo novoValor. replace copy (orig.begin(), orig.end(), d.begin(), valor, novoValor); Troca de begin() a end() valor por novoValor e copia para d. replace copy if (orig.begin(), orig.end(), d.begin(), Fun c aoPredicado, novoValor); Se a fun ca o predicado retornar true, troca por novoValor no destino d. swap (v[0], v[1]); Troca o conte udo de v[0] pelo conte udo de v[1]. iter swap (it1, it2); Troca os objetos apontados por it1 e it2. swap range (v, v+3, v+4); Troca os objetos no intervalo especicado. O primeiro intervalo vai de v a v+3 (excluindo v+3). O segundo intervalo inicia-se em v+4. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
602
35.3.5
Misturar/Mesclar/Inverter
Os algoritmos a seguir s ao utilizados para misturar, mesclar ou inverter elementos de diferentes containers. merge (orig1.begin(), orig1.end(), orig2.begin(), orig2.end(), dest.begin()) Pega os containers orig1 e orig2, que devem estar ordenados, e cria um container v3 com todos os elementos de orig1 e orig2. A seguir, copia os elementos de v3 para dest. merge (orig1.begin(), orig1.end(), orig2.begin(), orig2.end(), back inserter(d)) Pega os containers orig1 e orig2, que devem estar ordenados, e cria um container v3 com todos os elementos de orig1 e orig2. Depois copia v3 para d usando push_back(). inplace merge (v.begin(), v.begin()+n, v.end()) Mistura dois conjuntos de dados do mesmo container. Ir a misturar os valores de begin() a begin()+n com os valores a partir de begin()+n (sem ultrapassar v.end()). reverse (v.begin(), v.end()); Muda a ordem; o primeiro passa a ser o u ltimo. Veja listagem 36.4. reverse copy (orig.begin(), orig.end(), back inserter(dest)); Inverte os elementos de orig e copia para dest. A fun ca o back_inserter() chama a fun ca o push_back() de dest para inserir os elementos em dest. rotate (v.begin(), v.end(), v.begin()); Rotaciona ciclicamente. Veja listagem 36.4. random shue (v.begin(), v.end()); Embaralha os elementos do container randomicamente.
35.3.6
Pesquisa
Os algoritmos a seguir s ao utilizados para pesquisar/localizar determinado valor ou condi ca o. Para fazer pesquisa de tr as para frente use um reverse_iterator. nd (v.begin(), v.end(), valor); O find() procura por valor no intervalo especicado. Veja listagens 35.1 e 35.4. nd if (v.begin(), v.end(), Fun c aoPredicado); O find_if() procura no intervalo [rst-last) o objeto que satisfa ca ` a fun ca o predicado. Veja listagem 35.1. nd rst of (v1.begin(), v1.end(), v2.begin(), v2.end()); Retorna iterador para elemento de v1 que existe em v2. nd end(v1.begin(), v1.end(), v2.begin(), v2.end()); Procura a u ltima ocorr encia de uma subsequ encia em um intervalo. Procura no intervalo [v1.begin(), v1.end()) por uma sub-sequ encia de valores iguais no intervalo [v2.begin(), v2.end()) e retorna um iterador para primeiro elemento na sub-sequ encia. adjacent nd (v.begin(), v.end()); Procura pelo primeiro par de valores iguais e adjacentes; retorna iterador para o primeiro elemento. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
603
binary search (v.begin(), v.end(), valor); Retorna true se o valor estiver presente no container. O container deve estar ordenado. lower bound (v.begin(), v.end(), valor); Retorna um iterador para o primeiro elemento igual ao valor. Para manter o container ordenado, inserir valor utilizando o iterador retornado. No exemplo a seguir, se o vetor v tem os elementos 3,4,6,12,34,34,34,50 e valor=34, lower_bound() retorna iterador para o primeiro 34. Exemplo: vector<int>::iterator lower; lower = lower_bound(v.begin(),v.end(),valor); upper bound (v.begin(), v.end(), valor); Retorna um iterador para o primeiro elemento maior que valor. Se tiver 3,4,6,12,34,34,50 e valor=34, retorna iterador para 50. Exemplo : vector<int>::iterator uper = uper_bound(v.begin(),v.end(),valor); equal range (v.begin(), v.end(), valor); Retorna um pair para aplica ca o de first=lower_bound() e second=uper_bound(). Exemplo: pair<vector<int>::iterator, vector<int>::iterator> p; p = equal_range(v.begin(),v.end(),valor); search (v.1begin(), v1.end(), v2.begin(), v2.end()); Procura uma seq u encia de v1.begin() a v1.end() que exista em v2.begin() a v2.end(). Ou seja, a seq u encia do container v1 existe no container v2? Retorna iterador para primeiro objeto no container v1. search (v.begin(), v.end(), Fun c aoPredicado); Procura de v.begin() a v.end() os elementos do container que satisfa cam ` a fun ca o predicado. Retorna iterador para primeira ocorr encia. search n (v.begin(), v.end(), n, valor) Procura seq u encia com n combina co es de valor. Retorna iterador para primeiro elemento encontrado.
35.3.7
Ordena c ao
Os algoritmos a seguir s ao utilizados para ordenar um container. sort (v.begin(), v.end()); Ordena o container v, de v.begin(), at e v.end(). O m etodo sort() n ao e dispon vel para <list>; utilize o sort() do pr oprio container <list>. A fun ca o sort() usa um algoritmo do tipo quicksort e tem um custo computacional proporcional a O(N.log(N)). Veja listagens 35.1, 35.2, 35.3, 36.4. Exemplo: sort(v.begin(), v.end(), std::greater<int>); cio, meio, m); partial sort (in Ordena do in cio at e o meio. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
604
35.3.8
Classica c ao
Os algoritmos a seguir s ao utilizados para classicar um container. unique copy (orig.begin(), orig.end(), back inserter(dest)); Obt em uma c opia de orig, sem elementos repetidos, e copia para dest. unique (v.begin(), v.end()); Elimina os elementos duplicados, movendo-os para o m do container. Observe que retorna iterador para u ltimo elemento n ao duplicado. Nota: antes de chamar unique(), chame sort(). Apresenta-se no exemplo a seguir uma fun ca o gen erica que realmente elimina os elementos duplicados. Exemplo: template<typename C> void unique2(C& c) { // Ordena o container sort(c.begin(),c.end()); // Move para tr as elementos duplicados typename C::iterator p = unique(c.begin(),c.end()); // Deleta elementos duplicados c.erase(p,c.end()); }
35.3.9
Transforma c ao
Os algoritmos a seguir s ao utilizados para aplicar transforma co es aos elementos de um container. Os elementos transformados podem ser enviados para o pr oprio container destino ou um iterador (como ostream_iterator). generate (v.begin(), v.end(), fun c ao); generate() e usada para gerar novos valores para o container. De v.begin() a v.end() executa a fun ca o que n ao recebe nenhum par ametro mas retorna um novo elemento para o container. Veja listagem 36.4. c ao); generate n (v.begin(), n, fun De begin() a n executa a fun ca o que n ao recebe nada mas retorna um novo elemento para o container. Ou seja, preenche o container de v.begin() at e v.begin()+n. Note que v.begin() e um iterador, logo, a fun ca o pode ser usada n vezes e a sa da enviada para o iterador. for each (v.begin(), v.end(), fun c ao); Para cada elemento do container executa a fun ca o. De v.begin() a v.end() executa a fun ca o, utilizada para aplicar uma dada fun ca o a cada um dos elementos do container. Observe que for_each() n ao modica os elementos do container. transform (orig.begin(), orig.end(), dest.begin(), fun c ao); De orig.begin() a orig.end() executa a fun ca o e armazena o resultado em dest. Observe que a fun ca o deve receber um objeto do container (como const) e deve retornar um objeto Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
605
transformado. Por exemplo, para somar o n umero 75 a todos os elementos do container v. Veja outros exemplos nas listagens 36.3, 36.4. No exemplo a seguir o destino e o pr oprio vetor v. Exemplo: transform(v.begin(), v.end(), d.begin(), rand); transform(v.begin(), v.end(), v.begin(), bin2nd(plus<int>(),75); transform (orig1.begin(), orig1.end(), orig2.begin(), d.begin(), fun c ao); De orig1.begin() a orig1.end() executa a fun ca o, usando os dados de orig1 e orig2, e armazena o resultado em d. Observe que a fun ca o deve receber um objeto do container orig1 (como const) e um objeto do container orig2 (como const) e deve retornar um objeto transformado. partition (v.begin(), v.end(), Fun c aoPredicado); Uma parti ca o ordena o container de acordo com a fun ca o predicado. V ao para o in cio do container os objetos que satisfazem ao predicado (retornam true). Veja listagem 36.4. Exemplo: partition(in cio,fim,predicado); Dica: os algoritmos que mudam o container, como tranform(), retornam um iterador para destino.end().
35.3.10
Matem aticos
Os algoritmos a seguir s ao utilizados para realizar opera co es matem aticas, como exemplo obter o maior valor de um container. Veja o arquivo <numerics>. max (a, b); Retorna a, se a > b, ou b, se b > a. Retorna o maior valor. min (a, b); Retorna a, se a < b, ou b, se b < a. Retorna o menor valor. max element (v.begin(), v.end()); Retorna o maior elemento. min element (v.begin(), v.end()); Retorna o menor elemento. count (v.begin(), v.end(),valor); Determina o n umero de elementos igual a valor. Exemplo: int total = count(v.begin(),v.end(),0); c aoPredicado); count if (v.begin(), v.end(), Fun Determina o n umero de elementos que obedecem ` a fun ca o predicado. accumulate (v.begin(), v.end(), valorInicial); Retorna a soma de todos os elementos. Observe que podemos passar o valor inicial do somat orio. Veja listagem 36.4. Exemplo: int somat orio = accumulate(v.begin(),v.end(),0); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
606
35.3.11
set dierence (a, a+size, b, b+size, diferen ca); Todos os valores do vetor a que n ao estiverem no vetor b ser ao copiados para o vetor diferen ca. Veja listagem 36.4. Exemplo: int diferenca[size]; set_difference ( a, a + size , b , b + size , diferenca ); c ao); set intersection (a, a+size, b, b+size, interse Todos os valores do vetor a que estiverem no vetor b ser ao copiados para o vetor interse ca o. Veja listagem 36.4. Exemplo: int intersecao[size]; set_intersection (a,a+size,b,b+size,intersecao); ao); set union (a, a+size, b, b+size, uni Todos os valores do vetor a e b ser ao copiados para o vetor uni ao. Veja listagem 36.4. Exemplo: int uniao[size]; set_union (a,a+size,b,b+size,uniao); set symmetric dierence (a, a+size, b, b+size, sym dif ); Determina o conjunto de valores de a que n ao est ao em b e os valores de b que n ao est ao em a, e copia para o vetor sym_dif(). Veja listagem 36.4. Exemplo: int sym_dif[size]; set_symmetric_difference(a, a+size, b,b+size, sym_dif);
35.3.12
Um heap armazena os elementos de uma maneira semi-ordenada, de forma que a procura pelo maior elemento tenha um custo constante. A remo ca o do maior elemento e adi ca o de novos elementos tem tempo de processamento logar tmico. make heap (v.begin(), v.end()); Marca a pilha. O primeiro elemento de v e o maior. sort heap (v.begin(), v.end()); Ordena toda a pilha. push heap (v.begin(), v.end()); Adiciona elemento no container. pop heap (v.begin(), v.end()); Retira elemento do topo da pilha (maior elemento). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
607
35.4
Veremos a seguir exemplos de uso das fun co es gen ericas. Na listagem 35.1 apresentamos o uso de fun co es gen ericas como sort(); Listing 35.1: Usando sort(), find(), find_if(), fill().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 # include < iostream > # include < fstream > # include < iomanip > # include < string > # include < vector > # include < algorithm > using namespace std ;
// Classe de vetores // Algoritmos gen e ricos // Define o uso do espa c o de nomes std
// Declara ca ~ o de sobrecarg a de << para ostream e vector ostream & operator << ( ostream & os , const vector < int >& v ) { for ( int i = 0; i < v . size () ; i ++) os << " v [" << setw (3) << i << "]=" << setw (5) << v [ i ] << ; return os ; } // Declara ca ~ o de sobrecarg a de << para ofstream e vector ofstream & operator < < ( ofstream & os , const vector < int >& v ) { for ( int i = 0; i < v . size () ; i ++) os << setw (10) << v [ i ] << endl ; return os ; } // Declara ca ~ o e defini ca ~ o de fun ca ~ o predicado // Recebe um objeto do tipo armazenado no container // retorna verdadeiro ou falso . bool maiorQue5 ( int valor ) { return valor > 5; } int main () { string linha =" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\ n "; vector < int > v ; int data ; do { cout << "\ nEntre com o dado (" << setw (3) << v . size () << ") :"; cin >> data ; cin . get () ; if ( cin . good () ) v . push_back ( data ) ; } while ( cin . good () ) ; cin . get () ; cin . clear () ; // Reseta objeto cin para estado ok { ofstream fout (" vector . dat ") ; if (! fout ) return 0; fout << v << endl ; fout . close () ; } cout << "\ n " << linha << v << endl ;
608
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
int numero ; cout << "\ nEntre com o n u mero a ser localizado :"; cin >> numero ; cin . get () ; // Ponteiro para a posi ca ~ o localizada vector < int >:: iterator it = find ( v . begin () , v . end () , numero ) ; cout << "\ nN u mero localizad o na posi ca ~ o :" << ( it - v . begin () ) << endl ; // Localiza primeiro elemento que satisfaz a condi ca ~o // dada pela fun ca ~ o maiorQue5 it = find_if ( v . begin () , v . end () , maiorQue5 ) ; cout << "\ nN u mero maior que 5 localizado na posi ca ~ o :" << ( it - v . begin () ) << endl ;; // Ordena o container sort ( v . begin () , v . end () ) ; cout << "\ nVetor ap o s ordena ca ~ o com sort ( v . begin () ,v . end () ) \ n " << linha << v << endl ; // Preenche com o valor 45 fill ( v . begin () , v . end () , 45) ; cout << "\ nVetor ap o s fill ( v . begin () , v . end () , 45) ;\ n " << linha << v << endl ; // Retorna dimens~ a o e capacidade cout << " v . size () =" << v . size () << "\ nv . capacity () =" << v . capacity () << endl ; // R e d i m e n s i o n a o container v . resize (10) ; cout << "\ nVetor ap o s resize (10) :\ n " << linha << v << "\ nv . size () =" << v . size () << "\ nv . capacity () =" << v . capacity () << "\ n " << linha << endl ; cin . get () ; return 0; } [ b u e n o @ l d s c 0 5 Parte - III ] $ ./ a . out Entre com o dado ( 0) :45 Entre com o dado ( 1) :15 Entre com o dado ( 2) :91 Entre com o dado ( 3) :13 Entre com o dado ( 4) :26 Entre com o dado ( 5) : --------------------------------------------------------------v [ 0]= 45 v [ 1]= 15 v [ 2]= 91 v [ 3]= 13 v [ 4]= 26 Entre com o n u mero a ser localizado :91 N u mero localizado na posi ca ~ o :2 N u mero maior que 5 localizado na posi ca ~ o :0 Vetor ap o s ordena ca ~ o com sort ( v . begin () , v . end () ) --------------------------------------------------------------v [ 0]= 13 v [ 1]= 15 v [ 2]= 26 v [ 3]= 45 v [ 4]= 91 Vetor ap o s fill ( v . begin () , v . end () , 45) ; --------------------------------------------------------------v [ 0]= 45 v [ 1]= 45 v [ 2]= 45 v [ 3]= 45 v [ 4]= 45 v . size () =5 v . capacity () =8
609
No exemplo da listagem 35.2 mostramos o uso de sort() e copy(). O programa ordena as linhas de texto digitadas pelo usu ario ou as linhas de um arquivo de disco usando a fun ca o global OrdenaLinhasArquivo(). Listing 35.2: Usando sort() e copy() para ordenar linhas de texto.
# include # include # include # include # include # include < fstream > < iostream > < string > < vector > < iterator > < algorithm >
void O r d e n a L i n h a s A r q u i v o ( std :: istream & in , std :: ostream & out ) { std :: string linha ; std :: vector < std :: string > v ; while ( std :: getline ( in , linha ) ) v . push_back ( linha ) ; std :: sort ( v . begin () ,v . end () ) ; std :: cout << std :: endl ; std :: copy ( v . begin () ,v . end () , std :: ostream_iter at or < std :: string >( out ,"\ n " ) ) ; in . clear () ; return ; } int main () { using namespace std ; // Ordena linhas digitadas cout << " Digite diversas linhas de texto , e depois pressione ctrl + d :\ n "; O r d e n a L i n h a s A r q u i v o ( cin , cout ) ; cout << "\ nEntre com o nome do arquivo a ser ordenado :" < < endl ; string nomeArqui vo ; getline ( cin , nomeArquiv o ) ; ifstream fin ( nomeArquiv o . c_str () ) ; ofstream fout ((" Ordenado " + nomeArqui vo ) . c_str () ) ; O r d e n a L i n h a s A r q u i v o ( fin , fout ) ; return 0; } [ b u e n o @ l d s c 0 5 Parte - III ] $ ./ a . out Digite diversas linhas de texto , e depois pressione ctrl + d : Testando a ordem em que o texto vai sair ser a que vai dar certo ? Testando a ordem certo ? em que o texto vai sair ser a que vai dar Entre com o nome do arquivo a ser ordenado :
610
Entrada . dat
No exemplo da listagem 35.3 usamos copy(), para copiar dados de um arquivo de disco para um vetor. A seguir ordenamos o vetor e o enviamos para tela. Listing 35.3: Usando copy() para copiar dados de um arquivo de disco para um <vector>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # include # include # include # include # include < algorithm > < fstream > < iostream > < iterator > < vector >
int main () { using namespace std ; ifstream in (" dados . dat ") ; vector < int > v ; copy ( istream_itera to r < int >( in ) , istream_iter at or < int >() , b a c k _ i n s e r t e r ( v ) ) ; sort ( v . begin () ,v . end () ) ; copy ( v . begin () , v . end () , ostream_iter at or < int >( cout , "\ n ") ) ; return 0; } [ b u e n o @ l d s c 0 5 Parte - III ] $ ./ a . out 15 25 35 48 65 75 98
Na listagem 35.4 apresentamos o uso de fun co es gen ericas como nth_element() e find() para obter a mediana de um grupo de dados. A listagem e documentada. Note que estamos acostumados a usar container<tipo>::value_type para obter a informac a o do tipo de valor armazenado no container. Mas na fun ca o Mediana() n ao temos o container. Temos apenas os iteradores. Ou seja, precisamos obter o container a partir dos iteradores. Este e o motivo para criarmos o apelido typedef typename std::iterator_traits<iterador>::value_type value_type; Listing 35.4: Usando <vector> com algoritmos gen ericos: C alculo da mediana.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # include # include # include # include # include < iostream > < algorithm > < functional > < iterator > < vector >
template < typename iterador , typename operadorCo mp ar a ca o > iterador Mediana ( iterador first , iterador last , o p e r a d o r C o m p a r a c a o opComp ) { // Cria apelido typedef typename std :: iterator_trai ts < iterador >:: value_type value_type ; std :: vector < value_type > tmp ( first , last ) ; // Determina posi ca ~ o m e dia typename std :: vector < value_type >:: size_type posicao = tmp . size () / 2; // Localiza no container recebido o valor da mediana std :: nth_eleme nt ( tmp . begin () , tmp . begin () + posicao , tmp . end () , opComp ) ; return std :: find ( first , last , tmp [ posicao ]) ;
611
// Determina a mediana e mostra na tela int mediana = * Mediana ( v . begin () , v . end () , std :: less < int >() ) ; std :: cout << mediana << std :: endl ; return 0; } [ b u e n o @ l d s c 0 5 Parte - III ] $ ./ a . out 7284
No exemplo da listagem 35.5 criamos uma classe TCSeries que recebe dois par ametros, o n umero de elementos a serem criados e o incremento. Note que o operador() e sobrecarregado, e retorna o pr oximo valor da s erie. Ou seja, o objeto TCSeries se comporta como uma fun ca o que e chamada n vezes. Um objeto do tipo TCSeries e criado na chamada ao m etodo generat_n(), passamos para o construtor o valorInicial e o incremento. O m etodo generat_n(), executa nRepeti co es (chamadas) ao operator() do objeto criado, e envia para tela os valores retornados. Listing 35.5: Usando generator_n() para gerar uma s erie de dados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # include < algorithm > # include < iostream > # include < iterator > template < typename T > class TCSeries { public : // Construtor TCSeries ( const T & n =0 , const T & i =1) : proximo (n - i ) , incremento ( i ) {} // Operador s o b r e c a r r e g a d o T operator () () { return proximo += incremento ; } private : T proximo ; T incremento ; }; int main () { int valorInicial , incremento , nRepeticoe s ; std :: cout << " Entre com o valor inicial :"; std :: cin >> v a l o r I n i c i a l ; std :: cin . get () ; std :: cout << " Entre com o valor do incremento :"; std :: cin >> increment o ; std :: cin . get () ; std :: cout << " Entre com o n u mero de elementos :"; std :: cin >> nRepeticoe s ; std :: cin . get () ; std :: generate_n ( std :: ostream_itera t or < int >( std :: cout ,"\ n ") , // Destino nRepeticoes , // N u mero repeti co ~ es TCSeries < int >( valorInicial , incremento ) // Objeto fun ca ~o ); }
612
Entre com o valor inicial :123 Entre com o valor do increment o :3 Entre com o n u mero de elementos :6 123 126 129 132 135 138
35.5
D e uma olhada na Internet e procure por STL. Voc e encontrar a muitos sites com exemplos interessantes. next_permutation() e prev_permutation() permutam os elementos do container. Veja listagem 36.4. No exemplo abaixo, o vetor v1 e adicionado ao m de v2. A fun ca o back_inserter() chama v2.push_back() para cada elemento de v1. copy ( v1.begin(), v1.end(), back_inserter(v2) ); No exemplo abaixo, o deque d1 e adicionado no m de d2, front_insert() chama a fun ca o push_front() para cada elemento de d2. copy ( d1.begin(), d1.end(), front_inserter(d2) ); Se um algoritmo qualquer tem uma vers ao gen erica e uma c opia espec ca para um determinado container ( e um m etodo do container), ent ao a vers ao do container e mais r apida. A classe <string> pode ser usada como um vetor. Veja os exemplos. Exemplo: for(int i = 0; i < s.size(); i++) cout < < s[i] < < endl; for(string::const_iterator it = s.begin(); it != s.end(); it++) cout < < *it < < endl; Voc e encontra informa co es e outros exemplos de uso das fun co es da STL nas refer encias [Deitel and Deitel, 2002], e sobre programa ca o gen erica, em [Austern, 1998].
35.6
Neste cap tulo aprendemos a utilizar um conjunto de fun co es que s ao utilizadas na programa ca o gen erica e que s ao fornecidas com a STL. Vimos uma introdu ca o ` a programa ca o gen erica, e a seguir apresentamos a classica ca o das fun co es gen ericas (se modica ou n ao o container, tipo de iterador utilizado, e tipos de opera co es suportadas). Vimos que as fun co es gen ericas s ao classicadas da seguinte forma: preenchimento, compara ca o, remo ca o, trocas, misturar/mesclar/inverter, pesquisa, ordena ca o, classica ca o, transforma ca o, matem aticos, opera co es com conjuntos, ordena cao de pilhas. No nal do cap tulo vimos diversos exemplos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
35.7. EXERC ICIOS Nota: no cap tulo Cap tulo 36 - Objetos Fun co es da STL, veremos outros exemplos.
613
35.7
Exerc cios
1. Quais as fun co es gen ericas que n ao mudam o container? 2. Modique a listagem 35.1. Acrescente o uso de: nd rst of(); adjacent nd(); binary search(); lower bound(); upper bound(); equal range(); search(); search n();. 3. Modique a listagem 35.2, de tal forma que o usu ario possa denir o nome do arquivo de disco e a ordem de ordena ca o (ascendente/descendente). 4. S o para sentir a diferen ca, implemente a listagem 35.3 sem usar a STL. 5. Modique a listagem 35.4. Adicione o c alculo da m edio e desvio padr ao. 6. Modique a listagem 35.5. Crie a possibilidade de se criar s eries logar tmicas. 7. Monte um exemplo que leia de um InputIterator e escreva para um OutputIterator. 8. Quais os algoritmos gen ericos utilizados para opera co es de transforma ca o? 9. Monte um exemplo que utilize as fun co es de preenchimento (se ca o 35.3.1) e de remo ca o (se ca o 35.3.3). 10. Monte um exemplo que utilize as fun co es de compara ca o (se ca o 35.3.2) e de trocas (se ca o 35.3.4). 11. Monte um exemplo que fa ca pesquisas em um vetor (se ca o 35.3.6) e localize n umeros primos. 12. Monte um exemplo que aplique algoritmos de transforma ca o em polin omios (se ca o 35.3.9). 13. Implemente e teste a fun ca o unique2() (veja se ca o 35.3.8). 14. Voc e deve comentar o c odigo abaixo, e a seguir dizer o que faz o m etodo M? Exemplo: #include <fstream> #include <iterator> void CNome::M(string arqA, string arqB) { std::ifstream fin ( arqA.c_str() ); std::ofstream fout( arqB.c_str() ); std::copy(std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(fout)); } 15. Procure na Internet informa co es sobre os algoritmos stable_partition e stable_sort. 16. Procure na Internet informa co es sobre os algoritmos next_permutation e prev_permutation.
614
Cap tulo 36
36.1
Algumas classes podem ter o operator() sobrecarregado. Desta forma, pode-se fazer: Tipo NomeObjeto; TipoParametro parametro; int resultado = NomeObjeto(parametro); ou seja, o objeto se comporta como sendo uma fun ca o. Como esse procedimento e muito usado, a STL inclui classes para objetos fun co es. Uma classe para fun co es que recebem um par ametro (fun co es un arias, se ca o 36.1.1) e outra classe para fun co es que recebem dois par ametros (fun co es bin arias, se ca o 36.1.2). Essas fun co es s ao inclu das no arquivo de cabe calho <functional>.
36.1.1
Fun co es un arias recebem apenas um par ametro. Como seu uso e muito comum, a STL inclui a classe template unary_function<TipoPar^ ametro, TipoRetorno>. Assim, voc e pode criar suas pr oprias fun co es un arias fazendo uma heran ca de unary_function. Veja o exemplo: Exemplo: #include <cmath> class seno: public unary_function< double, double > { public: double y; 615
616
36.2. OBJETOS FUNC OES FORNECIDOS PELA STL double operator() (double x) // Operador sobrecarregado { return y = std::sin(x); } };
36.1.2
Fun co es bin arias recebem dois par ametros. Como seu uso tamb em e muito comum, a STL inclui a classe template binary_function<TipoPar^ ametro,TipoPar^ ametro, TipoRetorno>. Assim, voc e pode criar suas pr oprias fun co es bin arias fazendo uma heran ca de binary_function. Veja o exemplo: Exemplo: #include <cmath> class potencia : public binary_function< double, double, double > { public: double z; double operator() (double x,double y) { return z = std::pow(x,y); } };
36.2
Al em das classes unary_function e binary_function, a STL fornece um conjunto de func o es objetos de uso comum. Essas fun co es s ao listadas a seguir.
36.2.1
As fun co es atitm eticas podem ser utilizadas em algoritmos gen ericos. Por exemplo, a fun ca o bin aria plus<> realiza a soma de dois elementos do mesmo tipo. Observe que o operador+ precisa ter sido sobrecarregado para o tipo. plus<> Soma (x + y). minus<> Subtra ca o (x - y). times<> Multiplica ca o (x * y). multiplies<> Multiplica ca o (x * y). divides<> Divis ao (x / y). modulus<> M odulo (x % y). negate<> Nega ca o (- x). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
617
No exemplo a seguir cria-se um objeto fun ca o div, que e usado para realizar a divis ao de 20.5 por 3. Listing 36.1: Usando divides<>.
1 2 3 4 5 6 7 8 9 10 11 # include < functional > # include < iostream > int main () { // Cria objeto fun c~ a o para r e a l i z a c~ a o de d i v i s ~ a o de n u m e r o s float std :: divides < float > div ; std :: cout << div ( 20.5 , 3 ) << std :: endl ; return 0; } 6.83333
No exemplo a seguir usamos a fun ca o gen erica accumulate() e o objeto fun ca o multiplies<>, para calcular a m edia geom etrica de um vetor. . Listing 36.2: Usando multiplies<>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # include < cmath > # include < vector > # include < numeric > # include < functional > # include < iostream > using namespace std ; double M e d i a G e o m e t r i c a ( const vector < int >& v ) { double temp = accumulate ( v . begin () , v . end () , 1 , multiplies < int >() ) ; return ( pow ( temp ,1.0/ v . size () ) ) ; } int main () { vector < int > v ; int valor ; cout << " Entre com valores inteiros : " << endl ; while ( cin >> valor ) { v . push_back ( valor ) ; } cout << " M e dia Geom e tric a = " << M e d i a G e o m e t r i c a ( v ) << endl ; return 0; } Entre com valores inteiros : 5 6 7 8 9 4 3 2 1 M e dia Geom e trica = 4.14717
36.2.2
equal to<> Testa igualdade (x == y). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
618 not equal to<> Testa diferen ca (x != y). greater<> Maior que (x > y). less<> Menor que (x < y).
greater equal<> Maior que ou igual a (x >= y). less equal<> Menor que ou igual a (x <= y). No exemplo a seguir criamos um objeto do tipo priority_queue que ir a armazenar n umeros do tipo float. O container a ser utilizado e um <vector>, e utilizamos greater<float> (maior que) para denir o operador de compara ca o a ser utilizado na ordena ca o. Exemplo: priority_queue< float, vector<float>, greater<float> > objQueue;
36.2.3
logical and<> E logico (x & & y). logical or<> Ou l ogico (x || y). logical not<> Negac ao l ogica (! x)
Veja na listagem 36.3 um exemplo de classe fun ca o. O exemplo inicia-se denindo uma classe fun ca o objeto CFatorial, herdeira de unary_function. Dentro de main(), cria um <deque> com 10 elementos e preenche-os com valores seq uenciais. A seguir, usa a fun ca o gen erica transform() para executar o objeto fun ca o CFatorial para cada elemento do deque d e armazenar o resultado no vetor v. Observe que a fun ca o gen erica transform() aplica uma transforma ca o a cada elemento do <deque> d. A seguir, armazena o resultado dessa transforma ca o em v. Listing 36.3: Criando e usando uma classe fun ca o.
1 2 3 4 5 6 7 8 9 10 11 12 13 # include < iostream > # include < functional > # include < deque > # include < vector > # include < algorithm > # include < iterator > # include < iomanip > using namespace std ; // Classe fun c~ a o , cria uma fun c~ a o objeto a partir de uma fun c~ a o un a ria template < typename Parametro , typename Retorno > class TCFatorial : public unary_function < Parametro , Retorno > {
619
// D e t e r m i n a o f a t o r i a l dos n u m e r o s a r m a z e n a d o s em origem // e a r m a z e n a no vetor d e s t i n o transform ( origem . begin () , origem . end () , destino . begin () , TCFatorial < int , int >() ) ; cout << " N u meros : " ; copy ( origem . begin () , origem . end () , ostream_iter at or < int >( cout , " \ t " ) ) ; cout << " \ ne fatoriais : " ; copy ( destino . begin () , destino . end () , ostream_itera to r < int >( cout , " \ t " ) ) ; cout << endl << endl ; char resp ; TCFatorial < int , int > o b j e t o _ f u n c a o ; do { cout << " Entre com um n u mero ( int ) : " ; int numero ; cin >> numero ; cin . get () ; cout << " N u mero = " << setw (7) << numero << " fatorial = " << setw (7) << o b j e t o _ f u n c a o ( numero ) << " \ nContinua r ( s / n ) ? " ; cin . get ( resp ) ; cin . get () ; } while ( resp == s || resp == S ) ; return 0; }
N u meros 9
: 0 1
1 2
2 6
3 24
5 120
6 720
7 5040
8 40320
e fatoriais : 1 362880
120
Veja na listagem 36.4 outro exemplo de uso de fun co es gen ericas. Neste exemplo criamos a classe CTesteFuncoesGenericas, com os m etodos EntradaUsuario(), InicializaVetor() e Run(). Os m etodos EntradaUsuario() e InicializaVetor(), s ao utilizados para deni ca o dos valores do vetor a ser usado nos algoritmos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
620
Na primeira parte da fun ca o Run(), estamos enviando para tela a lista de fun co es dispon veis para teste. Observe que o nome das fun co es s ao armazenadas no vetor fun co es e que usamos setw() para mostrar de forma organizada a lista de fun co es. Na segunda parte de Run() diversas fun co es gen ericas s ao testadas. Note que o usu ario entra com o n umero da fun ca o a ser testada e a seguir a fun ca o e testada. O exemplo e extenso e mostra o uso de diversas fun co es gen ericas. Listing 36.4: Usando fun co es gen ericas e objetos da STL.
# include # include # include # include # include # include # include # include # include < iostream > < iomanip > < string > < vector > < algorithm > < memory > < cstdlib > < numeric > < functional > // // // // // // // // // E n t r a d a e sa da de dados Manipuladores S t r i n g s de C ++ Classe de v e t o r e s Classe para a l g o r i t m o s g e n ericos destroe e construct Fun c~ a o rand Fun c~ ao inner_product Fun c~ oes diversas
/* * Classe para teste dos a l g o r i t m o s g e n e r i c o s */ class C T e s t e F u n c o e s G e n e r i c a s { public : vector < int > v , v2 , v3 ; // A t r i b u t o s string msg ; C T e s t e F u n c o e s G e n e r i c a s () // C o n s t r u t o r { InicializaVetor(v); // P r e e n c h e o vetor v com v a l o r e s v3 = v2 = v ; msg = " \n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\ n " ; } // M etodos p ublicos void E n t r a d a U s u a r i o ( vector < int >& vetor ) ; void I n i c i a l i z a V e t o r ( vector < int >& vetor , int n = 5 ) ; bool Run () ; private : // M etodos privados void U s o _ d e _ f i l l _ n () ; // P r e e n c h i m e n t o void U s o _ d e _ e q u a l () ; // C o m p a r a c~ ao void U s o _ d e _ m i s m a t c h () ; void U s o _ d e _ i n c l u d e s () ; void U s o _ d e _ r e m o v e _ c o p y _ i f () ; // R e m o c~ ao void U s o _ d e _ r e p l a c e _ c o p y _ i f () ; // Trocas void U s o _ d e _ i n p l a c e _ m e r g e () ; // M i s t u r a r / m e s c l a r / i n v e r t e r void U s o _ d e _ r e v e r s e _ c o p y () ; void U s o _ d e _ r a n d o m _ s h u f f l e () ; void U s o _ d e _ f i n d _ i f _ o f f () ; // P e s q u i s a void U s o _ d e _ a d j a c e n t _ d i f f e r e n c e () ; void U s o _ d e _ s e a r c h _ n () ; void U s o _ d e _ b i n a r y _ s e a r c h () ; void U s o _ d e _ a d v a n c e () ; void U s o _ d e _ n e x t _ p e r m u t a t i o n () ; // O r d e n a c~ ao void U s o _ d e _ r e v e r s e () ; void U s o _ d e _ r o t a t e () ; void U s o _ d e _ g e n e r a t e () ; // T r a n s f o r m a c~ ao void U s o _ d e _ f o r _ e a c h () ; void U s o _ d e _ t r a n s f o r m () ; void U s o _ d e _ n t h _ e l e m e n t () ; // M a t e m aticos void U s o _ d e _ c o u n f _ i f () ; void U s o _ d e _ a c c u m u l a t e () ; void U s o _ d e _ i n n e r _ p r o d u c t () ;
621
622
char * vs [] = { " fill_n " , " equal " , " mismatch " , " includes " , " r e m o v e _ c o p y _ i f " , " replace_copy_if", " inplace_merge", " reverse_copy", " random_shuffle", " find_if " , " find_if_of f " , " a d j a c e n t _ d i f f e r e n c e " , " search_n " , " b i n a r y _ s e a r c h " , " advance " , " n e x t _ p e r m u t a t i o n " , " reverse " , " rotate " , " generate " , " for_each " , " transform " , " nth_eleme n t " , " counf_if " , " accumulate " , " i n n e r _ p r o d u c t " , " set_union " , " s e t _ i n t e r s e c t i o n " , " s e t _ d i f f e r e n c e " , " s e t _ s y m m e t r i c _ d i f f e r e n c e " , " make_heap " , " plus " , " minus " , " times " , " multiplies " , " divides " , " modulus " , " negate " , " equal_to " , " n o t _ e q u a l _ t o " , " greater " , " less " , " g r e a t e r _ e q u a l " , " less_equal " , " logical_a nd " , " logical_or " , " logical_n o t " , " bind2nd " , " not1 " , " men_fun_r ef " , " Mostra vetor " , " Sair do Programa " }; vector < string > funcoes ; cout << " = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \ n " << " = = = = = = = = = = = = = Qual fun ca ~ o deseja testar ??? = = = = = = = = = = = = = = = = \ n " << " = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \ n " ; for ( int i = 0; i < 30 ; i ++ ) { funcoes . push_back ( vs [ i ]) ; if ( funcoes [ i ] != " " ) cout << " Uso de " << funcoes [ i ] << setw (50 - funcoes [ i ]. size () ) << setfill ( . ) << i << endl ; } int selecao ; cin >> selecao ; cin . get () ; if ( selecao >= funcoes . size () ) return 0; InicializaVetor(v); cout << setfill ( ) << " Vetor v = " << v << endl ; if ( funcoes [ selecao ]== " fill_n " ) U s o _ d e _ f i l l _ n () ; else if ( funcoes [ selecao ]== " equal " ) U s o _ d e _ e q u a l () ; else if ( funcoes [ selecao ]== " mismatch " ) U s o _ d e _ m i s m a t c h () ; else if ( funcoes [ selecao ]== " includes " ) U s o _ d e _ i n c l u d e s () ; else if ( funcoes [ selecao ]== " r e m o v e _ c o p y _ i f " ) U s o _ d e _ r e m o v e _ c o p y _ i f () ; else if ( funcoes [ selecao ]== " r e p l a c e _ c o p y _ i f " ) U s o _ d e _ r e p l a c e _ c o p y _ i f () ; else if ( funcoes [ selecao ]== " i n p l a c e _ m e r g e " ) U s o _ d e _ i n p l a c e _ m e r g e () ; else if ( funcoes [ selecao ]== " r e v e r s e _ c o p y " ) U s o _ d e _ r e v e r s e _ c o p y () ; else if ( funcoes [ selecao ]== " r a n d o m _ s h u f f l e " ) U s o _ d e _ r a n d o m _ s h u f f l e () ; else if ( funcoes [ selecao ]== " find_if " ) U s o _ d e _ b i n d 2 n d () ; // Uso de find_if else if ( funcoes [ selecao ]== " find_if_o ff " ) U s o _ d e _ f i n d _ i f _ o f f () ; else if ( funcoes [ selecao ]== " a d j a c e n t _ d i f f e r e n c e " ) U s o _ d e _ a d j a c e n t _ d i f f e r e n c e () ; else if ( funcoes [ selecao ]== " search_n " ) U s o _ d e _ s e a r c h _ n () ; else if ( funcoes [ selecao ]== " b i n a r y _ s e a r c h " ) U s o _ d e _ b i n a r y _ s e a r c h () ; else if ( funcoes [ selecao ]== " advance " ) U s o _ d e _ a d v a n c e () ; else if ( funcoes [ selecao ]== " n e x t _ p e r m u t a t i o n " ) U s o _ d e _ n e x t _ p e r m u t a t i o n () ; else if ( funcoes [ selecao ]== " reverse " ) U s o _ d e _ r e v e r s e () ; else if ( funcoes [ selecao ]== " rotate " ) U s o _ d e _ r o t a t e () ; else if ( funcoes [ selecao ]== " generate " ) U s o _ d e _ g e n e r a t e () ; else if ( funcoes [ selecao ]== " for_each " ) U s o _ d e _ f o r _ e a c h () ; else if ( funcoes [ selecao ]== " transform " ) U s o _ d e _ t r a n s f o r m () ; else if ( funcoes [ selecao ]== " nth_eleme nt " ) U s o _ d e _ n t h _ e l e m e n t () ; else if ( funcoes [ selecao ]== " counf_if " ) U s o _ d e _ c o u n f _ i f () ; else if ( funcoes [ selecao ]== " accumulate " ) U s o _ d e _ a c c u m u l a t e () ; else if ( funcoes [ selecao ]== " i n n e r _ p r o d u c t " ) U s o _ d e _ i n n e r _ p r o d u c t () ; else if ( funcoes [ selecao ]== " set_union " ) U s o _ d e _ s e t _ u n i o n () ; else if ( funcoes [ selecao ]== " s e t _ i n t e r s e c t i o n " ) U s o _ d e _ s e t _ i n t e r s e c t i o n () ; else if ( funcoes [ selecao ]== " s e t _ d i f f e r e n c e " ) U s o _ d e _ s e t _ d i f f e r e n c e () ; else if ( funcoes [ selecao ]== " s e t _ s y m m e t r i c _ d i f f e r e n c e " ) U s o _ d e _ s e t _ s y m m e t r i c _ d i f f e r e n c e () ;
623
// Mostra o vetor else if ( funcoes [ selecao ]== " Mostra vetor " ) cout << setfill ( ) << " Vetor v = " << v << endl ; // Sai do p r o g r a m a else if ( funcoes [ selecao ]== " SAIR DO PROGRAMA " ) return 0; cout << " \a - - > Pressione enter para continuar " ; cin . get () ; cin . clear () ; return 1; // Se n~ a o e s c o l h e u sair r e t o r n a v e r d a d e i r o } // P r e e n c h i m e n t o void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ f i l l _ n () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // C o m p a r a c~ ao void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ e q u a l () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ m i s m a t c h () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ i n c l u d e s void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ i n c l u d e s () { v3 = v2 = v ; v3 . push_back (123) ; v2 . push_back (333) ; cout << setw (30) << " Vetor v2 = " << v2 << endl ; cout << setw (30) << " Vetor v3 = " << v3 << endl ; // cout . imbue ( locale (" pt_BR ") ) ; // o p c i o n a l cout << setw (30) << " v inclui v2 -> " << boolalpha << includes ( v . begin () , v . end () , v2 . begin () , v2 . end () ) << endl ; cout << setw (30) << " v3 inclui v2 -> " << boolalpha << includes ( v3 . begin () , v3 . end () , v2 . begin () , v2 . end () ) << endl ; cout << setw (30) << " v inclui v3 -> " << boolalpha << includes ( v . begin () , v . end () , v3 . begin () , v3 . end () ) << endl ; cout << setw (30) << " v2 inclui v3 -> " << boolalpha << includes ( v2 . begin () , v2 . end () , v3 . begin () , v3 . end () ) << endl ; cout << setw (30) << " v2 inclui v -> " << boolalpha << includes ( v2 . begin () , v2 . end () , v . begin () , v . end () ) << endl ; cout << setw (30) << " v3 inclui v -> " << boolalpha <<
624
} // R e m o c~ ao void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ r e m o v e _ c o p y _ i f () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // Trocas void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ r e p l a c e _ c o p y _ i f () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // M i s t u r a r / m e s c l a r/ i n v e r t e r void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ i n p l a c e _ m e r g e () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ r e v e r s e _ c o p y () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // E m b a r a l h a os e l e m e n t o s do c o n t a i n e r void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ r a n d o m _ s h u f f l e () { r a n d o m _ s h u f f l e ( v . begin () ,v . end () ) ; cout << " Vetor v ap o s r a n d o m _ s h u f l e = " << v << endl ; sort ( v . begin () ,v . end () ) ; cout << " Vetor v ap o s sort = " << v << endl ; } // P e s q u i s a void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ f i n d _ i f _ o f f () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ a d j a c e n t _ d i f f e r e n c e void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ a d j a c e n t _ d i f f e r e n c e () { cout << " uso de a d j a c e n t _ d i f f e r e n c e : " ; a d j a c e n t _ d i f f e r e n c e ( v . begin () , v . end () , ostream_itera to r < int >( cout , " " ) ) ; cout << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e a r c h _ n () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ b i n a r y _ s e a r c h // R e t o r n a v e r d a d e i r o se o valor for e n c o n t r a d o void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ b i n a r y _ s e a r c h () { cout << " Valor " << 3 << ( b i n a r y _ s e a r c h ( v . begin () ,v . end () ,3) ? " encontrado " : " n~ a o encontrado " ) << endl ; cout << " Valor " << 22 << ( b i n a r y _ s e a r c h ( v . begin () ,v . end () ,22) ? " encontrado " : " n~ a o encontrado " ) << endl ; } // Avan ca o iterador void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ a d v a n c e () { cout << " A partir da posi ca ~ o 0 , devo avan c ar quantas casas ( maximo = " << v . size () << " ) : " ; int n ; cin >> n ; cin . get () ; vector < int >:: iterator it = v . begin () ; advance ( it , n ) ; cout << " O iterador aponta agora para o elemento na posi ca ~o "
625
// T r a n s f o r m a c~ ao // C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ g e n e r a t e : a fun c~ a o c h a m a d a por g e n e r a t e n~ ao // recebe p a r ^ a m e t r o e r e t o r n a um e l e m e n t o para o c o n t a i n e r no e x e m p l o a // seguir chama a fun c~ a o rand para p r e e n c h e r o c o n t a i n e r com n umeros aleat orios void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ g e n e r a t e () { generate ( v . begin () ,v . end () , rand ) ; cout << " Vetor de n u meros aleat o rios v = " << v << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ f o r _ e a c h () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ t r a n s f o r m () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // M a t e m aticos void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ n t h _ e l e m e n t () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ c o u n f _ i f () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // A c u m u l a v a l o r e s no i n t e r v a l o e s p e c i f i c a d o void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ a c c u m u l a t e () { for ( int i = 0; i < v . size () ; i ++ ) cout << " Valor acumulado at e " << i << " = " << accumulate ( v . begin () ,v . begin () ,0 ) << endl ; // + 1 } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ i n n e r _ p r o d u c t () { cout << " ENTRE COM OS DADOS DO VETOR v \ n " ;
626
EntradaUsuario(v); // E n t r a d a dos dados do vetor v cout << " \ nENTRE COM OS DADOS DO VETOR v2 \ n " ; E n t r a d a U s u a r i o ( v2 ) ; // E n t r a d a dos dados do vetor v2 cout << " \ n " << " Vetor v = " << v << " \ nVetor v2 = " << v2 << " \ n P r o d u t o I n t e r n o v . v2 = " << i n n e r _ p r o d u c t ( v . begin () ,v . end () , v2 . begin () ,0) << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e t _ u n i o n () { v3 = v2 = v ; v3 . push_back (123) ; v2 . push_back (333) ; cout << " Vetor v2 = " << v2 << " \ nVetor v3 = " << v3 << " \ nUni~ a o de v2 e v3 = " ; set_union ( v3 . begin () , v3 . end () , v2 . begin () , v2 . end () , ostream_iter at or < int >( cout , " \ t " ) ) ; cout << endl ; } // C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e t _ i n t e r s e c t i o n void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e t _ i n t e r s e c t i o n () { cout << " Interse ca ~ o de v e v2 = " ; s e t _ i n t e r s e c t i o n ( v . begin () ,v . end () , v2 . begin () , v2 . end () , ostream_itera to r < int >( cout , " \ t " ) ) ; cout << endl ; } // C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e t _ d i f f e r e n c e void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e t _ d i f f e r e n c e () { cout << " diferen c a de v2 e v3 ( tem em v2 e n~ a o tem em v3 ) = " ; s e t _ d i f f e r e n c e ( v2 . begin () , v2 . end () , v3 . begin () , v3 . end () , ostream_itera to r < int >( cout , " \ t " ) ) ; cout << endl ; } // C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e t _ s y m m e t r i c _ d i f f e r e n c e void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ s e t _ s y m m e t r i c _ d i f f e r e n c e () { cout << " diferen c a sim e trica de v2 e v3 ( tem em v2 e n~ a o tem em v3 " ; cout << " ou tem em v3 e n~ a o tem em v2 ) = " ; s e t _ s y m m e t r i c _ d i f f e r e n c e ( v2 . begin () , v2 . end () , v3 . begin () , v3 . end () , ostream_iter at or < int >( cout , " \ t " ) ) ; cout << endl ; } // O r d e n a c~ a o por pilha void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ m a k e _ h e a p () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // F u n c~ o e s objeto // Uso da fun c~ ao bin a r i a plus e de t r a n s f o r m void C T e s t e F u n c o e s G e n e r i c a s :: Uso_de_pl us () { cout << " Vetor v = " << v << " \ nVetor v2 = " << v2 << endl ; transform ( v . begin () ,v . end () , v2 . begin () , v3 . begin () , plus < int >() ) ; cout << " Vetor v3 = v + v2 = " << v3 << endl ; }
627
628
// ir a para o in cio do vetor void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ n o t _ e q u a l _ t o () { InicializaVetor(v); const float valor = 2; partition ( v . begin () , v . end () , bind2nd ( not_equal_to < int >() , valor ) ) ; cout << " Rearranja o vetor de forma que todos os elementos " << " \ ndiferente s de 2 v~ a o para o in cio " << " \ nVetor v ap o s not_equal_to < int >(2) = " << v << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ g r e a t e r () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // Cada e l e m e n t o do vetor menor que 2 ir a para o in cio void C T e s t e F u n c o e s G e n e r i c a s :: Uso_de_le ss () { InicializaVetor(v); const float valor = 2; partition ( v . begin () , v . end () , bind2nd ( less < int >() , valor ) ) ; cout << " Rearranja o vetor de forma que todos os elementos " << " \ nmenores que 2 v~ a o para o in cio " << " \ nVetor v ap o s less < int >(2) = " << v << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ g r e a t e r _ e q u a l () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ l e s s _ e q u a l () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // F u n c~ oes l ogicas void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ l o g i c a l _ a n d () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ l o g i c a l _ o r () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ l o g i c a l _ n o t () { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } // A d a p t a d o r e s void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ b i n d 2 n d () { vector < int >:: iterator it = find_if ( v . begin () ,v . end () , not1 ( bind2nd ( greater_equal < int >() ,20) ) ) ; cout << " Valor maior que 20 localizado na posi ca ~ o " << ( it - v . begin () ) << " com o valor " << * it ; } void C T e s t e F u n c o e s G e n e r i c a s :: U s o _ d e _ m e n _ f u n _ r e f ( const vector < string >& s ) { { cout << msg << " Exerc cio : Montar este exemplo . " << msg << endl ; } /* vector < string >:: c o n s t _ i t e r a t o r it = f i n d _ i f( s . begin () ,s . end () , m e n _ f u n _ r e f (& string :: empty ) ) ; cout << " String vazia na p o s i c~ a o :" << it - s . begin () << endl ; */ } int main () { C T e s t e F u n c o e s G e n e r i c a s obj ; while ( obj . Run () ) ;
629
36.3
36.3.1
O adaptador bin2nd()
Alguns objetos fun co es, como greater_equal() precisam receber dois par ametros. Exemplo: greater_equal(20,30); Se uma fun ca o gen erica varre o container e utiliza apenas um par ametro, ent ao o uso de fun co es como greater_equal() ca inviabilizado. Para resolver este problema a STL incluiu o m etodo bin2nd(). O mesmo recebe a fun ca o gen erica a ser executada e o segundo par ametro a ser utilizado. O primeiro par ametro e obtido do container. Veja exemplos de uso de bind2nd nos m etodos Uso_de_bind2nd(); e Uso_de_divides(); da listagem 36.4.
36.3.2
Os adaptadores not1(),not2()
A fun ca o gen erica not1() e usada para negar uma fun ca o un aria e not2() para negar uma fun ca o bin aria. Podemos usar not1() para negar o resultado de uma fun ca o predicado. Veja exemplo de uso de not1() no m etodo Uso_de_bind2nd() da listagem 36.4.
36.3.3
O conjunto de fun co es men_fun s ao adaptadores da biblioteca padr ao, que possibilitam a aplica ca o de algoritmos da biblioteca padr ao aos m etodos de objetos denidos pelo usu ario. e um adaptador que possibilita a aplica ca o de algoritmos da bibliA fun ca o men_fun ref() oteca padr ao a m etodos de objetos denidos pelo usu ario. No exemplo a seguir, criamos um vetor de endere cos e a seguir executamos o m etodo Saida() de cada objeto do vetor usando o algoritmo for_each(): Exemplo: std vector< CEndereco > ve; ... std::for_each(ve.begin(), ve.end(), std::men_fun_ref(&CEndereco::Saida)); Note no exemplo acima que o vetor armazena objetos do tipo CEndereco e n ao ponteiros para CEndereco. A pergunta que ca e, e se tiv essemos um vetor de ponteiros, como executar amos for_each()? A solu ca o e usar o algoritmo men_fun(). Veja o exemplo: Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
630
36.4. RESUMO DO CAP ITULO Exemplo: std vector< CEndereco* > vpe; std::for_each(vpe.begin(), vpe.end(), std::men_fun(&CEndereco::Saida)).
J a a fun ca o men_fun_ptr() e utilizada para retornar um ponteiro para uma fun ca o membro (diferenciando um ponteiro de fun ca o de um objeto fun ca o). Na listagem 36.4, a fun ca o men_fun_ref() e usada para converter o ponteiro de m etodo string::empty, em uma referencia para fun ca o (veja o m etodo Uso_de_men_fun_ref()). Lembre-se, a maneira como devemos passar um ponteiro para um m etodo membro (se ca o F.7) e diferente da maneira como passamos um ponteiro de fun ca o (se ca o F.6). Nota: a biblioteca Boost, Cap tulo ?? - A Biblioteca Boost, inclui vers oes mais elaboradas dos adaptadores men_fun(). Consulte o manual da biblioteca.
36.3.4
Podemos criar nossos pr oprios algor tmos gen ericos. O exemplo a seguir, adaptado de [Solter and Kleper, 2005] mostra uma fun ca o gen erica. A fun ca o padr ao std::swap(A,B); troca o conte udo de A por B usando um objeto tempor ario, o que pode ser lento, pois todos os atributos de A e B precisam ser copiados. Em alguns casos voc e quer trocar apenas parte do objeto. Isto pode ser resolvido usando-se uma especializa ca o de swap (o que e mais r apido). Veja no exemplo a seguir a especializa ca o de swap para uma classe Tipo que tem um atributo x, o atributo que queremos trocar: Exemplo: // Especializa c~ ao de swap template<> void swap<Tipo>( Tipo A, Tipo B ) { swap(A.x,B.x); // Troca o conte udo de A.x por B.x }
36.4
Apresentamos neste cap tulo uma introdu ca o aos objetos fun co es da STL. A seguir vimos as fun co es un arias (recebem um par ametro) e bin arias (recebem dois par ametros). Aprendemos a utilizar os objetos fun co es fornecidos pela STL, as fun co es aritm eticas, de compara ca o, e l ogicas. Vimos ainda uma se ca o com dicas avan cadas de STL, onde apresentamos alguns adaptadores fornecidos pela STL como o adaptador para fun ca o objeto bin2nd(), os adaptadores not1(), not2(), e men_fun(). Finalmente aprendemos a extender a STL apresentando um exemplo de especializa ca o para std::swap(). Nota: como a STL e muito ampla n ao podemos esgotar todos os seus t opicos neste livro. A dica e: consulte o manual disponibilizado em http://www.sgi.com/tech/stl/, para ampliar seus conhecimento da STL. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
631
36.5
Exerc cios
1. Adicione novas fun co es gen ericas na listagem 36.4. 2. Transforma a classe CTesteFuncoesGenericas da listagem 36.4 em uma classe template. 3. Note que a listagem 36.4 apresenta diversos m etodos incompletos, sua tarefa e completar esta listagem.
632
[Comunidade-Software-Livre, 1996] Comunidade-Software-Livre (1996). Declarac a o de barcelona - desaos para amplia ca o e consolidad ca o do software livre. http://www.softwarelivre.org/forum2004/news/2297. [Cormen et al., 2002] Cormen, T. H., Charles E, L., Rivest, R. L., and Stein, C. (2002). Algoritmos. Campus. [da Silva Neto and Neto, 2005] da Silva Neto, A. J. and Neto, F. D. M. (2005). Problemas Inversos - Conceitos Fundamentais e Aplica co es. Editora UERJ. [Deitel and Deitel, 2002] Deitel, H. and Deitel, P. (2002). C++ HOW TO PROGRAM. PRENTICE HALL, Porto Alegre, 4 edition. 633
634
REFERENCIAS BIBLIOGRAFICAS
[Emerson Rios, 2004] Emerson Rios, T. R. (2004). Projeto e Engenharia de Software - Teste de Software. Alta Books. [Fowler and Scott, 2000] Fowler, M. and Scott, K. (2000). UML Essencial. Bookman, S ao Paulo. [Guedes, 2004] Guedes, G. T. A. (2004). UML Uma Abordagem Pr atica. novatec, S ao Paulo. [GuiaLivre, 2004] GuiaLivre (2004). Guia livre - refer encia de migra ca o para software livre do governo federal. Technical report, Governo Federal. http://www.governoeletronico.gov.br. [Holloway, 2006] Holloway, J. P. (2006). Introdu ca o a ` Programa ca o para Engenharia. LTC. [http://www.fsl.org, 2004] http://www.fsl.org (2004). Filosoa de Software Livre. [Johnson and Foote, 1998] Johnson, R. E. and Foote, B. (1998). Designing reusable classes. JOOP - Journal of Object-Oriented Programming, pages 2235. [Kernighan and Ritchie, 1988] Kernighan, B. W. and Ritchie, D. M. (1988). The C Programming Language, Second Edition. Prentice Hall. [Korson and Macgregor, 92] Korson, T. and Macgregor, J. D. (92). Technical criteria for the specication and evaluation of object oriented libraries. Software Engineering journal, pages 8594. AO RUP - Rational Unied Process. [Kruchten, 2003] Kruchten, P. (2003). INTRODUC AO Ci encia Moderna, S ao Paulo. [Lischner, 2003] Lischner, R. (2003). C++ in a Nutshell - A Language & Library Reference. Oreilly. [Martin and McClure, 1993] Martin, J. and McClure, C. (1993). CASE. MacGraw-Hill, S ao Paulo. T ecnicas Estruturadas e
[Meyers, 2005] Meyers, S. (2005). Eective C++ : 55 Specic Ways to Improve Your Programs and Designs. Addison-Wesley. [Parga, 2006] Parga, D. F. (2006). Introdu ca o a java. Revista inform, pages 1019. [Pressman, 2002] Pressman, R. S. (2002). Engenharia de Software. MCGraw Hill, Rio de Janeiro, 5 edition. [Queiroz, 2002] Queiroz, R. (2002). Porque usar software livre. RDL. [Rezende, 2002] Rezende, D. A. (2002). Engenharia de Software e Sistemas de Informa ca o. Brasport, Rio de Janeiro. [Rumbaugh et al., 1994] Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F., and Lorensen, W. (1994). Modelagem e Projetos Baseados em Objetos. Edit. Campus, Rio de Janeiro. [Solter and Kleper, 2005] Solter, N. A. and Kleper, S. J. (2005). Professional C++. Wrox. [Sonerviile, 1993] Sonerviile (1993). Engenharia de Software. MacGraw-Hill, S ao Paulo. [Stroustrup, 2005] Stroustrup, B. (2005). The design of c++0x. C/C++ Users Journal. [Sutter, 2006] Sutter, H. (2006). Programa ca o Avan cada em C++. Pearson - Mahron Books. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
REFERENCIAS BIBLIOGRAFICAS [Teles, 2004] Teles, V. (2004). Extreme Programming. Novatec, S ao Paulo. [Teles, 2006] Teles, V. (2006). Extreme programming. Revista inform, pages 4249.
635
[Vandevoorde and Josuttis, 2002] Vandevoorde, D. and Josuttis, N. M. (2002). C++ Templates: The Complete Guide. Addison Wesley Professional. [Wikipedia, 2007] Wikipedia (2007). wikipedia - http://www.wikipedia.org/. In Wikipedia. http://www.wikipedia.org/. [Winblad et al., 1993] Winblad, A. L. et al. (1993). Software Orientado a Objeto, volume 1. Makron Books, S ao Paulo.
636
REFERENCIAS BIBLIOGRAFICAS
Parte IV
Ap endices
637
Ap endice A
Diretrizes de Pr e-Processador
Neste ap endice veremos as diretrizes de pr e-processador. As diretrizes de pr e-processador s ao orienta co es, instru co es que fornecemos para a compilac a o do programa (veja se ca o A.1). Uma diretriz de pr e-processador inicia-se com o s mbolo # e e utilizada para inclus ao de arquivos (se ca o A.2), compila ca o condicional (se ca o A.3), uso de macros (se ca o A.4) e instru co es de guarda (se ca o A.5).
A.1
Fase de pr e-processamento
a primeira fase da compila E ca o, verica as instru co es de compila ca o passadas com o sinal # (reveja 7.7). Primeiro verica as instru co es de guarda (se ca o A.5), a seguir s ao inclu dos os arquivos externos (se ca o A.2), depois s ao processadas as macros (se ca o A.4). Na fase de pr e-processamento, cada letra do arquivo de disco e mapeada para o padr ao Unicode (ISO/IEC 10646) e posteriormente para o conjunto de caracteres de execu ca o. O resultado da fase de pr e-processamento e uma seq u encia de s mbolos que chamamos de unidade de tradu ca o. A unidade de tradu ca o e independente de outros arquivos (veja Figura 7.1). Note ainda que cada arquivo do programa e compilado separadamente. No exemplo a seguir a unidade de tradu ca o vai incluir o arquivo <iostream>. Exemplo: // Arquivo Prog.cpp #include <iostream> int main() { std::cout < < "Oi tudo bem!";
return 0; }
Para gerar o arquivo de pr e-processamento digite: g++ -E Prog.cpp > Prog.ii . Note que o arquivo gerado e muito grande.
A.2
Inclus ao de arquivos
Usamos a diretriz #include para incluir arquivos externos. Utilize #include <nome-do-arquivo> para incluir arquivos da biblioteca, e aspas duplas #include "nome-do-arquivo" para incluir arquivos do diret orio atual. A diferen ca entre ambas e que a segunda instru ca o procura os arquivos no diret orio do usu ario e depois nos diret orios identicados na vari avel de ambiente PATH e do compilador (/usr/include). 639
640
Prot otipo: // Para realizar a inclus ao de arquivos. #include <nome-do-arquivo> #include nome-do-arquivo #include caminho/para/o/arquivo/nome-do-arquivo Observe que usando aspas "" podemos passar o caminho completo do arquivo. Mas este proce mais simples setar o caminho da biblioteca na vari dimento e inadequado. E avel de ambiente PATH utilizando export PATH=$PATH:caminho/para/biblioteca, veja prot otipo a seguir. A vari avel PATH tamb em pode ser setada no arquivo oculto .bash prole, que ca localizado no diret orio raiz do usu ario (cd && gedit bash prole ). Prot otipo: # bash export PATH=$PATH:caminho/para/biblioteca/:caminho/para/arquivos/inclus ao # csh setenv PATH=$PATH:caminho/para/biblioteca/:caminho/para/arquivos/inclus ao
A.3
Compila c ao condicional
A compila ca o condicional permite que sejam colocadas no c odigo do programa instru co es de compila ca o que restringem as areas do arquivo a serem compiladas. Por exemplo, alguns arquivos podem ter nomes diferentes no Windows, no GNU/Linux, Unix ou no MacOS X. Com a compila ca o condicional, voc e pode vericar qual o sistema operacional e especicar os arquivos corretos, assim, podemos incluir instru co es que diferenciam plataformas. Veja a seguir as instru co es que podem ser utilizadas para compila ca o condicional.
A.3.1
#define
A linguagem C permite a deni ca o de vari aveis que s ao passadas ao compilador para a realiza ca o do processo de compila ca o. A instru ca o #define, e utilizada para denir uma vari avel de compila ca o. Veja prot otipo a seguir. Prot otipo: // Dene uma vari avel #dene var
A.3.2
#ifdef
Depois de denir uma vari avel podemos utilizar a instru ca o #ifdef. Se a vari avel foi denida o bloco e compilado. Prot otipo: #ifdef var ..bloco de c odigo.. #endif // Finaliza o ..bloco de c odigo.. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
641
A.3.3
#ifndef
Da mesma forma que #ifdef podemos usar #ifndef, ou seja, se a vari avel n ao foi denida compile o bloco. Isto e usado em sistemas multiplataforma, por exemplo, se n ao estamos no Windows fa ca isto. Prot otipo: // Apaga deni ca o da vari avel var #ifndef var ..bloco de c odigo.. #endif // Finaliza o ..bloco de c odigo.., o ifndef
A.3.4
#undef
A instru ca o #undef, e utilizada para apagar uma deni ca o. Veja prot otipo a seguir. Prot otipo: #undef var // Apaga deni ca o da vari avel var
As instru co es #define tamb em permitem a deni ca o de vari aveis que ser ao substitu das em tempo de compila ca o, funcionando de modo semelhante ao search(vari avel)/replace(valor) de seu editor de texto. Prot otipo: // Trocar a vari avel var pelo valor #dene vari avel valor No exemplo a seguir, denimos tr es vari aveis de ambiente. Na etapa de pr e-processamento toda vez que o compilador encontrar a palavra string1, ir a substitu -la por "mensagem_1". Da mesma forma, toda vez que o compilador encontrar a palavra CM_FileSave, ir a substitu -la por 2515. Exemplo: #define string1 "mensagem_1" #define CM_FileSave 2515 #define dimensao_x_matriz 10 Dica: o uso de #define para cria ca o de constantes, como em #define PI 3.1415 e obsoleto. Use const double pi = 3.1415;. Veja se ca o 12.4.
A.3.5
#if
Veja a seguir o prot otipo para compila ca o condicional com #if. Se a express ao for verdadeira, o compilador compila o c odigo dentro do bloco e, se for falsa, pula o bloco. O termo express ao constante indica que a express ao deve ser avaliada em tempo de compila ca o (durante a compila ca o). Prot otipo: #if express ao constante ..bloco de c odigo.. #endif Reveja agora o exemplo apresentado na listagem 8.3. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
642
A.3.6
#ifdef...else
Se a express ao constante for verdadeira, o compilador compila o bloco 1, se for falsa, compila o bloco 2. Veja exemplo na listagem A.1. Prot otipo: #ifdef express ao constante .. bloco de c odigo1 .. #else .. bloco de c odigo2 .. #endif Listing A.1: Pr e-processamento: Usando #ifdef..else.
1 2 3 4 5 6 7 8 9 10 11 # include < iostream > int main () { # ifdef DEBUG std :: cout << " Vers~ a o com vari a vel debug ativada " << std :: endl ; # else std :: cout << " Vers~ a o com vari a vel debug N ~ A O ativada " << std :: endl ; # endif return 0; } [ b u e n o @ s u p o r t e 3 Parte - VI ] $ g ++ if - else . cpp [ b u e n o @ s u p o r t e 3 Parte - VI ] $ ./ a . out Vers~ a o com vari a vel debug N ~ A O ativada [ b u e n o @ s u p o r t e 3 Parte - VI ] $ g ++ - DDEBUG if - else . cpp [ b u e n o @ s u p o r t e 3 Parte - VI ] $ ./ a . out Vers~ a o com vari a vel debug ativada
A.3.7
#if...else
Se a express ao constante for verdadeira, o compilador compila o bloco 1, se for falsa, compila o bloco 2. Veja exemplo na listagem A.2. Prot otipo: #if express ao constante ..bloclo de c odigo1 .. #else ..bloclo de c odigo2 .. #endif Listing A.2: Pr e-processamento: Usando #if..else.
1 2 3 4 5 6 7 8 9 10 11 12 # include < iostream > using namespace std ; int main () { # ifdef __Linux__ cout < < " oi GNU / Linux \ n " ; # else cout << " oi \ n " ; return 0; } # endif
A.4. MACROS
oi GNU / Linux
643
A.3.8
#if...#elif...#elif...#endif
A diretriz de processamento #if...elif e usada para m ultiplas verica co es. Funciona da mesma forma que if..else (veja se ca o D.2.2): Prot otipo: #if express ao constante1 ..bloclo de c odigo1 .. #elif express ao constante2 ..bloclo de c odigo2 .. #elif express ao constante3 ..bloclo de c odigo3 .. #endif Dica: os arquivos da biblioteca padr ao costumam incluir exemplos de uso das diretrizes de pr e-processador, sendo uma boa refer encia para estudo.
A.4
Macros
Na linguagem C, voc e pode utilizar macros, que s ao fun co es de pr e-processamento. Uma macro e implementada com uma diretiva #define. Veja o exemplo. Exemplo: // Defini c~ ao da macro #define soma(x,y) (x+y) int a = 4; int b = 5; // Uso da macro, resultado int z = (a + b); int z = soma(a,b); Na linguagem C++, as macros foram substitu das pelas fun co es inline, que s ao mais seguras por fazerem verica ca o de tipo (veja se ca o 13.10).
A.4.1
Macros pr e-denidas
A linguagem C++ tem um conjunto de macros pr e-denidas, veja lista abaixo. A listagem A.3 mostra o uso das macros pr e-denidas. LINE FILE DATE TIME STDC N umero da linha compilada. Nome do arquivo que esta sendo compilado. Data de compila ca o. Hora minuto e segundo. Se e compilador padr ao.
644
A.5. INSTRUC OES DE GUARDA Listing A.3: Pr e-processamento: Usando macros pr e-denidas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# include < iostream > using namespace std ; int main () { cout << " Arquivo : " << " \ nLinha : " << " \ nData : " << " \ nHora : " << " \ nCompilado r : "
# ifdef __GNUCC__ cout << " Compilado r da GNU : " << __GNUCC__ << endl ; # elif __MSC_VER_ _ cout << " Compilado r da Microsoft : " << __MSC_VER _ _ << endl ; # endif } Arquivo : List -A -4 - Macros . cpp Linha : 8 Data : Feb 13 2007 Hora : 11:47:58 Compilado r : 1
Veja a seguir uma macro, a mesma recebe dois par ametros, a e b e chama uma fun ca o f, passando o maior valor max(a,b). #define F(a,b) f( (a) > (b) ? (a) : (b))
Agora, veja o que acontece quando usamos a macro de forma inadvertida. F(++a,++b) O resultado gerado pela macro e dado por: f( (++a) > (++b) ? (++a) : (++b)) Ou seja, a e b s ao incrementados duas vezes, o que n ao desejamos. Este tipo de erro e comum quando se usa as obsoletas macros de C. A dica e simples, elimine o uso de macros, use fun co es inline de C++ (se ca o 13.10). Veja a seguir a fun ca o inline que substitue com vantagens as macros. Exemplo: // Defini c~ ao template <typename T> inline T F(const T&a, const T&b) { f( a > b ? a:b;); } // Uso F(a,b);
A.5
As instru co es de guarda foram apresentadas na se ca o 11.4. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
645
A.6
Evite utilizar macros; as fun co es inline do C++ realizam a mesma tarefa de forma mais inteligente. Substitua o uso de #define por const e enumera co es. Voc e pode identicar qual processador esta utilizando (verique o manual de seu compilador). _ _CNUCC_ _ Compilador da gnu. _ _MSC_VER_ _ Compilador da Microsoft (Microsoft visual C++).
A.7
Neste ap endice aprendemos a utilizar as diretrizes de pr e-processador de C++. Vimos que s ao instru co es que se iniciam com # e que fornecem instru co es para a compila ca o do programa. Aprendemos ainda a utilizar compila ca o condicional, e que n ao devemos usar as antigas macros de C. Entendemos o uso das instru co es de guarda.
A.8
Exerc cios
1. Diga com suas palavras como funciona a etapa de pr e-processamento. 2. Diga o que ocorre com a palavra dimensao x matriz na etapa de pr e-processamento do c odigo abaixo. #define dimensao_x_matriz 10 3. Nas listagens em que utilizamos arquivos .h separados dos arquivos .cpp, elimine do arquivo .h as instru co es de guarda e tente compilar novamente o programa. Descreva o que acontece. 4. Modique a listagem A.1 acrescentando novos blocos ifdef..else. 5. Modique a listagem A.2 acrescentando novos blocos if..else. 6. Rode o programa A.3 em sua m aquina, verique a sa da obtida. 7. Na se ca o A.4 falamos de exemplos de macros que podem apresentar problemas. Monte um programa com os exemplos apresentados na se ca o e veja a sa da obtida.
646
Ap endice B
B.1
A classe de armazenamento refere-se ao tempo de vida do objeto. A deni ca o da classe de armazenamento e o primeiro item da declara ca o de uma vari avel e instrui o compilador sobre o modo como a vari avel ser a armazenada. Existem tr es palavras-chave para denir a classe de armazenamento. As palavras-chave auto e register s ao utilizadas para vari aveis que s ao constru das, utilizadas e destru das automaticamente pelo compilador; static e utilizado para vari aveis que s o s ao destru das quando o programa e encerrado. Note que static tamb em e constru do e destru do automaticamente pelo compilador. Objetos criados com new e destru dos com delete, tem seu tempo de vida denido pelo programador. auto: e o m etodo default para armazenamento de vari aveis. Quando for encerrada a fun ca o ou bloco onde a vari avel foi declarada, esta ser a eliminada, isto e, destru da automaticamente. Exemplo: { auto int a = 3; // A vari avel a e criada } // A vari avel a e destru da register: um processador como um Intel-Pentium ou um AMD-Opteron, tem um bloco onde est ao os registradores. Cada registrador e utilizado, temporariamente, para realiza ca o de algum processamento, como uma soma. Assim, quando fazemos c = a + b; , a vari avel a e 647
648
B.2. ESPECIFICADOR DE LINKAGEM copiada para o registrador 1, e a vari avel b para o registrador 2. O resultado da soma e armazenado no registrador 3 e depois copiado para c. Quando utilizamos a palavra-chave register, estamos pedindo para o compilador colocar a vari avel em um registro, que tem processamento mais r apido. Quando se encerrar a fun ca o ou bloco onde foi declarada, a vari avel vai ser eliminada. Os compiladores mais modernos colocam nos registradores as vari aveis mais utilizadas. O tempo de vida e o mesmo de uma vari avel auto.
static: quanto utilizamos static a vari avel passa a existir a partir de sua deni ca o e dura toda a execu ca o do programa. Se n ao for denido um valor, assume o valor 0 (zero). Em um programa, os objetos est aticos s ao os primeiros a serem constru dos e os u ltimos a serem destru dos (se ca o 16.6.3). Todas as vari aveis globais t em classe de armazenamento est atica, isto e, existem por toda a vida do programa. Se dentro de uma fun ca o houver uma vari avel static, est a ser a criada quando o programa passar pela fun ca o pela primeira vez; na segunda passagem, a vari avel n ao e novamente criada. Um objeto ou membro de um objeto pode ser est atico, se for declarado explicitamente com static. A palavra-chave static tamb em indica que a linkagem e interna (se ca o B.2). Exemplo: int fun c~ ao() { auto int x; // O mesmo que int x; register int y; // Colocar no registro static char Titulo[] = "SAILAnaliseImagens"; // Deixar na mem oria return 0; }
B.2
Especicador de linkagem
Todo nome declarado e usado dene a necessidade de uma linkagem, isto e, de uma liga ca o entre o nome do objeto e o espa co de mem oria ocupado pelo objeto. Por exemplo, se declaramos Exemplo: extern int x; mas nunca usamos x, ent ao n ao teremos problema de linkagem. Mas se x for usado, o mesmo precisa estar denido em algum arquivo externo. Em C++ uma linkagem pode ser: Interna: como exemplo podemos citar atributos e m etodos de uma classe, vari aveis declaradas como static ou const. Externa: usa a palavra-chave extern, veja exemplo na se ca o B.2.1. Sem linkagem: como exemplo podemos citar vari aveis denidas dentro de um bloco ou fun ca o. Tamb em podemos especicar que a linkagem deve ser feita utilizando-se padr oes de outras linguagens, como C e pascal. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
649
voc e pode linkar programas em C com programas em C++. No exemplo abaixo informa que a fun ca o e uma fun ca o de C. Exemplo: extern "C" void cfuncao(); Outra maneira de fazer isto e criar um bloco de fun co es em C, veja exemplo: Exemplo: extern "C" { void cfuncao1(); void cfuncao2(); .. } pascal: se a fun ca o a ser chamada foi desenvolvida utilizando a linguagem de programa ca o pascal, voc e deve incluir na declarara ca o da fun ca o a palavra-chave pascal. Exemplo: int pascal fun c~ ao(par^ ametros); // Declara .. int pascal fun c~ ao(par^ ametros) // Define { }
B.2.1
Uso de extern
A utiliza ca o da palavra-chave extern permite a compila ca o separada dos diversos arquivos que comp oem um programa. Ou seja, voc e deve utilizar extern na declara ca o de uma fun ca o ou vari avel que e denida em outros arquivos. O arquivo com a declara ca o extern aceita a exist encia da fun ca o de modo que voc e pode compilar as fun co es separadamente. Exemplo: // No arquivo A: cria a vari avel x (declara e define) int x; // No arquivo B: informa que x j a existe (s o declara) extern int x; Com a declara ca o extern, o arquivo B aceita a exist encia da vari avel int x;, mas n ao aloca espa co de armazenamento para esta. Deste modo, voc e pode compilar os arquivos A e B separadamente. Veja nas listagens B.2 e B.3 exemplos de uso de static, extern e compila ca o separada. O exemplo das listagens B.2 e B.3 deixa claro a ordem em que os objetos est aticos s ao criados e destru dos. A classe Teste e criada apenas para enviar mensagens para tela. Primeiro s ao criados os objetos globais (denidos ou n ao com static), a seguir os objetos s ao criados de forma autom atica, dentro de main() (Arquivo A: T1 main., Arquivo A: static T2 global.) e do for (Arquivo A: T1 for.,Arquivo A: static T2 for.). Observe que T1 for e criado-destru do, e a seguir criado-destru do novamente. Ou seja, quando chega o m do bloco em que foram Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
650
criados, os objetos autom aticos s ao destru dos. Com a chamada a funcao1, o objeto (Arquivo e criado, como e est atico o mesmo e criado apenas uma vez, na sua primeira B: static T3 for) execu ca o. A funcao1() e encerrada, e a seguir a fun ca o main(). O objeto autom atico (Arquivo e destru do, e a seguir todos os outros objetos est aticos. Observe ainda que T2 A: T1 main.) foi criado duas vezes, e tem escopo de arquivo, n ao podendo ser utilizado no outro arquivo. No arquivo B usamos extern T1, de forma que podemos usar T1 (sem o criar novamente). Da mesma forma, a declara ca o extern void funcao1(); colocada no arquivo A, garantiu a chamada a fun ca o funcao1() sem que a mesma tivesse sido denida. Listing B.1: Classe Autixliar Cteste.
1 2 3 4 5 6 7 8 9 10 11 12 13 # include < iostream > # include < string > class CTeste { std :: string msg ; public : CTeste ( std :: string s ) : msg ( s ) { std :: cout << " Criou objeto ~ CTeste () { std :: cout << };
651
T1_main . static T3_for static T2_for . static T2_main . static T2_global . static T2_global . T1_global .
Para compilar este exemplo: g++ -c escopo-b.cpp g++ -c escopo-a.cpp Para compilar e linkar: g++ List-B-2-escopo-a.cpp List-B-3-escopo-b.cpp Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
B.3
Modicadores de acesso
Vimos na se ca o 8.4 que as palavras-chaves static, extern, const, volatile e mutable s ao qualicadores. Os mesmos podem ser divididos em modicadores de acesso (const, volatile e mutable) e especicador de linkagem (static, extern). Os modicadores de acesso s ao palavras-chave utilizadas para modicar o tipo de acesso a determinada vari avel. const: uma vari avel const e uma vari avel constante, que nunca muda. Portanto, seus valores s ao atribu dos uma u nica vez. Vari aveis const n ao podem aparecer ` a esquerda do sinal de igualdade. A palavra-chave const foi criada para substituir as instru co es #define. A vantagem e que com const existe verica ca o de tipo, o que n ao ocorre com #define. No exemplo da listagem B.4, criamos dois objetos const, um global const double PI = 3.14159265358979; e outro local, const float PI = static_cast < float >(::PI);. observe na sa da que PI local <float>, s o preserva os 7 primeiros d gitos, ou seja, 3.141592. Listing B.4: Usando modicadores de acesso.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # include < iostream > # include < iomanip > // C r i a c~ a o de objeto c o n s t a n t e ( n~ a o pode mudar ) , // global ( v i s v e l em todo p r o g r a m a) const double PI = 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 ; int main () { // C r i a c~ a o de objeto c o n s t a n t e ( n~ a o pode mudar ) , // local ( v i s v e l dentro de main ) const float PI = static_cas t < float >(:: PI ) ; std :: cout << std :: s e t p r e c i s i o n (15) << " Conte u do de PI local < float > = " << PI << " \ n " << std :: s e t p r e c i s i o n (15) << " Conte u do de PI global < double > = " << :: PI << " \ n " ; return 0; } Conte u do de PI local < float > = 3 . 1 4 1 5 9 2 7 4 1 0 1 2 5 7 3 2 Conte u do de PI global < double > = 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9
volatile: vari aveis que podem ter seu valor alterado de modo inesperado, n ao detectado pelo compilador (impede o compilador de utilizar otimiza co es agressivas com esta vari avel). T em utilidade em dispositivos mapeadores de mem oria, multitarefa e threads. Veja listagem ??. Exemplo: volatile int tempo; // Uso de volatile const volatile int alfa;// Uso de const volatile Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
653
mutable: quando voc e quer permitir que um atributo de uma classe/estrutura possa ser modicado, mesmo que o objeto seja declarado como const. Exemplo: struct Funcionario { char nome[30]; mutable int contador; } // Cria objeto do tipo Funcionario com nome func, constante const Funcionario func = {"Pedro",0}; // Abaixo tenta modificar o objeto func que e const strcpy(func.nome,"jo~ ao da silva"); // Erro // Abaixo o acesso e permitido gra cas ao especificador mutable func.contador = 1; const e volatile: no exemplo anterior, alfa e uma constante, e como tem o volatile, o compilador n ao faz qualquer suposi ca o sobre os valores de alfa. Um programa externo pode mudar o valor de alfa.
B.4
J a discutimos preliminarmente o conceito de escopo nas se co es 8.12 e 10.3. Um programa e dividido em n veis/escopos, para melhorar sua organiza ca o. Desta forma, quando declaramos uma vari avel em determinado ponto do programa, estamos fazendo com que essa vari avel possa ser acessada no n vel em que foi declarada e nos n veis seguintes. Ou seja, o escopo de uma vari avel dene onde ela pode ser utilizada. Existem dois tipos de escopo, com nome e sem nome. Um namespace e uma classe s ao exemplos de escopo com nomes. Um bloco, o corpo de uma fun ca o, e um namespace sem nome s ao exemplos de escopo sem nome. Veja a seguir alguns exemplos de escopo. Escopo local (de bloco): quando uma vari avel e declarada dentro de um bloco, ela pode ser acessada dentro desse bloco, a partir de sua declara ca o, e nos n veis mais baixos. No exemplo abaixo x pode ser acessado a partir de sua deni ca o, o que inclui o bloco 2. Exemplo: { // int x = 3; { // int r = 4; } // } // In cio bloco 1 In cio bloco 2 Fim bloco 2 Fim bloco 1
Escopo de fun c ao/m etodo: quando uma vari avel e declarada dentro de uma fun ca o, ela pode ser acessada dentro da fun ca o. Se a vari avel for declarada como static, ser a criada uma u nica vez, mantendo-se Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
654
B.5. SENTENCAS viva mesmo depois do encerramento da fun ca o. Se a vari avel n ao for static, deixar a de existir quando a fun ca o terminar.
Escopo de classe (C++): quando um objeto e declarado dentro de uma classe, como um atributo da classe. Se a especica ca o de acesso for private, o objeto poder a ser acessado somente na classe em que foi declarado. Se a especica ca o de acesso for protected, o objeto ser a vis vel na classe em que foi declarado e nas classes derivadas. Se a especica ca o de acesso for public, o objeto poder a ser acessado em todo o programa. Escopo de namespace: vimos no Cap tulo 10 - Namespace, o uso de namespace para criar um espa co de nomes e o uso de using para mudar o escopo. Escopo global: quando declaramos uma vari avel fora de todos os blocos, fun co es e classes, ent ao ela e uma vari avel global. Uma vari avel global pode ser acessada por todos os arquivos que comp oem o programa a partir de sua declara ca o. Escopo de arquivo (static): uma vari avel ou fun ca o static global s o e vista no arquivo em que foi declarada (uso obsoleto de static, programas modernos utilizam namespaces. Veja Cap tulo 10 - Namespace). Exemplo de vari aveis que s o s ao vistas no arquivo em que foram declaradas: Uma fun ca o inline declarada explicitamente. Uma vari avel const. Uma vari avel global est atica. Exemplo: // Vari avel est atica expl cita define o seu valor static int valor1 = 16; // Vari avel est atica impl cita assume o valor 0 static int valor2; // Fun c~ ao est atica, vis vel somente neste arquivo static int soma(int x, int y) { return x + y; }
B.5
Senten cas
Um objeto criado dentro de uma fun ca o ou bloco e eliminado quando a fun ca o ou o bloco termina, com exce ca o dos objetos est aticos, que s o s ao destru dos quando o programa termina. A fun ca o abort() aborta o programa sem destruir os objetos est aticos. Em C++, todo objeto const deve ser inicializado na sua declara ca o. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
B.6. RESUMO DO CAP ITULO Evite utilizar #define; utilize const de C++.
655
Uma declara ca o friend n ao adiciona a fun ca o ao escopo da classe (Cap tulo 20 - Friend). Qualquer uso de um nome deve ser n ao amb guo em seu escopo. Depois de analisada a n ao-ambig uidade e que ser a considerada a acessibilidade da vari avel. Quando dizemos que uma vari avel n ao deve ser amb gua em seu escopo, queremos dizer que o compilador, ao passar por uma vari avel, deve ter certeza de qual vari avel voc e quer acessar, n ao podendo car em d uvida. A ordem em que os especicadores s ao colocados n ao e importante, mas o padr ao e: Especicador de linkagem (static, extern), especicador de classe de armazenamento (auto, register, static), modicadores de acesso (const, volatile, mutable). Vari aveis extern tem liga ca o externa. Quando for acessar fun co es de outras linguagens, utilize o exemplo a seguir. Exemplo: extern "C++" retorno nomefun c~ ao(par^ ametros); extern "C" retorno nomefun c~ ao(par^ ametros); extern "FORTRAN" ...; // e n~ ao Fortran extern "Ada"...............; // e n~ ao ADA Note que se uma fun ca o f() tem uma linkagem em "C", ent ao um ponteiro para f() tamb em deve ter linkagem de "C".
B.6
Neste ap endice aprendemos o uso dos especicadores de classes de armazenamento (auto, register e static). Do especicador de linkagem, que pode ser interna, externa ou sem linkagem. Aprendemos a usar a palavra-chave extern. Vimos que os modicadores de acesso de C++ s ao const, volatile e mutable. Aprendemos que o escopo das vari aveis pode ser: local (de bloco), de fun ca o/m etodo, de classe (C++), de namespace, de arquivo (static) ou global.
B.7
Exerc cios
1. Monte um exemplo que use as palavras-chaves: auto, register, static. 2. Monte um exemplo que use as palavras-chaves: const, volatile e mutable. 3. Quais os problemas do programa abaixo? Exemplo: int main() { int x = 3; int r = x + y; { int y = 4; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
656 } cout < < r < < < < x < < < < y ; } 4. Monte um exemplo que use o conceito de extern. 5. Porque o uso de extern em C++ e obsoleto? 6. Modique a listagem B.4. 7. Modique as listagens B.2 e B.3.
Ap endice C
Operadores
Neste cap tulo apresentaremos quais os operadores de C/C++ e sua ordem de preced encia. Os operadores est ao divididos em: operadores aritm eticos (se ca o C.1.1), de atribui ca o (se ca o C.1.2), compostos (se ca o C.1.3), relacionais (se ca o C.1.4), l ogicos (se ca o C.1.5), de bits (se ca o C.1.6), condicional (se ca o C.1.7), incremento e decremento (se ca o C.1.8), v rgula (se ca o C.1.9), operador m odulo % (se ca o C.1.10), new (se ca o C.1.11), delete (se ca o C.1.12), typedef (se ca o C.1.13), sizeof (se ca o C.1.14), size_t (se ca o C.1.15), resolu ca o de escopo (se ca o C.1.16). 657
658
C.1
Os operadores denidos pela linguagem C++ podem ser utilizados para realizar determinada opera ca o entre objetos. Todo operador tem uma preced endia. Operadores de preced encia alta s ao executados antes dos operadores de preced encia baixa. Apresentamos na Tabela C.1 a preced encia dos operadores. O operador de mais alta prioridade e o de resolu ca o de escopo (::), a seguir os par enteses () e depois os colchetes []. O operador de mais baixa prioridade e o operador v rgula(,). Nota: normalmente alteramos a ordem de preced encia de determinada opera ca o matem atica utilizando parenteses extras.
Tabela C.1: Preced encia dos 2 3 4 dynamic cast ! delete static cast delete[] reinterpret cast (tipo) .* const cast sizeof ->* ++i & * - -i * / + new % new[] +
operadores. 5 6 != < < & and >> or < | ou <= && e > || ou >= ?: == =
7 += -= *= /= %= &= = |=
C.1.1
Os operadores aritm eticos como +,-,*,/ s ao usuais em diversas linguagens de programa ca o. C acrescentou o operador m odulo (%), o qual retorna o resto de uma divis ao. Prot otipo + * / % Soma. Subtra ca o. Multiplica ca o. Divis ao. Resto da divis ao.
Veja a seguir um exemplo: Exemplo: #include <iostream> using namespace std; int main() { int A = 1, B = 2, C A = B + C; // A = 18 - C; // B = 4 *( A / C); //
= A A B
659
Dica: a exponencia ca o xy pode ser realizada com a fun ca o pow(x,y) do arquivo de cabe calho <cmath>. O uso de x^y ou x**y n ao e v alido em C++.
C.1.2
No exemplo a seguir, o operador de atribui ca o e utilizado para atribuir o conte udo de B a A. Exemplo: A = B; A = B = C = D = 0;
C.1.3
Os operadores compostos aumentam a eci encia dos programas, pois s o acessam o objeto uma u nica vez. Exemplo: A += B; A -= B; A /= B; A *= B; // // // // O O O O mesmo mesmo mesmo mesmo que que que que A A A A = = = = A A A A + / * B; B; B; B;
C.1.4
Os operadores relacionais s ao utilizados para comparar objetos. Veja a seguir seu prot otipo: Prot otipo > >= < <= == != maior. maior ou igual. menor. menor ou igual. igual. diferente.
Um exemplo de uso dos operadores de compara ca o e apresentado na listagem C.1. Listing C.1: Usando os operadores de compara ca o, incremento, decremento, e os operadores compostos.
1 2 3 4 5 6 7 8 9 # include < iostream > void compara ( int a , int b ) ; // Fun c~ ao
int main () { int a , b ; std :: cout << " Entre com dois numeros inteiros ( a espa c o b enter ) : " ; // O b s e r v e abaixo a l e i t u r a de duas v a r i a v e i s em uma unica linha .
660
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 // Isto deve ser e v i t a d o. std :: cin >> a >> b ; std :: cin . get () ; compara (a , b ) ; a += 5; compara (a , b ) ; b - -; compara (a , b ) ; a *= ++ b ; compara (a , b ) ; return 0; }
// Pega o enter // O p e r a d o r c o m p o s t o . // O p e r a d o r de d e c r e m e n t o . // O p e r a d o r de i n c r e m e n t o e c o m p o s t o .
void compara ( int a , int b ) { if ( a == b ) // O p e r a d o r de c o m p a r a c~ ao std :: cout << a << " == " << b << " \ t " ; if ( a != b ) std :: cout << a << " != " << b << " \ t " ; if ( a < b ) std :: cout << a << " < " << b << " \ t " ; if ( a > b ) std :: cout << a << " > " << b << " \ t " ; if ( a <= b ) std :: cout << a << " <= " << b << " \ t " ; if ( a >= b ) std :: cout << a << " >= " << b << " \ t " ; } Entre com dois numeros inteiros ( a espa c o b enter ) : 3 4 3 != 4 3 < 4 3 <= 4 8 != 4 8 > 4 8 >= 4 8 != 3 8 > 3 8 >= 3 32 != 4 32 > 4 32 >= 4
C.1.5
Os operadores l ogicos s ao utilizados para testar determinadas condi co es. Prot otipo && and || or ! not e. e. ou. ou. nega ca o, inverte o resultado. nega ca o, inverte o resultado.
Na listagem C.2, se x for maior que y ou x maior que z, faz x = y + z; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
661
int z = 4;
if ( x > y || x > z ) x = y + z; std :: cout << " x = " << x << std :: endl ; if ( x < y or x < z ) x = y + z; std :: cout << " x = " << x << std :: endl ; return 0; }
C.1.6
Os operadores de bits s ao utilizados para testar determinadas condi co es. Prot otipo & bitand ^ xor | bitor >> << Opera ca o and para bits. Se os bits x e y s ao 1, ent ao retorna 1. Opera ca o and para bits. Opera ca o ou exclusiva. Se os bits x e y forem diferentes, retorna 1. Opera ca o ou exclusiva. Opera ca o ou inclusiva. Se os bits x e y s ao 0 retorna 0. Opera ca o ou inclusiva. Rotaciona bits para direita. Rotaciona bits para esquerda.
Veja exemplo de uso de operadores de bits na listagem C.3. Listing C.3: Usando os operadores de bits.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # include < iostream > using namespace std ; int main () { int n u m e r o I n t e i r o ; int mascara = 1 << 31; // Um l o o p i n g i n f i n i t o while ( true ) { cout << " \ nDigite um n u mero inteiro ( ctrl + c para encerrar ) : \ n " ; cin >> n u m e r o I n t e i r o ; cout << " N u mero = " << n u m e r o I n t e i r o << " , e sua r e p r e s e n t a c a ~ o em bits = " ; // P e r c o r r e os 32 bits for ( int i = 1; i <= 32; i ++) { // C o m p a r a n u mero com a m ascara char ch = ( n u m e r o I n t e i r o & mascara ) ? 1 : 0 ;
662
22 23 24 25 26 27 28 29 30 31
} } return 0; } Digite 0 N u mero Digite 1 N u mero Digite 10 N u mero Digite um n u mero inteiro ( ctrl + c para encerrar ) : = 0 , e sua r e p r e s e n t a c a ~ o em bits = 00000000 00000000 00000000 00000000 um n u mero inteiro ( ctrl + c para encerrar ) : = 1 , e sua r e p r e s e n t a c a ~ o em bits = 00000000 00000000 00000000 00000001 um n u mero inteiro ( ctrl + c para encerrar ) : = 10 , e sua r e p r e s e n t a c a ~ o em bits = 00000000 00000000 00000000 00001010 um n u mero inteiro ( ctrl + c para encerrar ) :
C.1.7
O operador condicional eou nico operador tern ario do C++. Veja o prot otipo. Se a condi ca o a a express ao falsa. for verdadeira, executar a a express ao verdadeira, e se for falsa, executar Prot otipo: ao falsa); (condi ca o)? (express ao verdadeira): (express Exemplo: int maior = x > y ? x : y;
C.1.8
Se voc e tem uma vari avel inteira e quer increment a-la de 1 (somar a 1), utilize o operador de incremento ++; para diminuir de 1, utilize o operador decremento --. Para obter: valor = valor + 1; , fa ca: ++valor;. Para obter: valor = valor - 1;, fa ca: --valor;. As opera co es de incremento/decremento podem ser do tipo postx ou prex, veja exemplo. A opera ca o postx (++y), utiliza o valor de y para calcular x e depois incrementa y. A opera ca o prex (++y), primeiro incrementa o valor de y e depois utiliza o valor de y para calcular z. Exemplo: int y = 5; // Define y = 5. int x = 5 + y++; // Faz x = 10 e depois y = 6. int z = 5 * ++y; // Faz y = 7 e depois z = 5*7 = 35. Um exemplo de uso do operador incremento e apresentado na listagem C.4. Listing C.4: Usando operador de incremento.
1 2 3 4 # include < iostream > using namespace std ; int main ()
663
C.1.9
O operador v rgula avalia duas express oes onde a sintaxe s o permite uma. Prot otipo: ao da direita) (express ao da esquerda),(express Exemplo: int x,y,z; for( int min = 0 , int max = 10 ; min < max ; min++ , { cout < < min < < " " < < max < < " "; }
max- )
Observe dentro do for a declara ca o de dois inteiros utilizando o separador v rgula: int min = 0 , int max = 10
C.1.10
O operador m odulo (%) retorna o resto de uma divis ao. No prot otipo a seguir, o resultado e o resto da divis ao de a por b. Prot otipo: A%B Retorna o resto da divis ao de A por B.
Veja no exemplo a seguir a utiliza ca o da fun ca o rand() da biblioteca matem atica-padr ao de C e do operador m odulo. Exemplo: #include <cmath> int a = 7, b = 4; int x = a % b; // x = 3 e o resto da divis~ ao de a por b x = rand() % 6; // x e um valor rand^ omico entre 0 e 5 // N umero rand^ omico entre min e min + max int n = min + rand() % (max + 1 -min); Veja na listagem C.5 exemplo de uso do operador m odulo (%) e do operador tern ario (?). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
664
AOS OPERADORES C.1. INTRODUC AO Listing C.5: Usando operador m odulo % e operador tern ario ?
1 2 3 4 5 6 7 8 9 10 11 12 13
# include < iostream > int main () { int contador = 1; std :: cout << " 5%4 int x = 5; int y = 3; int z = x > y ? x std :: cout << " \ nx << " z = return 0; }
5%4=1 x =5 , y =3 , z = x > y ? x : y ; z =5
C.1.11
Operador new
C.1.12
Operador delete
C.1.13
Operador typedef
C.1.14
Operador sizeof
Veja a descri ca o do operador sizeof na se ca o 9.5.3. Veja na listagem ?? exemplo de uso de sizeof.
C.1.15
Operador size_t
C.1.16
O operador de resolu ca o de escopo e utilizado para informar o compilador que queremos acessar a vari avel global. Se utilizarmos o operador de resolu ca o de escopo dentro de uma fun ca o, estaremos acessando a vari avel global externa a ` fun ca o. Veja o exemplo: Exemplo: int x = 70; int main() { int x = 56; int y = x; // y = 56 int z = ::x; // z = 70 pega o x externo a fun c~ ao main() Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
665
C.2
Performance: em testes de compara ca o, sempre teste em primeiro lugar as condi co es mais prov aveis. BUG: e um erro comum utilizar = para comparar dois valores, como na express ao if(x = 3); quando o correto e if(x == 3) um erro comum utilizar =! em vez de !=. E Para inverter um bool, utilize !. Se precisar, utilize par enteses extras para deixar o c odigo mais claro. N ao confunda um operador sobre bits (& e |) com operadores l ogicos (&& e ||). bool pode assumir true(!= 0) ou false(== 0); assim 1 e true, 5 e true, 0 e false.
C.3
Neste ap endice aprendemos a usar o operadores de C++. Os operadores aritm eticos, de atribui ca o, compostos, relacionais, l ogicos, de bits, condicional, de incremento e decremento, v rgula, operador m odulo. Operadores de aloca ca o e dele ca o de mem oria (new e delete). O uso de typedef para criar apelidos, e o uso de sizeof e size_t. Finalmente, vimos o operador de resolu ca o de escopo.
C.4
Exerc cios
1. Dados os operadores (), new e ==, qual tem maior preced encia? 2. Monte um exemplo que utilize todos os operadores aritm eticos. 3. Explique a diferen ca entre o operador de atribui ca o e os operadores compostos. 4. Compilar e rodar o exemplo da listagem C.1, usando diferentes valores de a e b. Depois, modique o exemplo da listagem C.1. 5. Modique o exemplo da listagem C.2. 6. Modique o exemplo da listagem C.3. 7. Modique o exemplo da listagem C.4. 8. Modique o exemplo da listagem C.5. 9. Modique o exemplo da listagem ??.
666
Ap endice D
Estruturas de Controle
Apresenta-se neste ap endice uma introdu ca o ` as estruturas de controle (se ca o D.1). Veremos as estruturas condicionais (se ca o D.2) e as estruturas de repeti ca o (se ca o D.3). No nal do cap tulo s ao listados alguns programas que mostram o uso pr atico das estruturas de controle.
D.1
Um programa sem estruturas de controle e um programa sequ encial, em que uma linha e executada ap os a outra. De um modo geral as linguagens de programa ca o oferecem dois tipos de estruturas de controle, ` as condicionais e as de repeti ca o. Ambas podem ser utilizadas para alterar a sequ encia de execu ca o do programa. Nas estruturas condicionais a sequ encia de execu ca o e alterada em fun ca o de decis oes que s ao tomadas durante a execu ca o do programa. J a as estruturas de repeti ca o s ao utilizadas para realiza ca o de repeti co es (la cos/loopings) de um determinado bloco de c odigo. As estruturas de controle de C++ s ao: Estruturas condicionais if (veja se ca o D.2.1), if..else (veja se ca o D.2.2), if..else..if..else (veja se ca o D.2.3), switch..case (veja se ca o D.2.4), operador? (veja se ca o D.2.5). Estruturas de repeti ca o for (veja se ca o D.3.1), while (veja se ca o D.3.2), do..while (veja se ca o D.3.3), break (veja se ca o D.3.4), continue (veja se ca o D.3.5). Bem, antes de come car vale a pena lembrar que uma express ao e verdadeira se retorna um n umero diferente de 0 (ou true), e e falsa se retorna 0 (ou false). 667
668
D.2
Estruturas condicionais
Nas estruturas condicionais a sequ encia de execu ca o e alterada em fun ca o de decis oes que s ao tomadas durante a execu ca o do programa.
D.2.1
if
Um instru ca o if e utilizada para garantir que determinada a ca o s o ser a executada se a express ao condicional for verdadeira. No prot otipo a seguir, se a express ao for verdadeira vai executar a pr oximo linha (ou bloco). Prot otipo: if(express ao condicional) a ca o; Prot otipo: if(express ao condicional) { a ca o1; a ca o2;...a ca oN; } Exemplo: int x = 0, y = 1; if( x > y ) cout < < x > y. ;
D.2.2
if.....else
Uma estrutura de controle do tipo if..else e utilizada quando a a ca o a ser executada depende de uma condi ca o. Veja no prot otipo a seguir que numa estrutura de controle do tipo if..else, se a express ao for verdadeira vai executar a a c~ ao1, se for falsa vai executar a a c~ ao2. No exemplo, como x n ao e maior ou igual a y, vai imprimir x < y. Prot otipo: if(express ao condicional) a ca o1; else a ca o2; Exemplo: int x = 0; int y = 1; if( x >= y ) { cout < < "x >= y"< < endl; } else { cout < < "x < y"< < endl; } Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
669
D.2.3
Outra estrutura de controle condicional, if..else..if..., e utilizada quando a a ca o a ser executada al em de depender de uma condi ca o espec ca, esta relacionada as demais condi co es e a co es. O uso de if..else..if..else, produz um c odigo r apido. Sempre coloque no in cio da sequ encia de if..else os tens com maior probabilidade de ocorr encia. O primeiro if que for verdadeiro vai ser executado, os demais s ao pulados. Cada else esta associado ao if imediatamente acima. Prot otipo: if(express ao condicional1) ...a ca o1...; else if (express ao condicional2) a ca o2; ... else if (express ao condicional n) a ca o n; No exemplo a seguir se a idade e menor do que 12 ent ao a sa da ser a crian ca. Se a idade e maior que 12 e menor do que 18 ent ao a sa da ser a adolescente. Se a idade for maior que 18 a sa da ser a adulto. Exemplo: if( idade < 12 ) cout < < "crian ca"; else if ( idade < 18 ) cout < < "adolescente"; else cout < < "adulto";
D.2.4
switch....case
A instru ca o switch case e utilizada quando se deseja fazer uma sele ca o entre uma s erie de semelhante a uma sequ op co es. E encia if..else. Se nenhuma op ca o satisfazer a condi ca o vai realizar a instru ca o default. Veja prot otipo a seguir. Note que resposta deve ser inteiro ou ser convertido para inteiro. Observe que o m de uma instru ca o case: n ao e automaticamente delimitado pelo in cio do pr oximo case, precisamos incluir a palavra-chave break. Prot otipo: switch (resposta) { case a: intru co es1; break; case b: intru co es2; break; default: instru ca o default; }
// Se resposta == a // Realiza instru co es 1 // Encerra o switch // Se resposta == b // Realiza instru co es 2 // Encerra o switch // Opcional (sempre a u ltima)
A listagem D.1 mostra o uso de switch. Veremos o uso de for na se ca o D.3.1. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
670
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
# include < vector > # include < iostream > # include < iomanip > # include < string > using namespace std ; int main () { vector < string > time ; time . push_back ( string time . push_back ( string time . push_back ( string time . push_back ( string
( " Palmeiras " ) ) ; ( " Corintians " ) ) ; ( " S~ a o Paulo " ) ) ; ( " Santos " ) ) ;
cout << " Para encerrar , digite o caractere de fim de arquivo .\ n " << " No Windows / DOS ( ctrl + z ) no GNU / Linux , Unix ( ctrl + d ) :\ n " << " --> Qual o seu time do cora ca ~ o < - -:\ n " ; for ( int i = 0; i < time . size () ; i ++) cout << setw (20) << time [ i ] << " ( " << setw (2) << i << " ) : " << endl ; int resp ; while ( cin >> resp ) { cin . get () ; string osite ( " O site de seu time est a em : \ n " ) ; switch ( resp ) { case 0: cout << " Parab e ns , voc^ e escolheu um t e t r a c a m p e a ~ o Brasileiro . " << osite << " http :// www . palmeiras . com . br / " << endl ; break ; case 1: cout << " Parab e ns , voc^ e escolheu um tricampe~ a o Brasileiro . " << osite << " http :// www . corinthia n s . com . br / " << endl ; break ; case 2: cout << " Parab e ns , voc^ e escolheu um tricampe~ a o Brasileiro " << osite << " http :// www . spfc . com . br / " << endl ; break ; case 3: cout << " Parab e ns , voc^ e escolheu um campe~ a o Brasileiro . " << osite << " http :// www . s a n t o s f u t e b o l c l u b e . com . br / " << endl ; break ; default : cout << " Entrou na op ca ~ o default do switch , ou seja , voc^ e entrou " << " com uma op ca ~ o errada , repita a opera ca ~ o . " << endl ; break ; // Break o p c i o n a l } } return 0; } Para encerrar , digite o caracter de fim de arquivo . No windows / DOS ( ctrl + z ) no unix / linux / mac ( ctrl + d ) : --> Qual o seu time do cora ca ~ o < - -:
671
D.2.5
express~ ao_condicional?
a c~ ao_verdadeira :
a c~ ao_falsa;
O operador condicional ? eou nico operador tern ario do C++, o mesmo foi descrito na se ca o C.1.7.
D.3
Estruturas de repeti c ao
Nas estruturas de repeti ca o um determinado bloco de c odigo e repetido um determinado n umero de vezes. As estruturas de repeti ca o s ao utilizadas para realiza ca o la cos/loopings. O objetivo das estruturas de controle e possibilitar o controle e as tomadas de decis oes nos programas.
D.3.1
O for e uma estrutura de controle de repeti ca o utilizado para a realiza ca o de la cos (loopings ). O prot otipo a seguir ilustra a forma de uso do for. O primeiro tem e a inicializa ca o da vari avel de controle do la co. O segundo tem e a condi ca o utilizada para continuar no la co. Se a condi ca o for falsa o la co e encerrado. O terceiro tem, a a c~ ao1 e a opera ca o que vai ser executada a cada la co. J a a a c~ ao2, e utilizada, geralmente, para modicar a vari avel de controle. Prot otipo: for( inicializa ca o; condi ca o; a ca o2 ) a ca o1; No exemplo abaixo, cria uma vari avel cont do tipo int e inicializa com o valor 3. A seguir testa se cont e menor que 20. Depois do teste, entra dentro do bloco e executa a linha (cout < < "\nO valor de cont e agora = " < < cont;). Depois de realizada a execu ca o do bloco, a a c~ ao2 e executada, isto e, cont++. Exemplo: for ( int cont = 3; cont < 20; cont++ ) { cout < < "\nO valor de cont e agora = " < < cont ; } cout < < \nfor encerrado < < endl; Veja abaixo a seq uencia de execu ca o: int cont = 3; cont < 20 ? cout < < "\nO valor de cont e agora = " < < cont; cont++; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
672
D.3. ESTRUTURAS DE REPETIC AO cont < 20 ? cout < < "\nO valor de cont e agora = " < < cont; cont ++; cont < 20 ? cout < < "\nO valor de cont e agora = " < < cont; cont++; .... // Quando cont = = 20 o for e encerrado. cout < < \nfor encerrado < < endl;
D.3.2
Enquanto a condi ca o for verdadeira executa a a ca o. O comando while pode ser usado no lugar de for, veja o prot otipo e exemplo a seguir. Prot otipo: while ( condi ca o ) { a ca o; }; Exemplo: // O for abaixo, for( inicio ; condi c~ ao ; a c~ ao2 ) { a c~ ao1; } // Pode ser realizado usando while desta forma inicio; while( condi c~ ao ) { a c~ ao1; a c~ ao2; } Veja exemplos de uso de while nas listagens 8.6 e D.2. Listing D.2: Usando while.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # include < iostream > using std :: cout ; using std :: endl ; int main () { int y , x = 1 , total = 0; while ( x <= 5) { y = x * x; cout << x << " \ t " << y << endl ; total += y ; ++ x ; } cout << " Total = " << total << endl ; return 0; }
673
D.3.3
O comando do while, realiza a a ca o e somente depois testa a condi ca o. Desta forma a a ca o e executada pelo menos uma vez. Veja a seguir o prot otipo e na listagem D.3 um exemplo. Prot otipo: do { a ca o; } while ( express ao condicional ); Listing D.3: Usando do..while.
1 2 3 4 5 6 7 8 9 10 11 12 13 # include < iostream > int main () { int i = 1; do { // Sempre r e a l i z a o l o o p i n g pelo menos 1 vez . std :: cout << i << " " ; } while (++ i <= 10) ; std :: cout << std :: endl ; return 0; } 1 2 3 4 5 6 7 8 9 10
D.3.4
break
Um break pode ser usado dentro de um for, em um while, do...while, ou switch. Quando um break e encontrado, o bloco e encerrado. No prot otipo a seguir, se a condi ca o2 for verdadeira a a c~ ao2 n ao ser a executada, e o for e encerrado. Prot otipo: for( inicio; condi ca o ; a ca o3 ) { a ca o1; if( condi ca o2 ) break; a ca o2; } Veja a seguir um exemplo. Exemplo: for( int i = 0; i < 10 ; i++ ) { Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
674 cout < < "valor de i = " < < i < < endl; if( i == 5 ) break; cout < < "Passou pelo break" < < endl; }
D.3.5
continue
O controle continue (usado em for, while, do..while), faz com que o programa pule as pr oximas linhas e prossiga na express ao que controla o la co. Isto e, quando continue e executado todos os pr oximos passos s ao pulados e o pr oximo la co e executado. Se assemelha a um comando goto. No prot otipo a seguir, se a condi ca o for verdadeira, a a c~ ao2 n ao e executada, o pr oximo passo a ser executado e a a c~ ao3 e a seguir a condi ca o. Prot otipo: for( inicio; condi ca o; a ca o3 ) { a ca o1; if( condi ca o ) continue; a ca o2; } Veja exemplo de uso de break e continue na listagem D.4. Listing D.4: Usando break, continue, do..while, e switch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # include < iostream > using namespace std ; void T e s t a n d o _ b r e a k () ; void T e s t a n d o _ c o n t i n u e () ; int main () { char resp ; do { cout << " Testar o break ( b ) ou o continue ( c ) , ( q ) para sair : " ; cin . get ( resp ) ; cin . get () ; switch ( resp ) { case b : case B : T e s t a n d o _ b r e a k () ; break ; case c : case C : T e s t a n d o _ c o n t i n u e () ; break ; case q : case Q : cout << " Tchau . " << endl ; break ;
675
default : cout << " Op ca ~ o inv a lida : " << endl ; } } while ( resp != q && resp != Q ) ; return 0; } void T e s t a n d o _ b r e a k () { for ( int x = 1; x <= 10; x ++ ) { if ( x == 5) break ; // E n c e r r a o l o o p i n g quando x ==5 cout << x << ; } cout << " \ nQuando x ==5 , executa o break e sai do looping . " << endl ; } void T e s t a n d o _ c o n t i n u e () { for ( int x = 1; x <= 20; x += 1 ) { if ( x == 5) continue ; // Pula para p r o x i m o passo do l o o p i n g quando x ==5 cout << x << " ; " ; } cout << " \ nUm continue continua o looping , mas pula todas as linhas abaixo . " << " \ nObserve acima que n~ a o imprimiu o n u mero 5. " << endl ; } Testar o break ( b ) ou o continue ( c ) , ( q ) para sair : b 1 2 3 4 Quando x ==5 , executa o break e sai do looping . Testar o break ( b ) ou o continue ( c ) , ( q ) para sair : c 1;2;3;4;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20; Um continue continua o looping , mas pula todas as linhas abaixo . Observe acima que n~ a o imprimiu o n u mero 5. Testar o break ( b ) ou o continue ( c ) , ( q ) para sair : q Tchau .
D.4
As estruturas de controle s ao utilizadas em la cos (loopings ), na realiza ca o de contagens, na escolha entre diferentes blocos de instru co es. Os objetos declarados dentro do for s o s ao vis veis dentro do for. Evite o uso de do...while();. Enquanto break encerra o la co, continue continua sem executar as linhas que est ao abaixo.
D.5
Neste ap endice aprendemos a usar as estruturas de controle de C++. As estruturas condicionais, if, if..else, if..else..if..else, switch..case, e o operador ?. Vimos ainda as Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
D.6
Exerc cios
1. Comece modicando os exemplos das listagens deste cap tulo. 2. Na listagem D.1 acrescente dados do seu time de cora ca o. 3. Na listagem D.1 elimine os break e veja o que acontece. 4. Na listagem 8.4 mude os valores iniciais e nais do la co e veja o que acontece. 5. Modique a listagem 8.5. Fa ca a mesma coisa usando dentro do primeiro for um while. 6. Modique a listagem 8.6 acrescentando uma mensagem de erro e um break caso o valor da potencia ultrapasse o limite suportado para um int. 7. Na listagem D.2 modique os valores iniciais de x, e a condi ca o de sa da do while. Pense em acrescentar dentro do while um for. 8. Na listagem D.3 modique o valor inicial de i e a condi ca o de sa da. Pe ca para o usu ario entrar com estes dados. 9. Monte um pequeno programa de cadastro de alunos de um col egio. O programa deve: (a) ter fun co es para adicionar/eliminar novos alunos. (b) ter uma fun ca o de entrada que deve solicitar os seguintes dados: Nome do aluno, idade, n umero de registro no col egio, coecienteDeRendimento. (c) ter duas fun co es de sa da. A primeira deve mostrar na tela a lista de alunos em ordem crescente usando a idade como par ametro classicador. A segunda fun ca o deve usar o n umero de registro como par ametro classicador. (d) a sele ca o do tipo de fun ca o a ser executada deve ser feita utilizando-se um switch. 10. Para o programa acima descrito monte uma fun ca o que recebe dois alunos como par ametros. A fun ca o deve imprimir na tela os dados do aluno que tem o maior coecienteDeRendimento. Esta fun ca o ser a utilizada para efeitos de classica ca o dos alunos quando os mesmos solicitarem alguma bolsa de aux lio. 11. Para o programa acima descrito monte uma fun ca o que mostra na tela a lista de alunos aprovados (notaM edia >= 6) e a lista de alunos reprovados (notaM edia < 6). Nota: voc e encontra na refer encia [Holloway, 2006], diversos exemplos de algoritmos em C++, e nas refer encias [Cormen et al., 2002, Boente, 2006] exemplos gen ericos de algoritmos.
Ap endice E
E.1
A fun ca o principal de um programa e chamada main(). Quando um programa e executado na linha de comando do DOS, Unix, GNU/Linux, Mac OS X, Windows, o sistema operacional chama a fun ca o main() do programa e passa para o programa dois argumentos: o texto da linha de comando e o n umero de strings da linha de comando. Assim, voc e pode utilizar a linha de comando para entrada de informa co es para seu programa. Veja a seguir o prot otipo da fun ca o main(). O par ametro argc e o n umero de elementos da linha de comando e argv[] o vetor para as strings digitadas na linha de comando. Prot otipo: int main(int argc, const char *argv[]) {...... return 0;} No exemplo a seguir, o programa recebe um vetor com as strings {cp, funcoes.lyx, funcoes.lyx~} e o n umero de argumentos da linha de comando que e 3. Exemplo: // Na linha de comando do GNU/Linux digitou-se: cp funcoes.lyx funcoes.lyx~ // O programa interpreta o seguinte: // argc = 3 // argv[0] = "cp" // argv[1] = "funcoes.lyx" // argv[2] = "funcoes.lyx~" Veja na listagem E.1 exemplo de uso de entrada na linha de comando. Listing E.1: Fun ca o main() e a entrada na linha de comando.
1 2 # include < iostream > using namespace std ;
677
678
3 4 5 6 7 8 9 10 11
int main ( int argc , char ** argv ) { cout << " argc = " << argc << endl ; int cont = argc ; while ( cont - -) cout << " argv [ " << cont << " ]= " << argv [ cont ] << endl ; return 0; } [ b u e n o @ s u p o r t e 3 Parte - VI ] $ ./ a . out opcao1 opcao2 opcao3 argc =4 argv [3]= opcao3 argv [2]= opcao2 argv [1]= opcao1 argv [0]=./ a . out
E.2
A fun ca o getopt(), declarada no arquivo de cabe calho /usr/include/unistd.h, fornece um mecanismo simples para processar a linha de comando. Veja a seguir o prot otipo da fun ca o getopt(). Como existem casos e necessidades especiais, tamb em foram denidas um conjunto de vari aveis globais que s ao utilizadas por getopt(): Prot otipo: extern char *optarg; // Ponteiro para pr oxima string extern int optind; // Indice para pr oximo argumento extern int opterr; // Flag de erro extern int optopt; // Caracter inv alido const char* optstring; // Lista de par ametros v alidos int getopt ( int argc, char* argv[], const char* optstring ); A fun ca o getopt() recebe os par ametros argc e argv[], e uma string de C (const char* optstring ) com a lista de par ametros v alidos (ex: -abc:d). Se o par ametro e v alido o mesmo e retornado. Se o par ametro e inv alido o retorno e o caracter ? e optopt e setado com o caracter inv alido. Se o par ametro requer um valor adicional (ex: -c arq.dat) e o mesmo n ao e fornecido, retorna :. Se n ao existem mais par ametros retorna -1. Em alguns sistemas, quando um par ametro n ao e v alido, uma mensagem de erro e enviada para sa da de erro. O exemplo da listagem E.2 mostra o uso de getopt(). Observe que a cada chamada getopt() processa uma nova op ca o. O uso de : depois de c indica que c recebe um argumento string, a mesma e recuperada com optarg. Listing E.2: Processando par ametros de main() com getopt().
1 2 3 4 5 6 7 8 9 10 # include < unistd .h > # include < iostream > using namespace std ; int main ( int argc , char * argv []) { int opt ; // E n q u a n t o o r e t o r n o da fun c~ a o getopt () for d i f e r e n t e de -1 // p r o c e s s a linha de c o m a n d o while (( opt = getopt ( argc , argv , " abc : d " ) ) != -1)
679
" Op ca ~ o = " << static_cast < char >( opt ) << endl ;
" Op ca ~ o = " << static_cast < char >( opt ) << endl ; // inclui a r g u m e n t o adicional , uso de optarg " Op ca ~ o = " << static_cast < char >( opt ) " Argumento = " << optarg << endl ;
<< endl ;
// Indica op c~ ao inv alida " Op ca ~ o Inv a lida = " << static_cast < char >( optopt ) << endl ; // Indica falta de a r g u m e n t o s " Falta de argumentos . " << endl ;
} // Lista de a r g u m e n t o s errados , m o v i d o s para o fim de argv for (; optind < argc ; optind ++) cout << " Op ca ~ o inv a lida argv [ " << optind << " ]= " << argv [ optind ] << endl ; // R e s t a n t e do p r o g r a m a ... return 0; } bash -3.00 $ ./ a . out - a Op ca ~o = a bash -3.00 $ ./ a . out - abc Op ca ~o = a Op ca ~o = b ./ a . out : option requires an argument -- c Op ca ~ o Inv a lida = c bash -3.00 $ ./ a . out - abc arg . dat Op ca ~o = a Op ca ~o = b Op ca ~ o = c Argumento = arg . dat bash -3.00 $ ./ a . out - ab -c arg . dat -f Op ca ~o = a Op ca ~o = b Op ca ~ o = c Argumento = arg . dat ./ a . out : invalid option -- f Op ca ~ o Inv a lida = f
E.3
Uma fun ca o recursiva e uma fun ca o que chama a s mesma. Veja a seguir um exemplo de fun ca o recursiva. A mesma e utilizada para calcular o n umero de Fibonaci. Observe que dentro do else a fun ca o e chamada de forma recursiva. Exemplo: // N umeros de Fibonaci long fibonaci(long n) Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
680
E.4. USO DE ELIPSE ... EM FUNC OES { if(n==0 || n==1) return n; else return fibonaci(n-1) + fibonaci(n-2); // Observe a recurs~ ao }
Observe que em fun co es recursivas existe um excesso de chamadas de fun co es, o que diminui a performance do sistema. O exemplo da listagem E.3 apresenta uma fun ca o recursiva que calcula o fatorial de um n umero. Listing E.3: Fun ca o recursiva: c alculo do fatorial.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # include < iostream > # include < iomanip > using namespace std ; long int fatorial ( long int ) ; // D e c l a r a c~ a o da fun c~ ao
int main () { long int min ; cout << " Entre com o valor m nimo ( min ) : " ; cin >> min ; long int max ; cout << " Entre com o valor m a ximo ( max ) : " ; cin >> max ; cin . get () ; // Pega o enter for ( long int i = min ; i <= max ; i ++) cout << setw (2) << i << " ! = " << fatorial ( i ) << endl ; return 0; } // D e f i n i c~ a o da fun c~ a o ( lembre - se , f a t o r i a l 5 = 5 * 4 * 3 * 2 * 1 ) long int fatorial ( long int n ) { if ( n <= 1) // Se for menor ou igual a 1 r e t o r n a 1 ( f i n a l i z a ) return 1; else // Se for >1 chama fun c~ ao fatorial novamente ( recurs~ a o) return n * fatorial ( n - 1) ; } Entre com o valor m nimo ( min ) : 5 Entre com o valor m a ximo ( max ) : 9 5! = 120 6! = 720 7! = 5040 8! = 40320 9! = 362880
E.4
A elipse refere-se a tr es pontos como par ametro de uma fun ca o. Uma elipse numa lista de par ametros signica que a fun ca o pode receber mais par ametros. Um exemplo de fun ca o que Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
681
utiliza elipses e a printf() (de C), que pode receber um n umero variado de par ametros. Para maiores informa co es, veja a fun ca o printf() e o help de seu ambiente de desenvolvimento. Veja na listagem E.4 exemplo de uso de elipse. Observe que a fun ca o va_start inicializa a retirada de vari aveis da pilha, a fun ca o va_arg retira uma vari avel da pilha, especicando o tamanho em bytes da vari avel (o que e feito passando o double), e a fun ca o va_end naliza a retirada de dados da pilha. Isto signica que a utiliza ca o de elipse altera o estado da pilha e sua utiliza ca o deve ser evitada, ou utilizada somente ap os a fun ca o ter sido extensivamente testada. Listing E.4: Usando elipses (...) : fun ca o m edia.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # include < cstdarg > # include < iostream > # include < cmath > // D e c l a r a c~ a o da fun c~ a o Media double Media ( int n ,...) ; // n e o n u mero de e l e m e n t o s int main () { double media ; int n =4; double i =1 , j =2 , k =3 , l =4; std :: cout << " M e dia = " << Media (n ,i ,j ,k , l ) ; return 0; } // D e f i n i c~ a o da fun c~ a o Media () , o b s e r v e o uso de elipse ... double Media ( int n ,...) { double total = 0; va_list variavel ; // Cria lista v a r i avel va_start ( variavel , n ) ; // I n i c i a l i z a lista v a r i avel for ( int j = 1 ; j <= n ; j ++ ) { double valor = va_arg ( variavel , double ) ; std :: cout << " valor lido = " << valor << std :: endl ; total += valor ; } va_end ( variavel ) ; // E n c e r r a lista return total / n ; } valor valor valor valor M e dia lido = lido = lido = lido = = 2.5 1 2 3 4
E.5
Objetos grandes devem ser passados por refer encia ou por ponteiros. O nome de uma fun ca o e um ponteiro para fun ca o com endere co constante, denido na compila ca o. Em C++ podemos declarar a fun ca o assim: void NomedaFuncao(); // C++ void NomedaFuncao(void); // C Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
682
Quando utilizamos uma matriz como argumento de uma fun ca o, os valores s ao passados por refer encia e n ao por c opia. Se a matriz estiver dentro de uma estrutura, ela ser a passada por c opia. Como as fun co es de C++ denidas em um arquivo podem ser utilizadas em outro arquivo, as mesmas tem uma liga ca o extern por default. Performance: par ametros passados por refer encia aumentam a eci encia, pois os valores n ao s ao copiados. Na fun ca o main(), o retorno do valor 0 informa ao sistema operacional que o programa foi nalizado com exito. Qualquer valor diferente de zero indica um erro. Dentro da fun ca o main(), inclua um mecanismo simples de tratamento de exce co es. Veja Cap tulo 26 - Exce co es. Quando main() e encerrada com return(); ou exit(); os objetos est aticos s ao destru dos na ordem inversa em que foram constru dos. Seguran ca: se voc e quer ter certeza de que o par ametro n ao ser a alterado, deve pass a-lo como refer encia constante. Veja o exemplo a seguir. O especicador const informa que a vari avel e constante e n ao pode ser alterada dentro da fun ca o. Deste modo, a fun ca o pode acessar a vari avel, mas n ao pode modic a-la. Exemplo: fun c~ ao(const tipo& vari avel);
E.6
Neste ap endice aprendemos a utilizar a fun ca o main() e a entrada na linha de comando. Aprendemos que main() e a fun ca o de entrada em um programa em C/C++ e que seus par ametros podem ser processados com getopt(). Vimos ainda as fun co es recursivas, e o uso de elipse ... em fun co es.
E.7
Exerc cios
1. Modique a listagem 8.11 de forma que a lista de n umeros aleat orios seja salva em disco. 2. Use o nd de seu computador para localizar a biblioteca cstdlib (no gnu/linux ca em /usr/include/c++/vers ao do compilador). Veja o arquivo <cstdlib> e localize a declara ca o das fun co es srand() e rand(). 3. Modique a listagem E.1, fa ca com que a mesma receba uma lista de n umeros inteiros e mostre na tela os valores recebidos e a sua m edia aritm etica. 4. Modique o exemplo da listagem E.2, de forma que a op ca o passada seja utilizada para executar uma fun ca o interna. Por exemplo, m ir a calcular a m edia dos elementos recebidos, s ir a calcular o desvio padr ao, i os valores dever ao ser passados pelo usu ario. 5. Modique a listagem E.3, alertando o usu ario quando o n umero for muito grande. 6. Modique o exemplo da listagem E.4, acrescentando o c alculo do desvio padr ao e a possibilidade de entrada dos dados. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
E.7. EXERC ICIOS 7. Modique a listagem 8.8 de forma que o usu ario entre com o valor do expoente.
683
8. Modique a listagem 8.11 acrescentando o uso de outras fun co es das bibliotecas de C. 9. Implementar fun ca o para c alculo do n umero de Fibonaci (veja se ca o E.3).
684
Ap endice F
F.1
Opera co es que podem ser realizadas com ponteiros: A subtra ca o de dois ponteiros retorna o n umero de elementos entre os dois ponteiros. Exemplo: int array = {0,1,2,3,4}; int* ptr1 = &array[0]; int* ptr2 = &array[4]; No exemplo abaixo, o n umero n e o n umero de objetos entre ptr1 e ptr2 int n = ptr2 - ptr1; cout < < "N umero de objetos entre ptr2 e ptr1 = " < < n < <
endl;
Podemos comparar ponteiros com os operadores relacionais (> , >=, <, <= , = =, !=): 685
686
F.2. PONTEIRO VOID* Exemplo: if(ptr == ptr2) cout < < "ptr2 e ptr1 apontam para o mesmo objeto." < <
endl;
Podemos incrementar (ptr++) e decrementar (ptr--) um ponteiro. No exemplo a seguir, se ptr aponta para o elemento 0 de um vetor, ptr++, faz com que passe a apontar para o elemento 1 do vetor. O valor num erico do incremento e denido pelo valor retornado por sizeof: Exemplo: cout < < "O ptr1++; cout < < "O cout < < "O ptr2--; cout < < "O
ponteiro ptr1 aponta para " < < // Incrementa ptr ponteiro ptr1 aponta para " < < ponteiro ptr2 aponta para " < < // Decrementa ptr ponteiro ptr2 aponta para " < <
*ptr1 < < endl; *ptr1 < < endl; *ptr2 < < endl; *ptr2 < < endl;
Podemos somar ou subtrair um ponteiro de um inteiro. No exemplo abaixo, 3 signica 3 vari aveis ` a frente, e n ao 3 bytes. ptr1 = ptr + 3; cout < < "O ponteiro ptr1 aponta para " < < *ptr1 < < endl;
F.2
Ponteiro void*
Um ponteiro void* e um ponteiro de prop osito geral, que aponta para qualquer tipo de objeto e e usualmente utilizado como par ametro de fun co es de prop osito geral. Para ser desreferenciado, um ponteiro void deve ser convertido para um tipo conhecido em tempo de compila ca o, pois um ponteiro void* n ao tem a informa ca o do tipo do objeto para o qual est a apontando. Se um ponteiro e do tipo int*, o objeto apontado tem o tamanho de um inteiro, assim o compilador sabe quantos bytes deve ler a partir do endere co especicado pelo ponteiro. Quando um ponteiro e do tipo void*, o compilador s o sabe a posi ca o para a qual ele aponta, mas n ao sabe a quantidade de bytes que deve ser lida (ou escrita). Veja no exemplo a seguir que tenta colocar 7 em i, mas ocorre um erro, pois void n ao necess pode utilizar o operador desreferencia ca o *. E ario formatar o ponteiro void*, denindo o tamanho da mem oria que vai ser acessada. Exemplo: // ptr_void e um ponteiro para qualquer coisa. void* ptr_void; // Ponteiro para int int * ptr_int; // Cria objeto do tipo int, com nome i e valor 5 int i = 5; // Endere co do objeto i e armazenado em ptr_int ptr_int = & i; // Endere co do objeto i e armazenado em ptr_void ptr_void = & i; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
F.3. PONTEIRO PARA PONTEIRO // Coloca o valor 5 em i *ptr_int = 5; // Tenta colocar 7 em i usando ptr_void (ocorre um erro) *ptr_void = 7; // ok, converte ptr_void para int* e depois desrefer^ encia. *(int*) ptr_void = 7; // C *(static_cast<int*> (ptr_void) = 7; // C++
687
F.3
Um ponteiro e utilizado para refer encia indireta a um determinado objeto, armazenando o endere co do objeto. Um ponteiro tamb em e um objeto. Logo, um ponteiro pode apontar para outro ponteiro. Veja o exemplo. Listing F.1: Ponteiro de ponteiro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # include < iostream > using namespace std ; int main () { int variavel = 33; int * ptr1 ; int ** ptr2 ; int *** ptr3 ; // P o n t e i r o com e n d e r e camento indireto simples // P o n t e i r o com e n d e r e c a m e n t o i n d i r e t o duplo // P o n t e i r o com e n d e r e c a m e n t o i n d i r e t o triplo
ptr1 =& variavel ; // Coloca e n d e r e c o da v a r i a v e l em ptr1 , // ou seja , ptr1 aponta para v a r i avel ptr2 = & ptr1 ; // ptr2 aponta para ptr1
ptr3 = & ptr2 ; // ptr3 aponta para ptr2 cout << " vari a vel = " << variavel << endl ; * ptr1 = 5; // A r m a z e n a o valor 5 em v a r i a v e l ( usando ptr1 ) cout << " vari a vel = " << variavel << endl ; ** ptr2 = 7; // A r m a z e n a o valor 7 em v a r i a v e l ( usando ptr2 ) cout << " vari a vel = " << variavel << endl ; *** ptr3 = 14; // A r m a z e n a o valor 14 em v a r i a v e l ( usando ptr3 ) cout << " vari a vel = " << variavel << endl ; return 0; } vari a vel vari a vel vari a vel vari a vel = = = = 33 5 7 14
Vamos relatar este u ltimo caso ***ptr3 = 14; utilizando novamente a met afora do carteiro. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
688
O pobre do carteiro tem muito trabalho. Ele pega o n umero 14 e vai at e a casa de ptr3. Chegando l a, recebe ordem para ir at e a casa de ptr2; j a cansado, chega at e a casa de ptr2 e, para sua surpresa, recebe ordem para ir at e ptr1. Chateado e com fome, vai at e a casa de ptr1;. Para sua desgra ca, recebe ordem para ir at e a casa da vari avel; o pobre coitado leva o n umero 14 at e a casa da vari avel e, como n ao e de ferro, descansa. Em resumo: Quando voc e faz Tipo *ptr; est a criando um ponteiro para o Tipo. Quando voc e utiliza ptr1= &algo;, est a armazenando o endere co da vari avel no ponteiro. Quando voc e utiliza int **ptr2= &ptr1;, est a criando um ponteiro de ponteiro com nome ptr2, e armazenando o endere co de ptr1 em ptr2. Quando voc e utiliza int ***ptr3 = &ptr2;, o ponteiro de ponteiro de ponteiro ptr3 vai apontar para a mesma vari avel que ptr2. Quando voc e utiliza ptr=& x; *ptr=55;, est a armazenando o valor 55 na vari avel apontada por ptr, no caso a vari avel x.
F.4
Convers ao de ponteiros
A Tabela F.1 mostra a convers ao de ponteiros. Na primeira linha, um Tipo e convertido em uma refer encia para o tipo (Tipo&). A compreens ao dessa Tabela e importante. Leia cada linha com cuidado. Tabela F.1: Convers ao de ponteiros. Para Descri ca o Tipo& de Tipo para refer encia Tipo de refer encia para Tipo Tipo * converte um vetor const para um ponteiro Tipo(*)(argumentos) de fun ca o para ponteiro de fun ca o const Tipo de Tipo para const Tipo volatile Tipo de Tipo para volatile Tipo const Tipo* de Tipo* para const Tipo* volatile Tipo* de Tipo* para volatile Tipo*
F.5
Utilizando auto_ptr
Como descrito no Cap tulo 26 - Exce co es, se voc e tem um objeto din amico (por ex.: int* ptr = new int[30];) e ocorre uma exce ca o, voc e deve fornecer mecanismos para apagar os objetos din amicos. Esta pode ser uma situa ca o complicada. O auto_ptr e uma classe ponteiro que tem uma rela ca o ntima com a RTTI (tabela de informa co es em tempo de execu ca o), de forma que se ocorrer uma exce ca o ap os a aloca ca o de um objeto din amico, este se auto-deleta. Ou seja, ao sair de escopo um ponteiro auto_ptr, automaticamente chama o destrutor do objeto. A classe auto_ptr e denida no arquivo de cabe calho <memory>. Veja o exemplo da listagem F.2. Observe que o mais f acil de usar e o mais vers atil e o <vector> da STL. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
689
Note na sa da a presen ca de valores negativos. Isto ocorre porque quando constru mos um vetor, o primeiro objeto e constru do usando construtor default, e os demais usando o construtor de c opia. Ou seja, para eliminar os valores negativos e necess ario implementar o construtor de c opia. Listing F.2: Comparando o uso de vetores est aticos de C, din amicos de C++, com auto_ptr de C++ e <vector> da stl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 # include < iostream > # include < memory > # include < vector > using namespace std ; class CTipo { public : int t ; static int cont ; CTipo () { cont ++; cout << " Construtor do objeto , cont = " << cont << endl ; } ~ CTipo () { cout << " Destrutor do objeto , cont = " << cont << endl ; cont - -; } }; int CTipo :: cont = 0; int main () { cout << " ----- vetor est a tico de C : " << endl ; { CTipo v_static [2]; // Cria vetor e s t a t i c o com 2 e l e m e n t o s } // D e s t r o i vetor ao sair de escopo cout << " ----- vetor din^ a mico em C ++ sem STL : " << endl ; { CTipo * v_dinamico = new CTipo [3]; // ..... U t i l i z a o vetor ... delete [] v_dinamico ; // P r e c i s a do delete [] } // Usando auto_ptr , a u t o _ p t r n~ a o deve a p o n t a r para um vetor . cout << " ----- Objeto din^ a mico em C ++ com auto_ptr : " << endl ; { auto_ptr < CTipo > v_autoptr ( new CTipo ) ; v_autoptr - > t = 77; // ..... U T i l i z a o vetor ... cout << " t = " << v_autoptr - > t << endl ; } // a p a g a d o a u t o m a t i c a m e n t e cout << " ----- vetor din^ a mico em C ++ com STL : " << { vector < CTipo > v_stl (4 , CTipo () ) ; // for ( int i = 0; i < v_stl . size () ; i ++) { v_stl [ i ]. t = i ; cout << i << " = " << v_stl [ i ]. t << endl ; } } // D e s t r o i objeto endl ; din^ E amico
ao sair de escopo
690
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
cout << " ----- vetor de ponteiros em C ++ com STL : " << endl ; { vector < CTipo * > v_stl (5) ; // Cria vetor de p o n t e i r o s for ( int i = 0; i < v_stl . size () ; i ++) { v_stl [ i ] = new CTipo () ; // Cria objeto v_stl [ i ] - > t = i ; // Usa objeto cout << " i = " << i << " t = " << v_stl [ i ] - > t << endl ; } for ( int i = 0; i < v_stl . size () ; i ++) delete v_stl [ i ]; // Deleta o b j e t o s } return 0; }
----- vetor est a tico de C : Construto r do objeto , cont = 1 Construto r do objeto , cont = 2 Destrutor do objeto , cont = 2 Destrutor do objeto , cont = 1 ----- vetor din^ a mico em C ++ sem STL : Construto r do objeto , cont = 1 Construto r do objeto , cont = 2 Construto r do objeto , cont = 3 Destrutor do objeto , cont = 3 Destrutor do objeto , cont = 2 Destrutor do objeto , cont = 1 ----- Objeto din^ a mico em C ++ com auto_ptr : Construto r do objeto , cont = 1 t = 77 Destrutor do objeto , cont = 1 ----- vetor din^ a mico em C ++ com STL : Construto r do objeto , cont = 1 Destrutor do objeto , cont = 1 0 = 0 1 = 1 2 = 2 3 = 3 Destrutor do objeto , cont = 0 Destrutor do objeto , cont = -1 Destrutor do objeto , cont = -2 Destrutor do objeto , cont = -3 ----- vetor de ponteiros em C ++ com STL : Construto r do objeto , cont = 1 i = 0 t = 0 Construto r do objeto , cont = 2 i = 1 t = 1 Construto r do objeto , cont = 3 i = 2 t = 2 Construto r do objeto , cont = 4 i = 3 t = 3 Construto r do objeto , cont = 5 i = 4 t = 4 Destrutor do objeto , cont = 5 Destrutor do objeto , cont = 4 Destrutor do objeto , cont = 3 Destrutor do objeto , cont = 2 Destrutor do objeto , cont = 1
691
Observe que dois objetos auto_ptr n ao podem apontar para o mesmo objeto, por isso, o construtor de c opia e o operador de c opia de auto_ptr tem um comportamento estranho. Exemplo: // Cria objeto int apontado por aptr1 void auto_ptr<int> aptr1(new int()); // Abaixo faz aptr2 apontar para o objeto int e aptr1 para NULL!! auto_ptr<int> aptr2(aptr1); Desta forma, quando aptr2 sair de escopo o objeto criado e deletado, e quanto aptr1 sair de escopo nada acontece, evitando-se a destrui ca o repetida do objeto criado. Observe que esta solu ca o elimina a destrui ca o dupla do objeto criado, mas aptr1 e aptr2 n ao tem o comportamento esperado. Por este motivo aconselha-se a substitui ca o do uso de auto_ptr por shared_ptr da biblioteca boost++ (veja se ca o ??). Dica: substitua o uso de auto_ptr por shared_ptr da biblioteca boost++, veja se ca o ??.
F.6
Ponteiro de fun c ao
Voc e pode criar um ponteiro para uma fun ca o e usar o ponteiro para chamar a fun ca o. A listagem F.3 mostra um exemplo. Listing F.3: Usando ponteiro de fun ca o.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # include < iostream > using namespace std ; double cubo ( double x ) ; // D e c l a r a c~ a o da fun c~ ao int main () { // Define tipo ptr_funcao , um p o n t e i r o de fun c~ ao // que tem como p a r a m e t r o um double e como r e t o r n o um double . typedef double (* ptr_funcao ) ( double x ) ; // A r m a z e n a o e n d e r e c o da fun c~ a o no p o n t e i r o ptr_funcao ptr = cubo ; // U t i l i z a o p o n t e i r o de fun c~ a o para e x e c u t a r a fun c~ a o cubo . double x = 3; cout << " resultado = " << ptr ( x ) << endl ; return 0; } // D e f i n i c~ a o da fun c~ ao double cubo ( double x ) { return x * x * x ; } resultado = 27
O exemplo a seguir, adaptado de [Lischner, 2003], mostra outros poss veis usos de ponteiros para fun co es. Seja a fun ca o f(), que retorna um int* e recebe um int*. int* f(int*); Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
692
e a fun ca o G(), que retorna um int* e recebe um ponteiro para f(), ptr_f, e um int. int* G(int*(*ptr_f)(int*), int); Para criar um array com 10 ponteiros de fun ca o para fun ca o G() podemos usar: int* (*vptr_G[10])(int*(*)(int*), int); Note que a sintaxe do exemplo acima e confusa para usu arios iniciantes. Uma alternativa seria usar a sequ encia abaixo. Primeiro usa typedef para declarar um apelido para int* typedef int* ptrInt; A seguir, usa typedef para declarar um apelido para o ponteiro de fun ca o que retorna um ponteiro para int e recebe como par ametro um ponteiro para int. typedef ptrInt (*ptr_f)(ptrInt); Finamente, cria um array com 10 ponteiros de fun ca o para G(). ptrInt (*vptr_G[10]) (ptr_f,int);
F.7
Este e um t tulo de n vel 3, isto signica que s o deve ser lido por usu ario experiente. Em determinados casos, muito especiais (raros), voc e pode querer ter um ponteiro para um atributo ou m etodo de uma classe. Esta se ca o mostra, por meio de um exemplo, como voc e deve proceder. Exemplo: class A { static int x; // Atributo void Mx(); // M etodo } // Criando ponteiro para m etodo fx() da classe A void(A::*ptrMx)() = & A::Mx(); // Ponteiro para atributo x da classe A int A::*ptr_x = & A::x; cout < < (*ptr_x) < < endl; Veja exemplo na listagem F.4. Observe a forma como o ponteiro e criado e usado. Note que o como o m etodo e virtual e o objeto usado e do tipo derivado, o m etodo executado e o m etodo da classe derivada. Listing F.4: Ponteiro para m etodos da classe.
1 2 3 4 5 6 7 # include < iostream > class Base { public : Base ( int i ) : x_ ( i ) {} virtual ~ Base () {}
693
F.8
Ponteiros em hierarquias
Quando usamos ponteiros em uma hierarquia, o endere co apontado pode variar, um oset (deslocamento) pode ocorrer em tempo de execu ca o, veja listagem F.5. Listing F.5: Ponteiro em hierarquias e oset.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # include < iostream > using namespace std ; class Base {}; class Derivada : public Base {}; int main () { Derivada d ; Base * pb = & d ; Derivada * pd = & d ; if ( pb == pd ) cout << " pb = " << pb << " pd = " << pd << " pb == pd " << endl ; else cout << " pb != pd " << endl ; return 0; } pb =0 x 7 f f f a e b 9 4 0 9 f pd =0 x 7 f f f a e b 9 4 0 9 f pb == pd
694
Na listagem F.6 apresenta-se a utiliza ca o do operador de endere co e sizeof. Observe na sa da que nome aponta para o vetor, mostrando a sa da "LDSC - Laborat orio Desenvolvimento Software Cient fico" . O conte udo de *nome e o caracter L e o endere co de nome um endere co de mem oria. Como o conte udo de *nome e o caracter n, quando convertemos para int, obtemos o valor 76. Observe ainda que sizeof(&nome) e 8, ou seja o ponteiro nome consome 8 bytes. J a o sizeof de nome e 57, indicando que consumimos 57 caracteres (56 caracteres mais o caracter terminador \0). Nota: observe que estes valores variam de plataforma para plataforma, estes resultados s ao obtidos em um GNU/Linux/Fedora 6 com uma SUN-Ultra40 (processadores AMD-Opteron de 64 bits). Listing F.6: Usando operador de endere co (&) e sizeof().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # include < iostream > using namespace std ; int main () { char nome [] = " LDSC - Laborat o r i o D e s e n v o l v i m e n t o Software Cient fico " ; cout << " nome = " << nome ; cout << " \ n * nome = " << * nome ; cout << " \ n & nome = " << & nome ; cout << " \ n & nome [0] = " << & nome [0]; cout << " \ n nome [0] = " << nome [0]; cout << " \ n ( int ) * nome = " << ( int ) * nome ; cout << " \ n sizeof (& nome ) = " << sizeof (& nome ) ; cout << " \ n sizeof ( nome ) = " << sizeof ( nome ) << endl ; return 0; } nome = LDSC - Laborat o ri o D e s e n v o l v i m e n t o Software Cient fico * nome = L & nome = 0 x 7 f f f 9 9 9 f b d f 0 & nome [0] = LDSC - Laborat o ri o D e s e n v o l v i m e n t o Software Cient fico nome [0] = L ( int ) * nome = 76 sizeof (& nome ) = 8 sizeof ( nome ) = 57
F.9
O ponteiro void* n ao permite o uso do operador de localiza ca o(*) e endere camento(&). O conte udo de void* s o pode ser acessado depois da deni ca o do tipo de objeto para o qual o ponteiro aponta. Um ponteiro void* pode ser igualado a outros ponteiros e vice-versa. Observe a utiliza ca o da mesma palavra-chave para diferentes prop ositos: para lista de argumentos, void = nenhum argumento; para retorno de fun ca o, void = nenhum retorno; para ponteiros, void = ponteiro para qualquer tipo de objeto. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
695
Um ponteiro qualquer (desde que n ao seja const e volatile) pode ser convertido para void*. Um ponteiro pode ser convertido em qualquer tipo integral que seja sucientemente grande para cont e-lo. Um ponteiro de um objeto de tamanho n pode ser convertido para ponteiro do objeto de tamanho m, se n > m. Sempre inicializar os ponteiros ( ptr = NULL; ). Sempre destruir os objetos alocados com new com delete. Um ponteiro para uma classe-derivada pode ser convertido em ponteiro para a classe-base. 3 Um ponteiro para um objeto B (de uma classe-base) pode ser convertido em ponteiro para o objeto D (de uma classe-derivada) se a convers ao for direta e n ao amb gua, e se B n ao e classe-base virtual. 3 Uma refer encia a uma classe pode ser convertida em uma refer encia a uma classe-base acess vel.
F.10
Neste ap endice aprendemos conceitos adicionais sobre ponteiros, como a soma e a subtra ca o de ponteiros. O uso do ponteiro void*, e de ponteiro para ponteiro. Como fazer para converter ponteiros. Exemplo de uso de auto_ptr. Como criar e usar um ponteiro de fun ca o, e ponteiros para m etodos e atributos da classe. Finalmente vimos o uso de ponteiros em hierarquias.
F.11
Exerc cios
1. Na se ca o F.1 apresentamos um exemplo. Transforme o mesmo em listagem, teste, e depois fa ca modica co es e aperfei coamentos. 2. Monte um exemplo com ponteiro void (se ca o F.2). 3. Monte um exemplo que utilize os conceitos apresentados na se ca o F.3. 4. Monte um exemplo com convers ao de ponteiros (se ca o F.4). 5. Modique a listagem F.3, acrescentando novas fun co es. 6. Modique a listagem F.6, acrescentando o uso de sizeof() para tipos padr oes da linguagem. (a) Ex: sizeof (int). 7. Na listagem F.2 acrescentar o construtor de c opia. 8. No exemplo de uso de <vector> din amico da STL, o construtor est a criando o objeto uma u nica vez (visto que s o e executado uma vez), mas est a deletando o objeto quatro vezes. Como proceder para corrigir este problema? Tente implementar na classe Tipo o construtor de c opia.
696
Ap endice G
G.1
Estruturas - struct
Vimos no Cap tulo 11 - Classes, a utiliza ca o de classes para criar o conceito de objeto com seus atributos e m etodos. A linguagem C utiliza a palavra-chave struct para criar entidades que s ao utilizadas para armazenar somente vari aveis (sem fun co es). Assim, uma estrutura permite reunir um conjunto de vari aveis, dentro de uma entidade u nica. Uma struct e um conjunto de vari aveis ou objetos reunidos. Os objetos que comp oem a struct podem ser de diferentes tipos. C++ estendeu as structs de C e estas podem ser utilizadas para incluir fun co es. A dica e utilizar a palavra chave struct apenas para reunir atributos (de acordo com sua deni ca o inicial) e deixar para as classes a reuni ao de atributos e m etodos.
G.1.1
O prot otipo para deni ca o de uma estrutura inicia-se com a palavra-chave struct e, a seguir, o nome da estrutura e o bloco com a deni ca o dos atributos que fazem parte da estrutura. N ao se esque ca do ponto e v rgula ap os o nal do bloco. Prot otipo: struct SNomeEstrutura { avel1; Tipo 1 vari avel2; Tipo 2 vari ... aveln; Tipo n vari }; 697
698
Depois de denida uma estrutura, o seu nome passa a ser um tipo do usu ario, ou seja, a estrutura pode ser utilizada da mesma forma que qualquer outro tipo de C++. Veja a seguir como criar e utilizar uma struct de C. Criando um objeto de uma estrutura Pode-se criar um objeto de uma estrutura do mesmo modo que se cria um objeto qualquer de C. Veja a seguir o prot otipo e um exemplo. Prot otipo: SNomeEstrutura nomeObjeto; // Cria um objeto SNomeEstrutura v[n]; // Pode-se criar um vetor de estruturas. Exemplo: SPonto { int x,y; } int main() { SPonto p1 = {}; // x = y = 0 SPonto p2 = {3, 2}; // x = 3; y = 2; } Acessando atributos de uma estrutura Para acessar um atributo de uma estrutura, utiliza-se o operador ponto (.) se esta for est atica, e o operador seta (->) se esta for din amica. Prot otipo: SNomeEstrutura nomeObjeto; nomeObjeto.atributo; Prot otipo: SNomeEstrutura* ptr; ptr = new SNomeEstrutura; ptr ->atributo; delete ptr; Reveja agora o exemplo da listagem 9.4.
G.1.2
Pode-se passar uma estrutura por c opia, por refer encia ou por ponteiro para uma fun ca o. Veja o exemplo. Exemplo: Tipo Fun c~ ao( SNomeEstrutura obj1); // Por c opia Tipo Fun c~ ao( SNomeEstrutura & obj2); // Por refer^ encia Tipo Fun c~ ao( SNomeEstrutura * obj2); // Por ponteiro Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
699
G.1.3
Estruturas aninhadas
Quando temos uma estrutura dentro de outra temos uma estrutura aninhada. Veja exemplo de uso de estruturas aninhadas na listagem G.1. Listing G.1: Usando estruturas aninhadas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # include < iostream > # include < string > using namespace std ; // Define uma e s t r u t u r a S P e s s o a struct SPessoa { public : string nome ; int idade ; // Define uma e s t r u t u r a a n i n h a d a // a e s t r u t u r a S F a m i l i a dentro de S P e s s o a struct SFamilia { string sobrenome ; int n u m e r o I r m a o s ; } SFamilia ; }; int main () { // Cria objeto do tipo Pessoa SPessoa Joao ; Joao . nome = " Jo~ ao " ; Joao . idade = 21; Joao . SFamilia . n u m e r o I r m a o s = 3; Joao . SFamilia . sobrenome = " da Silva " ; cout << Joao . nome << " " << Joao . SFamilia . sobrenome << " \ n " << Joao . idade << " anos " << endl << " tem " << Joao . SFamilia . n u m e r o I r m a o s << " irmaos " << endl ; return 0; } Jo~ a o da Silva 21 anos tem 3 irmaos
G.1.4
Uni oes e estruturas dentro de classes s ao sempre public. Inicialmente n ao era permitida a inclus ao de fun co es dentro da estrutura; hoje, uma struct aceita fun co es. Se quiser colocar fun co es dentro da estrutura, utilize classes. Uma struct X n ao pode conter uma inst ancia de si mesma (mas pode ter um ponteiro para X). Por default, os elementos de uma struct s ao p ublicos (public:); para classes, o default e privado (private:). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
700
O sizeof de uma estrutura pode ser maior que a soma do sizeof de seus elementos. Isto provoca pequenos desperd cios de mem oria, que podem ser reduzidos colocando-se no in cio da estrutura os objetos maiores e, a seguir, os menores (por ordem de tamanho). Veja se ca o 15.7. Ao contr ario de C++, em C uma estrutura n ao dene um tipo do usu ario. Para criarmos um objeto da estrutura usamos a palavra-chave typedef. Exemplo: struct SNome {int x}; SNome objeto_do_tipo_SNome; // C++ struct SNome objeto_do_tipo_SNome; // C
G.2
Uma uni ao (union) permite a um conjunto de objetos ocupar o mesmo local na mem oria. Observe que somente um objeto pode ser utilizado por vez. Uma uni ao pode ser considerada uma estrutura onde todos os objetos t em deslocamento zero e cujo tamanho e suciente para conter o seu maior membro. Ou seja, o espa co ocupado por uma union e correspondente ao do maior objeto denido. Depois de denida uma union, o seu nome passa a ser um tipo do usu ario. Como uma union pode armazenar objetos de diferentes tipos, ela n ao pode armazenar uma classe com construtor, com destruidor ou operador de c opia. O motivo e simples: se uma union tiver um int e um CPonto (listagem 13.5), quando a union sair de escopo, dever a destruir o objeto int ou o objeto CPonto?. Veja se co es 11.5.5 e 11.5.6. Uni oes n ao suportam heran ca, mas podem ter construtores. Segundo [Lischner, 2003], uma uni ao e semelhante a uma estrutura, mas com as seguintes restri co es. N ao deve ter uma classe-base, e n ao pode ser uma classe-base. N ao deve ter m etodos virtuais nem membros est aticos. Membros de dados n ao podem ser refer encias. Todos os seus membros de dados devem ser triviais (veja se c ao 11.5.6). As classes triviais descritas na se ca o 11.5.6, s ao importantes porque uni oes s o podem ter membros triviais.
G.2.1
Veja a seguir o prot otipo de uma union. Prot otipo: union UNomeUniao { Tipo1 v1; Tipo2 v2; Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
G.3. ENUMERAC OES - ENUM }; // Para criar um objeto da uni ao fa ca: UNomeUniao obj; // Para armazenar valores na uni ao: Tipo1 x; obj.v1 = x; // Para acessar os atributos da uni ao fa ca: Tipo1 y = obj.v1;
701
Veja a seguir exemplo de uso de uma union. Observe que a union armazena dois objetos, um int e um double. Logo, a union ter a o tamanho de um double. Exemplo: union UData { int x; double y; } UData obj1; obj1.x = 5; UData obj2; obj2.y = 5.0 + obj1.x ; Observe que podemos colocar dois objetos denidos pelo usu ario dentro de uma union, mas s o podemos utilizar um de cada vez. Em alguns casos, um objeto pode ter o mesmo objetivo geral, mas seria interessante poder ter dois nomes. No exemplo a seguir, dois objetos do tipo double s ao declarados dentro da importante union. Assim, podemos utilizar dois nomes para o mesmo endere co de mem oria. E lembrar que o mesmo tamb em pode ser feito com refer encias. Exemplo: union UPropriedade { double condut^ ancia; double raioHidraulico; }; Voc e pode criar uni oes sem um nome, pois deste modo as vari aveis denidas dentro da union podem ser acessadas diretamente, sem a utiliza ca o do ponto (.). A esta uni ao damos o nome de uni ao an onima. Obviamente, como os nomes denidos dentro dessa uni ao podem ser utilizados diretamente no escopo em que foram declarados, vari aveis com o mesmo nome causar ao ambig uidade.
G.3
Uma enumera ca o e uma seq u encia de valores que tem como objetivo enumerar algum processo. Uma enumera ca o e um tipo discreto, denido pelo usu ario e um tipo do usu ario. Os valores podem ser denidos pelo programador (como em seg=2) ou serem denidos automaticamente pelo sistema.
G.3.1
No prot otipo a seguir v1 , v2 , v3 ,..., vn , s ao os valores, ENome e o nome da enumera ca o. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
702 Prot otipo: enum ENome { v1, v2, v3,...,vn }; Veja no exemplo a seguir como declarar uma enumera ca o.
Exemplo: enum EDia { dom, seg, ter, qua, qui, sex, sab }; Onde EDia e o nome da enumera ca o e dom = 1, seg = 2, ter = 3, qua = 4, qui = 5, sex = 6, sab = 7, os valores da enumera ca o. Observe que os valores de cada elemento da enumera ca o s ao incrementados de 1. Veja no exemplo a seguir outros exemplos de enumera co es. Exemplo: enum ECor {r = 1 , g = 2 , b = 3 }; Exemplo: enum EResposta {nao = 0, sim = 1 , sei = 3 , nunca = 4};
talves = 2 , nao-
Veja no exemplo da listagem G.2 a cria ca o e uso de um objeto do tipo EDia com nome d. O programa pergunta que dia e hoje (n umero do m es e dia da semana). A seguir cria um objeto do tipo da enumera ca o e usa o mesmo para imprimir um calend ario para os pr oximos 30 dias. Listing G.2: Usando enumera co es: Um calend ario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # include < iostream > # include < string > # include < iomanip > using namespace std ; // Cria uma e n u m e r a c~ a o com o nome EDia enum EDia { dom =1 , seg , ter , qua , qui , sex , sab }; // Abaixo s o b r e c a r r e g a o o p e r a d o r ++ EDia & operator ++( EDia & d , int ) { if ( d == sab ) { d = dom ; return d ; } else { int x = static_cast < int >( d ); x ++; d = static_cast < EDia >( x ); return d ; } } int main () { cout << " Que dia do m^ es e hoje ( n u mero ): " ; int x ; cin >> x ; cin . get (); cout << " Que dia da semana e hoje ( dom =1 , seg =2 , ter =3 ,.. , sab =7): " ; int y ;
703
Voc e pode criar uma enumera ca o sem um nome, neste caso os atributos internos podem ser acessados diretamente. Veja listagem G.3. Listing G.3: Usando enumera ca o anonima.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 # include < iostream > using namespace std ; // C r i a n d o uma e n u m e r a c~ ao an^ onima enum { jan = 1 , fev , mar , abr , mai , jun , jul , ago , set , out , nov , dez }; int main () { for ( int i = 1; i <= 12; i ++) { cout << " \ nmes = " << i << " = " ; switch ( i ) { case jan : case fev : case mar : case abr : case mai : case jun : case jul : case ago : case set : case out : case nov : case dez :
cout cout cout cout cout cout cout cout cout cout cout cout
<< << << << << << << << << << << <<
" " " " " " " " " " " "
janeiro " ; fevereiro " ; mar co "; abril " ; maio " ; junho " ; julho " ; agosto " ; setembro " ; outubro " ; novembro " ; dezembo " ;
break ; break ; break ; break ; break ; break ; break ; break ; break ; break ; break ; break ;
704
27 28 29 30 31 }; } cout << endl ; return 0; } mes mes mes mes mes mes mes mes mes mes mes mes = = = = = = = = = = = = janeiro fevereiro mar co abril maio junho julho agosto setembro outubro novembro dezembo
G.3.2
Por default uma enumera ca o inicia-se com 0. Em opera co es aritm eticas, os elementos de uma enumera ca o s ao convertidos automaticamente para int. Mas um inteiro n ao e automaticamente convertido para enumera ca o, neste caso precisamos usar um static_cast<> (veja se ca o 25.6). Os elementos de uma enumera ca o (ex.: {dom = 1, seg, ter, qua, qui, sex, sab}) s ao constantes e n ao podem ser alterados. Uma enumera ca o e um tipo u nico, um tipo do usu ario, e pode ser utilizada para criar objetos do tipo da enumera ca o, o que inclui atributos est aticos. Veja o exemplo. Exemplo: class T { public: enum EColor { black = 0, white = 1 }; static EColor sc; }; T::Ecolor T::sc = white; int main() { T::EColor c; ... return 0; } Uma enumera ca o permite sobrecarga de operador. Voc e pode usar enumera co es para armazenar n umeros inteiros, mas lembre-se, voc e n ao pode obter o endere co de uma enumera ca o. Uma enumera ca o declarada dentro de uma classe, coloca os membros da enumera ca o no escopo da classe. Veja exemplo a seguir. Note que podemos declarar a enumera ca o dentro da classe Base, podemos declarar e denir o valor de um objeto ECor est atico dentro da classe Botao, ou somente declarar dentro de Dialogo e denir posteriormente. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
G.4. RESUMO DO CAP ITULO Exemplo: class Base { public: enum ECor {preto, branco, vermelho, verde, azul}; }; class Botao : public Base { const ECor cor = verde; }; class Dialogo : public Base { static const ECor cor ; }; Base::ECor Dialogo::cor = Base::azul;
705
G.4
Neste ap endice aprendemos em mais detalhes como usar as estruturas de C. Aprendemos que uma struct e um conjunto de vari aveis ou objetos reunidos. Falamos que embora C++ atual permita que uma estrutura tenha m etodos, devemos incluir m etodos apenas nas classes. Ou seja, as estruturas devem ter apenas atributos (dados/vari aveis). Vimos que as uni oes podem ser utilizadas da mesma forma que as estruturas, mas que somente uma vari avel deve ser utilizada por vez. Aprendemos que o espa co de mem oria ocupado pela estrutura e o do seu maior objeto. Finalmente, aprendemos que uma enumera ca o e uma seq u encia de valores que tem como objetivo enumerar algum processo.
G.5
Exerc cios
1. O exemplo da listagem G.2 tem problemas. O aluno deve tentar corrigir os problemas. Por exemplo, acrescentar verica ca o do nal do mes 30 ou 31 dias? Melhorar a l ogica do algoritmo. 2. Para os exerc cios que zemos anteriormente, classes CPonto, CCirculo, CElipse, CAluno, CFuncion ario, etc, verique se o sizeof() da classe e igual a soma do sizeof() dos seus atributos.
706
Ap endice H
H.1
Um vetor ou array no estilo de C e um bloco de mem oria alocado para armazenamento de objetos cont guos e do mesmo Tipo. O tamanho (ou size) de um array deve ser conhecido em tempo de compila ca o. Veja a seguir o prot otipo para criar arrays no estilo de C. Prot otipo: // Unidimensional Tipo nome [ dimens ao ] ; // Bidimensional Tipo nome [ dimens ao1 ] [ dimens ao2 ] ; // Tridimensional Tipo nome [ dimens ao1 ] [ dimens ao2 ] [ dimens ao3 ] ; // Ndimensional Tipo nome [ dimens ao1 ] [ dimens ao2 ] [ dimens ao3 ] ... [dimens aoN];
H.2
No exemplo a seguir criamos um vetor unidimensional com 10 elementos. Observe que os valores do vetor s ao indenidos. Exemplo: int v0[10] ; Se o array for est atico, todos os valores s ao inicializados com 0. No exemplo a seguir criamos um vetor unidimensional est atico com 5 elementos iguais a 0. 707
No exemplo abaixo, criamos um vetor unidimensional v2 com 4 elementos. A seguir inicializamos seus valores um a um. Exemplo: int v2[4]; v2[0] = 11, v2[1] = 22, v2[2] = 0, v2[3] = 0.0; No exemplo abaixo criamos os vetores v3 e v4. Os mesmos s ao inicializados na cria ca o usando {}. Exemplo: int v3[5] int v4[4] = { 11, 22, 33, 44, 55 }; = { 11, 22 };
A dimens ao do array pode ser omitida se o compilador puder calcular a dimens ao. No exemplo a seguir o vetor v5 vai ter 3 elementos, isto e, v5[0] = 0, v5[1] = 11, v5[2] = 22. Exemplo: int v5[] = { 0, 11, 22 }; Podemos inicilizar todos os elementos com zero. Exemplo: int v6[5] = { };
H.3
Um array ndimensional tamb em pode ser criado, no exemplo a seguir criamos um array bidimensional. Observe a forma como podemos criar a matriz identidade. Exemplo: int matriz[4][3] = { {0,1,2} {3,4,5} {6,7,8} {9,10,11} }; int imagem[4][3] = { { 0, 1, 2 } { 3, 4, 5 } { 6, 7, 8 } { 9,10,11 } }; int matrizIdentidade3x3[3][3] = { {1} {0,1} {0,0,1} };
H.4
O programa da listagem H.1 realiza a binariza ca o de imagens, isto e, a convers ao de imagens em tons de cinza em imagens bin arias. O mesmo usa arrays (vetores e matrizes) com aloca ca o din amica e enumera co es. A sa da do programa e ilustrada nas imagens da Figura H.1. Em (a) a imagem de origem em tons de cinza, em (c) o gr aco do histograma de n veis de cinza e em (b) a imagem binarizada. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
709
Como pr e-requisitos o programa precisa do arquivo "pstream.h" dispon vel no endere co http://pstreams.sourceforge.net/ e anexado nas listagens do livro. O mesmo e utilizado em nosso programa para obter acesso direto ao programa gnuplot utilizando streans. Um objeto opstream esta no namespace redi. Um objeto redi::opstream e usado para enviar sequ encias de comandos para programas externos. O programa usa ainda o programa externo display para visualizar as imagens. Os programas gnuplot e display est ao dispon veis na maioria das distribui co es GNU/Linux. Como o programa trabalha com imagens, selecionamos os formatos .pgm (para imagens em tons de cinza) e .pbm (para imagens em preto e branco). Estes formatos trabalham com dados em ASCII. Veja a seguir como s ao os formato .pgm e .pbm.
// Formato dos arquivos PBM ( Nome . pbm ) P1 ny nx dados // Formato dos arquivos PGM ( Nome . pgm ) P2 ny nx nCores dados
Um arquivo .pgm pode ser gerado usando o programa import ou o programa convert (ambos programas de terminal). O programa import e usado para capturar uma tela (exemplo: abra um terminal e digite: import nomeImagem.pgm , a seguir selecione a regi ao da imagem a ser capturada), o programa convert e usado para converter arquivos de imagens (exemplo: convert nomeImagem.jpg nomeImagem.pgm ). Inclui nas listagens do livro a imagem imagemExterna.pgm. Os arquivos de imagens (incluindo o formato .pgm e .pbm) podem ser visualizados com o programa display ou outro visualizador qualquer. Denidos os pr e-requisitos e o Tipo do arquivo de imagem, vamos a descri ca o do programa. O programa inicia solicitando o nome da imagem a ser aberta, no formato pgm, um formato ASCII f acil de manipular. L e os dados de cabe calho do arquivo de disco, como formato e dimens oes da imagem. A seguir aloca dinamicamente uma imagem 2D e seta seus valores com os dados do arquivo de disco. Para mostrar a imagem usa-se o programa display, acessado diretamente utilizando-se a fun ca o system("nomeDoComando"); Um vetor histograma e criado e zerado. O histograma e calculado em um for duplo, que varre toda imagem e para cada p xel da imagem acumula seu valor no histograma. O gr aco do histograma e mostrado usando-se o programa externo gnuplot. A seguir o programa solicita ao usu ario o valor de corte (n vel de cinza) e realiza a binariza ca o. A imagem binarizada e salva em disco. A fun ca o Write() e usada para salvar a imagem em disco. A mesma recebe o nome da imagem, um ponteiro para imagem, suas dimens oes, al em do formato da imagem. O formato pode ser PBM ou PGM, conforme denido na enumera ca o. A fun ca o AlocaMatriz2D() e usada para alocar dinamicamente uma matriz com duas dimens oes. DesalocaMatriz2D() e usada para desalocar a matriz. Listing H.1: Usando arrays: Um programa de binariza ca o.
1 2 3 4 5 6 # include < string > # include < fstream > # include < iostream > # include < cstdlib > # include " pstream . h " using namespace std ;
710
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
// Cria e n u m e r a c~ ao enum { PBM , // = 1 PGM // = 2 }; // Salva imagem em disco bool Write ( string nomeImagem , int ** imagem , int nx , int ny , int formato = PGM ); // Aloca d i n a m i c a m e n t e m a t r i z 2 D int ** A l o c a M a t r i z 2 D ( int nx , int ny ); // D e s a l o c a d i n a m i c a m e n t e matriz 2 D bool D e s a l o c a M a t r i z 2 D ( int **& dat , int nx , int ny ); int main ( int argc , char * argv []) { int nx = 680; int ny = 480; int nCores = 256; int ** imagem = NULL ; string formato ; string nomeImagem ; cout << " Entre com o nome do arquivo de disco com a imagem ( formato pbm ou pgm ): " ; getline ( cin , nomeImagem ); // L^ e dados do a r q u i v o de disco ( formato , nx , ny , nCores ) // c_str () c o n v e r t e string de C ++ para C ifstream fin ( nomeImagem . c_str () ); if ( fin . fail ()) { cerr << " Falha abertura arquivo : " ; exit (0); } fin >> formato ; // P1 ou P2 fin >> nx ; fin >> ny ; if ( formato == " P2 " ) // PGM fin >> nCores ; imagem = A l o c a M a t r i z 2 D ( nx , ny ); // Aloca a matriz imagem // L^ e os dados da imagem do a r q u i v o de disco for ( int i = 0 ; i < nx ; i ++ ) for ( int j = 0 ; j < ny ; j ++ ) fin >> imagem [ i ][ j ]; // E x e c u t a c o m a n d o que mostra a imagem usando o p r o g r a m a d i s p l a y string comando = " display " + nomeImagem + " & " ; system ( comando . c_str ()); // e x e c u t a c o m a n d o do shell // Cria h i s t o g r a m a int * vhistogra ma = NULL ; vhistogra m a = new int [ nCores ]; if ( vhistogra ma == NULL ) { cerr << " Falha aloca ca ~ o histograma : " ; exit (0); } // Zera o h i s t o g r a m a for ( int i = 0; i < nCores ; i ++ )
711
"
// Salva imagem b i n a r i z a d a Write ( string ( " i m a g e m E x t e r n a B i n a r i z a d a " ) , imagem , system ( " display i m a g e m E x t e r n a B i n a r i z a d a . pbm & " ); return 0; }
nx ,
ny , PBM );
// Salva imagem em disco bool Write ( string nomeImagem , int ** imagem , int nx , int ny , int formato ) { ofstream fout ; switch ( formato ) { case PGM : // Salva imagem no f o r m a t o pgm fout . open ( ( nomeImagem + " . pgm " ). c_str () ); if ( fout . fail ()) return 0; fout << " P2 " << endl ; fout << nx << " " << ny << " " << sizeof ( int ) << endl ; break ; case PBM : // Salva imagem no f o r m a t o pbm fout . open ( ( nomeImagem + " . pbm " ). c_str () );
712
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
// Salva dados de cor em disco for ( int i = 0 ; i < nx ; i ++) { for ( int j = 0; j < ny ; j ++ ) fout << imagem [ i ][ j ] << ; fout << endl ; } fout . close (); return 1; } // Aloca d i n a m i c a m e n t e m a t r i z 2 D int ** A l o c a M a t r i z 2 D ( int nx , int ny ) { int i ; // int ** dat = NULL ; // Cria p o n t e i r o nulo dat = new int *[ nx ]; // Passo 1: aloca eixo x if ( dat ) // se alocou dat c o r r e t a m e n t e { for ( i = 0; i < nx ; i ++) // zera todos os p o n t e i r o s dat [ i ] dat [ i ] = NULL ; // porque se a a l o c a c a o der errado for ( i = 0; i < nx ; i ++) // vai chamar d e s a l o c a { dat [ i ] = new int [ ny ]; // Passo 2: aloca linhas y if ( dat [ i ] == NULL ) // Se a linha nao foi a l o c a d a { // chama D e s a l o c a Para evitar D e s a l o c a M a t r i z 2 D ( dat , nx , ny ); // v a z a m e n t o de m e m o r i a return 0; } } // O que nao foi a l o c a d o esta com NULL e return dat ; // pode ser d e l e t a d o } } // D e s a l o c a d i n a m i c a m e n t e matriz 2 D bool D e s a l o c a M a t r i z 2 D ( int **& dat , int nx , int ny ) { if ( dat != NULL ) { for ( int i = 0; i < nx ; i ++) if ( dat [ i ]) delete [] dat [ i ]; // Passo 1: apaga linhas y delete [] dat ; dat = NULL ; return 1; } return 0; } // Passo 2: apaga eixo x
Veja na Figura H.1 as sa das geradas pelo programa de binariza ca o da listagem H.1. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
713
H.5
Neste cap tulo aprendemos a criar e usar vetores e matrizes - arrays - no estilo de C. Embora C++ apresente o container <vector> (apresentado no Cap tulo 32 - Os Containers Sequ enciais <vector>, <list>, <deque>), e as diversas fun co es gen ericas (vistas no Cap tulo 35 - Programa ca o Gen erica) o uso de vetores e matrizes no estilo de C se justica em fun ca o da necessidade de maior performance. Adicionalmente, aprender a usar vetores e matrizes no estilo de C se justica em fun ca o da necessidade de se adaptar c odigos legados - c odigos antigos - utilizados em diversos programas de engenharia. O Cap tulo ?? - A biblioteca Blitz++, apresenta a biblioteca de matrizes Blitz++, a mesma alia caracter sticas de boa performance e facilidade de uso.
H.6
Exerc cios
1. Mude o programa da listagem H.1 de forma que o nome da imagem possa ser passado atrav es da linha de comando (veja se ca o E.1).
3. Crie uma m ascara (uma matriz 3x3), dena seus valores como sendo 1. Crie uma imagem do tamanho da imagem original, zerada. A seguir percorra toda imagem e aplique um ltro de passa-baixa sobre a imagem. Isto e, algo parecido com:
Exemplo: int masc[3][3]={{1,1,1}{1,1,1}{1,1,1}}; for i // Varre a imagem for j. for k // Varre a m ascara for l imagemFiltrada[i][j] += imagem[i][j]*masc[k][l];
Nota: o c odigo da listagem acima esta incorreto, e parte do trabalho do aluno montar o algoritmo correto para aplicar o ltro. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
714
Ap endice I
Gloss ario
Abstra c ao: processo de criar uma superclasse pela extra ca o de qualidades comuns ou caracter sticas gerais de uma ou mais classes ou objetos espec cos. A c ao: usada em modelagem din amica, se refere a opera ca o instant anea associada a um evento. Agente: veja objeto ativo. Agrega c ao: forma especial de associa ca o entre o todo e suas partes, no qual o todo e composto de partes. Agregado xo: quando o n umero de partes e denido. Agregado recursivo: quando o objeto pode conter a si pr oprio. Agregado vari avel: quando o n umero de partes e indenido. Algoritmo: conjunto de etapas ordenadas de forma espec ca, utilizadas para solucionar um problema, tal como uma f ormula matem atica ou uma s erie de instru co es de um programa. Ambiente de janelas: interface gr aca com janelas m ultiplas na tela de um computador. Ambiente windows: veja ambiente de janelas. Amigo: classes amigas permitem o compartilhamento de m etodos e atributos. An alise orientada a objeto: an alise dos requisitos de um sistema em termos de objetos reais. Realizada sem considerar os requisitos de implementa ca o. Ancestral imediato: aquele que e identicado na declara ca o do objeto. Arquitetura: estrutura geral de um sistema, incluindo a sua divis ao em subsistemas e suas aloca co es para tarefas e processadores. Assinatura: para um atributo, o tipo do atributo, para uma opera ca o (m etodo ou fun ca o), o nome da opera ca o, seus par ametros e o tipo de retorno. Associa c ao derivada: denida em termos de outras associa co es. Associa c ao qualicada: associa ca o que relaciona duas classes e um qualicador. Associa c ao tern aria: associa ca o entre tr es classes. 715
716 Associa c ao: relacionamento entre duas ou mais classes descrevendo um grupo de liga co es com estruturas e sem anticas comuns. Atividade (em modelagem din amica): opera ca o que leva tempo para terminar. Est a relacionada a estados e representa acontecimentos do mundo real. Atributo de classe: atributo que existe na classe e n ao nos objetos. Todos os objetos da classe t em acesso ao atributo de classe, mas este eu nico. Ator: objeto ativo que pode gerar eventos. Atributo: uma propriedade ou caracter stica de um objeto. Atributo de evento: dados transportados por um evento. Atributo de associa c ao: atributo que existe em fun ca o de uma associa ca o entre dois objetos. Atributo derivado: atributo que e calculado a partir de outros atributos. Banco de dados: uma cole ca o de dados armazenados e gerenciados eletronicamente. Biblioteca de classes: uma cole ca o de classes gen ericas que podem ser adaptadas para uma aplica ca o particular. Caixa-preta: met afora utilizada em engenharia para descrever um dispositivo em que os componentes internos s ao desconhecidos pelo usu ario. Os objetos s ao como caixas-pretas em que seus funcionamentos internos cam ocultos aos usu arios e programadores. Cancelar: denir um m etodo em uma classe-derivada que substitui o m etodo ancestral. Caracter stica: e uma palavra gen erica para atributos e m etodos. Cen ario (em modelagem din amica): seq u encia de eventos que ocorre durante uma determinada execu ca o do sistema. Classes: sin onimo de tipos de objeto (f abrica de objetos). Classe abstrata: classe que n ao pode gerar objetos. Classe concreta: classe que pode gerar objetos. Classe-base: classe que tem classes herdeiras (tem uma ou mais classes lhas). Classe-derivada: classe herdeira (tem um ou mais pais). Classe-lho: o mesmo que classe-derivada. Classe-pai: o mesmo que classe-base. CORBA: Common Object Request Broker Arquiteture. CREW: Concurrent Read, Exclusive Write. CRCW: Concurrent Read, Concurrent Write. C odigo aberto: express ao utilizada para indicar que voc e pode ver o c odigo-fonte do programa. Entretanto, nada pode ser dito a respeito das condi co es sob as quais o c odigofonte se encontra. Existem programas de c odigo aberto que n ao s ao livres, pois o usu ario, dependendo da licen ca, pode ser proibido de alterar e publicar o c odigo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
717 C odigo reentrante: c odigo usado em bibliotecas compartilhadas. O mesmo c odigo pode ser usado por diferentes programas ao mesmo tempo (n ao usa internamente vari aveis est aticas). Coer encia: propriedade de uma entidade, como uma classe, uma opera ca o ou m odulo, tal que ela se organize em um plano consistente e todas as suas partes se ajustem no sentido de um objetivo comum. Cole c ao de lixo: rotina de gerenciamento de mem oria que pesquisa a mem oria por segmentos de programa, dados ou objetos que n ao se encontram mais ativos, e recupera o espa co n ao utilizado. Compilador: programa que traduz uma linguagem de programa ca o para a linguagem de m aquina. Concorr encia: a capacidade de programas orientados a objeto de se comunicarem em multitarefa. Concorrente: duas ou mais tarefas, atividades ou eventos cujas execu co es podem se sobrep or no tempo. Condi c ao: usada em modelagem din amica, se refere a fun ca o booleana de valores de objetos v alidos durante um intervalo de tempo. Construtor: m etodo especial que e utilizado para inicializar todos os atributos de um objeto. Consulta: e uma opera ca o (m etodo) que, quando executada n ao altera o objeto. Dados persistentes: dados que continuam existindo mesmo ap os encerrada a execu ca o de um programa. Debuger: programa que permite ao usu ario corrigir erros de software por interm edio do exame e altera ca o do conte udo da mem oria, e iniciar ou parar a execu ca o em um local predeterminado ou breakpoint. Serve para localizar e alterar erros de l ogica de um programa ou para corre co es em um programa. Depurador: veja Debuger. Delega c ao: mecanismo de implementa ca o no qual um objeto, em resposta a uma opera ca o nele pr oprio, repassa a opera ca o para outro objeto. Projeto orientado a objeto: tradu ca o da estrutura l ogica de um sistema em uma estrutura f sica composta de objetos de software. Destrutor: libera os objetos dinamicamente alocados e destr oi o objeto. Podem ser expl citos ou impl citos; se expl citos (declarados), podem liberar outros tipos de dados e realizar outras fun co es. Diagrama de seq u encia: diagrama que mostra o remetente e o receptor (eventos e mensagens). Diagrama de atividade: diagrama que mostra o movimento de dados e seu processamento manual ou por computador. Diagrama de objetos: representa ca o gr aca de objetos mostrando os relacionamentos, atributos e opera co es. Diagrama que mostra o relacionamento de objetos entre si. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
718 Dicion ario de dados: par agrafo que descreve uma classe, seus atributos, m etodos e associac o es. Discord ancia de nome: conito que pode ocorrer em hereditariedade m ultipla quando o mesmo m etodo ou atributo de inst ancia for herdado de m ultiplas classes. DCS: Decomposition, communication, and synchrinization. Encapsulamento: casamento do c odigo com os dados dentro de uma unidade de objeto. Isto representa a modularidade aplicada aos dados. O encapsulamento torna invis veis os dados para o usu ario, embora os m etodos permane cam vis veis. Escala: o relacionamento entre tr es elementos e chamado escala. Escalabilidade: possibilidade de alterar as congura co es do sistema de acordo com as necessidades. Especializa c ao: a cria ca o de classes-derivadas (subclasses) a partir de uma classe-base (ou superclasse) por meio do renamento da classe-base. EREW: Exclusive Read, Exclusive Write. ERCW: Exclusive Read, Concurrent Write. Estado: valores dos atributos e liga co es de um objeto em um determinado momento. Evento: usado em modelagem din amica, se refere a algo que acontece instantaneamente. Expansibilidade: expandir um programa sem ter em m aos o c odigo-fonte. Extens ao (em generaliza ca o): o acr escimo de novas caracter sticas por meio de uma subclasse. Extensibilidade: habilidade de um programa ou sistema em ser facilmente alterado para que possa tratar novas classes de entrada. Folha: mecanismo de subdivis ao de um modelo de objetos em uma s erie de p aginas. Framework: uma biblioteca de classe anadaespecialmente para uma determinada categoria de aplica ca o. M etodo virtual: m etodo especial chamado por interm edio de uma refer encia de classe b asica ou indicador, carregado dinamicamente em tempo de execu ca o. GNU: acr onimo para GNU n ao e Unix. GNU e o nome de um sistema operacional completo e compat vel com Unix escrito a partir de 1983, por Richard Stallman e in umeros hackers da comunidade de software livre espalhados pela Internet. O GNU e um sistema totalmente livre, ou seja, ele fornece as quatro liberdades b asicas do software livre: a liberdade de uso, modica ca o, c opia e publica ca o de vers oes modicadas. Atualmente o sistema GNU e largamente utilizado, especialmente na sua variante GNU/Linux. GNU/Linux: sistema operacional GNU totalmente livre que utiliza o Linux como kernel. GNU/Linux e a variante mais conhecida do sistema GNU. O sistema GNU original ` as vezes e referenciado como GNU/Hurd para maior clareza. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
719 GPL: licen ca de software livre mais utilizada no mundo. Caracteriza-se por ser uma licen ca com Copy-left, ou seja, qualquer trabalho derivado de qualquer parte de um software livre licenciado sob GPL obrigatoriamente deve permanecer livre. A GPL pode ser obtida em http://www.gnu.org/licenses/gpl.html. Gerenciamento de mem oria: a maneira pela qual o computador trata a sua mem oria. Inclui prote ca o de mem oria e quaisquer outras t ecnicas de mem oria virtual. Gr acos orientados a objeto: programas que t em a fun ca o de desenhar e que s ao apresentados ao usu ario sob a forma de objetos na tela. Heran ca: a propriedade de todos os tipos de objetos que permite a um tipo ser denido como herdando todas os atributos e m etodos contidos no pai. Handle: vari avel utilizada pelo sistema operacional para identicar um objeto. Heran ca m ultipla: permite a um objeto herdar m etodos e atributos de mais de um pai. Heran ca repetida: quando um objeto e descendente de outro por mais de um caminho. Hereditariedade: mecanismo usado para compartilhar m etodos e tipos de dados automaticamente entre classes, subclasses e objetos. N ao e encontrado em sistemas de procedures. Permite programar apenas as diferen cas de classes previamente denidas. Hierarquia: descri ca o de um sistema que conta com uma estrutura constru da em n veis diferentes. Os n veis mais altos controlam os mais baixos. Hierarquia de objetos (estrutura): diagrama que mostra o relacionamento dos objetos. Icone: representa ca o gr aca de um objeto. Identidade do objeto: algo sobre o objeto que permanece invari avel entre todas as possibilidades de modica ca o de seu estado. Pode ser usado para indicar um objeto. Informa c ao escondida/oculta: recurso de programa ca o pelo qual a informa ca o dentro de um m odulo permanece privada a ele. Estrat egia de design que visa a maximizar a modularidade ocultando o maior n umero poss vel de informa co es dentro dos componentes de um design. Inst ancia: objeto que faz parte de uma classe. Instancia c ao: processo de cria ca o de inst ancias a partir de classes. Invariante: declara ca o sobre alguma condi ca o ou relacionamento que deve ser sempre verdadeiro. Janela: area de visualiza ca o separada em uma tela de exibi ca o fornecida pelo software. Os ambientes gr acos dos sistemas operacionais podem mostrar janelas m ultiplas na tela, permitindo que o usu ario mantenha v arios programas aplicativos ativados e vis veis ao mesmo tempo. Os programas aplicativos individuais tamb em contam com janelas m ultiplas, oferecendo capacidade de visualiza ca o para mais de um documento, planilha ou arquivo de dados. Kernel : parte fundamental de um programa como um sistema operacional, residente todo o tempo em mem oria. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
720 Largura de banda: n umero de canos por onde os dados uem. Quanto maior a largura de banda, maior a velocidade com que os dados uem do processador para a mem oria e para os dispositivos (placa de rede, monitor). Lat encia: tempo perdido com a comunica ca o entre os diversos dispositivos. Linux: clone livre do kernel do Unix, escrito a partir do zero por Linus Torvalds, com a ajuda de um grupo de programadores espalhado pela Internet. Ele objetiva estar em conformidade com o POSIX e com a Single Unix Specication. Ap os mostrar-se mais est avel e simples que o HURD (kernel original do GNU), o Linux foi inclu do no sistema GNU tornando-o pronto para conquistar o mercado com a variante GNU/Linux. Liga c ao: processo de organizar um programa para solucionar todas as conex oes entre seus componentes. Estaticamente, as liga co es s ao denidas na compila ca o. Dinamicamente, a liga ca o ocorre quando o programa est a rodando. Liga c ao a posteriori (din amica): um m etodo que permite chamar outros m etodos cujo endere co n ao e conhecido em tempo de compila ca o/linkedi ca o. O endere co s o e conhecido durante a execu ca o. Liga c ao a priori/anterior: m etodo tradicional de compila ca o pelo qual os endere cos dos m etodos e fun co es s ao determinados na etapa de linkagem. Liga c ao est atica: veja liga ca o a priori. Linguagem concorrente: linguagem que permite a execu ca o simult anea de objetos m ultiplos, geralmente com arquitetura de hardware paralela. Linguagem n ao procedural: linguagem de programa ca o que gera a l ogica para o programa diretamente a partir da descri ca o do problema pelo usu ario, em vez de um conjunto de procedures baseadas em l ogica de programa ca o tradicional. Linguagem orientada a objeto: linguagem de computador que suporta objetos, classes, m etodos, mensagens e hereditariedade. As caracter sticas secund arias podem incluir hereditariedade m ultipla, liga ca o din amica e polimorsmo. Linguagem procedural: linguagem de programa ca o como COBOL, FORTRAN, BASIC, C e Pascal, baseada na utiliza ca o de ordem particular de a co es e que tem conhecimento das opera co es de processamento de dados e t ecnicas de programa ca o. Manuten c ao: capacidade de um programa ou sistema para transformar reparos de bugs e aumentar a funcionalidade a m de satisfazer ` as necessidades do usu ario. MIMD: Multiple Instruction Stream, Multiple Data Stream. Cada processador atua de forma independente. Implementado utilizando cluster. Mem oria compartilhada: em m aquinas com mais de um processador - SMP, a mem oria costuma ser compartilhada (os processadores podem acessar a mesma mem oria). Multitasking: o conceito de multitasking gerenciado pelo sistemas operacional (ex: GNU/Linux), possibilitando que m ultiplas tarefas sejam executadas simultaneamente atrav es da divis ao do tempo do(s) processador (es). Se voc e tem n tarefas em um sistema o ideal e ter n processadores no mesmo sistema ou utilizar um cluster que lhe ofere ca n processadores. O Sistema operacional controla a troca dos processos dando a cada um deles uma por ca o de tempo. Quando o tempo do processo encerra, o SO salva os dados do processo que esta sendo executado e passa a execu ca o para o pr oximo processo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
721 Multi tasking operating system: sistema operacional que roda mais de uma tarefa de cada vez. Cada tarefa utiliza o processador por um determinado tempo. Multi tasking operating system em sistemas multiprocessados: o sistema operacional e multitarefa e o computador tem mais de um processador. Ex.: Sun-Solaris rodando em uma esta ca o de trabalho SUN-Enterprise E450. Multisession: um sistema operacional multisession admite que mais de um usu ario esteja logado, rodando mais de uma se ca o (ex: GNU/Linux). Multiprocessing: um sistema operacional que possibilita a execu ca o de mais de um processo por se ca o. Multithreading: um sistema operacional que possibilita que um processo tenha mais de uma thread. Mensagem: solicita ca o enviada a um objeto para alterar seu estado ou retornar um valor. A mesma mensagem pode ser enviada para objetos diferentes porque eles simplesmente informam a um objeto o que fazer. Os m etodos denidos dentro de um objeto receptor determinam como ser a executada a solicita ca o. Veja m etodo/polimorsmo. Metaclasse: classe que descreve outras classes. Metadados: s ao dados que descrevem outros dados. Por exemplo, uma deni ca o de uma classe. M etodo: um m etodo e uma fun ca o que e denida como pertencendo a um tipo de objeto. Implementa a resposta quando uma mensagem e enviada a um objeto. Os m etodos determinam como um objeto responder a a uma mensagem. Veja mensagens. M etodo de implementa c ao (estilo): m etodo que realiza o processamento de dados sem realizar qualquer tomada de decis oes. M etodo est atico: implementado usando a liga ca o a priori. M etodo pol tico: m etodo que realiza o processamento de tomadas de decis oes. N ao realiza processamento de dados. M etodo virtual: implementado usando a liga ca o a posteriori. Metodologia: em engenharia de software, e o processo de produ ca o organizada de um programa, utilizando t ecnicas e conven co es conhecidas. Movimento pelo software livre: movimento surgido na d ecada de 1970 em conseq u encia da crescente press ao recebida para a ado ca o de softwares propriet arios e assinaturas de tratados de n ao-divulga ca o. O movimento intensicou-se a partir da d ecada de 1980 com o projeto GNU que libertava os usu arios dos sistemas UNIX propriet arios. O GNU consolidou-se na d ecada de 1990 como um sistema completo e funcional, atingindo uma qualidade t ecnica compar avel aos melhores sistemas operacionais propriet arios. Modelo funcional: descri ca o dos aspectos de um sistema que transforma valores utilizando fun co es, mapeamentos, restri co es e depend encias funcionais. Modularidade: a constru ca o de um programa em m odulos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
722 Multiplicidade: n umero de inst ancias de uma classe que podem relacionar-se a uma u nica inst ancia de outra classe. MPP: massive parallel processing (um computador com v arios processadores). Objeto: elemento prim ario em um programa orientado a objeto. Objetos s ao entidades que encapsulam dentro de si pr oprios os dados que descrevem o objeto e as instru co es para operar esses dados. Objeto ativo: um objeto que monitora eventos ocorrendo em uma aplica ca o e assume a a ca o ` vezes chamado de agente. por si pr oprio. As Objeto passivo: objeto que atua somente por solicita ca o. Objeto polim orco: o descendente herda a forma do ancestral (m etodos), mas pode redenir os m etodos assumindo outras formas (polimorsmo). Open source initiative: grupo desmembrado do movimento pelo software livre em 1998, que rejeita a luta pela liberdade no uso do software. Seu objetivo e disseminar a id eia de que c odigo-fonte dispon vel e com modica ca o permitida gera melhores programas. Apesar de n ao endossar o esp rito de liberdade, esse grupo costuma recomendar o uso da licen ca GPL. Opera c ao abstrata: opera ca o declarada, mas n ao implementada. Opera c ao de classe: opera ca o que e realizada pela classe e n ao pelas inst ancias desta. S o pode manipular os atributos de classe. Opera c ao: fun ca o ou m etodo que pode ser aplicado por um objeto. Orientado por objeto: termo para pr atica de programa ca o ou compiladores que agrupam elementos individuais de programa ca o em hierarquias de classes, permitindo que objetos do programa compartilhem o acesso a dados e procedimentos sem redeni ca o. POSIX: Portable Operation System Interface - IEEE-STD 1003.1-2001. Pai-lho: maneira de expressar a rela ca o entre classes e subclasses. As classes-lho ou subclasses herdam os m etodos e atributos de inst ancia da classe-pai. Por meio da hereditariedade m ultipla, um lho pode ter diversos pais. Papel: uma extremidade de uma associa ca o. Paradigma: Extra do de http://pt.wikipedia.org/wiki/Paradigma. Paradigma e a repre um pressuposto los senta ca o do padr ao de modelos a serem seguidos. E oco matriz, ou seja, uma teoria, um conhecimento que origina o estudo de um campo cient co; uma realiza ca o cient ca com m etodos e valores que s ao concebidos como modelo; uma refer encia inicial como base de modelo para estudos e pesquisas. Na losoa grega, paradigma era considerado a u encia de um pensamento, pois atrav es de v arios pensamentos do mesmo assunto e que se concluia a id eia, seja ela intelectual ou material, depois dela realizada surgiam outras id eias at e chegar a uma conclus ao nal. Paradigmas h bridos: linguagens h bridas como o C++, que fazem uso de t ecnicas de programa ca o OOP e estruturada. Pilha: a rvore bin aria completa em que os nodos cont em chaves de pesquisa organizadas em ordem descendente. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
723 Polimorsmo: propriedade de compartilhar uma a ca o simples. Cada classe-derivada implementa os m etodos de forma apropriada as suas necessidades. Habilidade de a mesma mensagem ser interpretada de maneiras diferentes quando recebida por objetos diferentes. Por exemplo, a impress ao de uma mensagem, quando enviada a uma gura ou diagrama, aciona um m etodo ou implementa ca o diferente daquele que a mesma mensagem de impress ao envia a um documento. Pr e-processador: programa de software que executa procedimentos preliminares na entrada de dados antes da execu ca o do programa principal. Por exemplo, o c odigo-fonte C++ e comumente pr e-processado e traduzido para o c odigo-fonte C antes de ser compilado. Privado: os m etodos e atributos pertencentes a uma classe s ao privados por default. Os elementos privados s o podem ser acessados por m etodos que perten cam ` a classe, desde que esta n ao seja descendente (s o acessado pela classe). Processamento distribu do: sistema de computadores ligados por uma rede de comunica co es com cada sistema gerenciando sua pr opria carga local e a rede suportando o sistema como um todo. Processo: alguma coisa que transforma valores de dados. Programa: conjunto de instru co es que informam ao computador o que fazer. Um programa e escrito em uma linguagem de programa ca o e e convertido em linguagem de m aquina por meio de softwares chamados montadores e compiladores. Programa c ao estruturada: losoa de programa ca o voltada ao gerenciamento de complexidade por meio da formaliza ca o e padroniza ca o da metodologia de programa ca o. A programa ca o estruturada e caracterizada pela sua apresenta ca o top-down. Programa c ao orientada ao objeto: metodologia usada para a cria ca o de programas por interm edio da utiliza ca o de objetos auto-sucientes com dados e o comportamento encapsulados e que atuam por meio de solicita ca o e interagem com outros, enviando e devolvendo mensagens. Programa c ao top-down: metodologia que cria um programa modular de estrutura hier arquica. Primeiro, o desenhista projeta, codica e testa um m odulo que representa a estrutura do programa e depois continua da mesma maneira criando m odulos de n vel mais baixo, que representam suas subfun co es. Programa c ao visual: categoria gen erica de aplicativos que executam programa ca o gr aca e seus efeitos visuais ao usu ario. Por exemplo, em pacotes de desenho os objetos podem ser desenhados, aumentados e at e modicados por meio de manipula co es diretas da imagem na tela e n ao pela altera ca o de dados num ericos em uma tabela de dimens oes. Protegido: podem ser acessados pela classe e pelas classes derivadas. Protocolo: conjunto de mensagens as quais o objeto pode responder. P ublico: os m etodos declarados como public podem ser acessados pela classe, classe derivadas, e por aplica co es (dentro de main(), por exemplo). Qualicador: atributo de um objeto que faz a distin ca o entre o conjunto de objetos na extremidade muitos de uma associa ca o. Recurs ao: habilidade de uma sub-rotina ou m odulo de programa em chamar a si mesmo. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
724 Redeni c ao: propriedade das classes derivadas de modicar os m etodos da classe-pai. Assim, duas classes-irm as (lhas do mesmo pai) podem ter m etodos com o mesmo nome, mas com realiza co es diferentes. Restri c ao: usado em generaliza co es, se refere a limita ca o que uma subclasse coloca no valor de um atributo contido em uma superclasse. Robusto: um software robusto n ao e facilmente destru do por erros em seus pressupostos. Conta com verica co es internas que objetivam eliminar bugs. Simula c ao: representa ca o matem atica da intera ca o de objetos do mundo real. Software livre: software que garante ao usu ario plenas liberdades de uso, modica ca o, c opia e publica ca o de vers oes modicadas. A deni ca o de software livre pode ser encontrada em http://www.gnu.org/philosophy/free-sw.html. Sobrecarga de operador: deni ca o da forma como o operador atua sobre os atributos da classe. Subclasse: renamento de uma classe em uma outra mais especializada (classe-derivada ou lho). Superclasse: em uma hierarquia, uma classe mais gen erica que armazena atributos e m etodos que podem ser herdados por outras classes. Algumas vezes tratada como classe-base ou pai. SMP: single multiple processor (com mem oria compartilhada). SIMD: Single Instruction Stream, Multiple Data. Todos os processadores executam a mesma opera ca o ao mesmo tempo. Muito utilizado no processamento de vetores e matrizes, f acil de implementar. Implementado utilizando swar ou smp. SPMD: Single Program, Multiple Data. Todos os processadores rodam o mesmo programa. Implementado utilizando cluster. Single tasking operating system: sistema operacional que roda somente uma tarefa de cada vez. Ex.: DOS. Tabelas dos m etodos virtuais (VMT): tabela que aparece no segmento de dados de cada tipo de objeto virtual. A VMT cont em o tamanho do objeto (tamanho do registro) e os ponteiros para os m etodos. this: ponteiro para o objeto denido implicitamente. Usado para resolver conitos de nomes dentro de um m etodo da classe. Tipica c ao: propriedade de uma linguagem de distinguir com clareza os tipos denidos. A tipica ca o forte (C++) ajuda a desenvolver softwares mais robustos. Tipo ancestral: todo tipo herdado por qualquer outro tipo de objeto. Tipo de dados abstratos: conjunto de estruturas de dados (tipos de dados) denido em termos de recursos de estruturas e de opera co es executadas sobre elas. Na POO, os tipos de objetos s ao tipos de dados abstratos. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
725 Troca de mensagens: Sistema pelo qual o processamento e distribu do pelas v arias m aquinas do cluster. Os dados s ao enviados de uma m aquina para outra, processados e devolvidos. As bibliotecas para troca de mensagem mais utilizadas s ao o MPI e o PVM. Unix: sistema operacional multiusu ario e multitarefa que trata os dados que foram designados a ele at e aparecer um novo valor ou o programa terminar sua execu ca o. Vari avel de inst ancia: dado contido em um objeto que descreve propriedades do objeto que a possui. Vari avel global: vari avel acess vel a todos os m odulos de um programa. Vari avel: uma estrutura em mem oria que trata os dados que foram designados a ela at e aparecer um novo valor ou o programa terminar a sua execu ca o. Virtual: ambiente simulado ou conceitual. Realidade virtual, por exemplo, e uma realizada simulada. Windows: veja janela. WBS: Work Breakdown Structure.
726
Ap endice J
J.1
Bookmark
O bookmark que utilizo para acessar diversos sites de programa ca o, incluindo os links apresentados neste cap tulo est a disponibilizado em: http://www.lenep.uenf.br/~bueno/bookmarks-prog.html Uma c opia do mesmo e distribu da juntamente com as listagens de programas deste livro. Nota: e importante lembrar que sites de internet mudam constantemente, de forma que alguns links podem n ao estar mais dispon veis.
J.2
Veremos a seguir uma lista de HOWTOs relacionados direta ou indiretamente com programa ca o em C++, desenvolvimento de software livre, software multiplataforma, cluster de computadores e programa ca o paralela. C++ Programming HOWTO. C++ Beautiful HOWTO. CVS RCS HOWTO (document for Linux Source Code Control System). GCC HOWTO. Program Library HOWTO. Kernel HOWTO (kernel do GNU/Linux). Beowulf HOWTO. Parallel Processing HOWTO. Serial Programming HOWTO. 727
728 Glibc 2 HOWTO. Software Release Practice HOWTO. Bash Prog Intro HOWTO. BASH Programming Introduction HOWTO. C editing with VIM HOWTO. Emacs Beginner HOWTO. Esses HOWTOs podem ser obtidos nos sites: http://www.tldp.org/HOWTO/HOWTO-INDEX/howtos.html,
http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/ps/.
J.3
Sites UML
UML no Brasil: http://www.uml.com.br Object management group : http://www.omg.org Refer encia r apida: http://www.rational.com/uml/resources/quick/ UML Tutorial in 7 days : http://odl-skopje.etf.ukim.edu.mk/UML-Help/ Softwares de modelagem: http://www.microgold.com http://www.rational.com/products/rose http://www.visual-paradigm.com http://www.gnome.org/gnome-office/dia.shtm http://bouml.free.fr/ Programa ca o Orientada para Objeto em C++ no Ambiente Windows: http://www.fea.usp.br/Fia/livros/95/liv95-ProgOrientC++.html Object-Oriented Technologies Ltd : http://www.realobj.demon.co.uk/ Welcome to OOPs world : http://oop.rosweb.ru/ Bibliograa: http://liinwww.ira.uka.de/bibliography/Object/index.html Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
729
J.4
J.4.1
Sites C++
Ambientes de desenvolvimento
Kdevelop, ambiente multiplataforma e multilinguagem, completo, com uso da biblioteca QT ou KDE: kdevelop http: // www. kdevelop. org/ Bloodshed Dev-C++ (Windows, GNU/Linux): http://www.bloodshed.net/dev/devcpp.html The Source-Navigator IDE, (GNU/Linux, Unix): http://sources.redhat.com/sourcenav/ Kylix, ambiente com uso da biblioteca VCL (Visual Class Library ) (GNU/Linux, Unix, Windows): http://www.borland.com/kylix/index.html Code Warrior Metroworks, ambiente com uso da biblioteca code warrior : http://www.metrowerks.com Qt - designer, desenho de interfaces gr acas usando a biblioteca Qt (Windows, GNU/Linux, Unix, Mac): http://www.trolltech.com Veja uma pequena reportagem sobre o Qtdesigner na Revista do Linux, edi ca o 31: http://www.revistadolinux.com.br/ed/031/assinantes/programacao.php3 glade, desenho de interfaces gr acas usando a biblioteca gtk++ (GNU/Linux, Unix): http://glade.gnome.org/ GTK+ - The GIMP Toolkit : http://www.gtk.org/ Source-Navigator(TM) : http://sources.redhat.com/sourcenav/ Anjuta [DevStudio] : http://www.anjuta.org/ Eclipse: http://www.eclipse.org/
J.4.2
Compiladores
Intel: http://www.intel.com/software/products/compilers/ Borland: http://www.borland.com/cbuilder Metroworks: http://www.metrowerks.com/ Microsoft Visual C++: http://msdn2.microsoft.com/en-us/visualc/default.aspx Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
730
J.4.3
Exemplos
Voc e pode baixar um conjunto de exemplos de programas em C++ em: www.deitel.com ftp://ftp.cs.rpi.edu/pub/stl http://www.tempest-sw.com/cpp Outros exemplos no site da disciplina de programa ca o pr atica: https://www.lenep.uenf.br/~bueno/DisciplinaProgramacaoPratica/
J.4.4
Tutoriais
Uma lista completa de tutoriais pode ser encontrada em: http://www.mysteries-megasite.com/linux/tutorials.html Tutorial de C++ para programadores de C: http://www.4p8.com/eric.brasseur/cppcen.html GTK: http://www.gtk.org/tutorial/ NIST Course on C++ Programming for Scientists : http://math.nist.gov/~RPozo/c++class/ Diversos: http://www.freetutorials.com/ http://www.mysteries-megasite.com/linux/tutorials.html http://www.cplusplus.com/doc/tutorial/ http://www.intap.net/~drw/cpp/index.htm
J.4.5
FAQ
http://help-site.com/c.m/prog/lang/cpp/ http://www.jamesd.demon.co.uk/csc/faq.html
J.4.6
Voc e encontra em http://www.gotw.ca/publications/, diversas dicas de links do autor Herb Sutter. De um modo geral s ao dicas avan cadas. Dicas de gerenciamento de mem oria: http://www.arnaut.eti.br/op/CPPFL16.htm. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
731
J.5
Comite Ansi C++: http://www.open-std.org/jtc1/sc22/WG21/ Guia STL da GNU: http://gcc.gnu.org/onlinedocs/libstdc++/documentation.html Guia STL: http://www.sgi.com/tech/stl/ Phil Ottewells STL Tutorial : http://www.yrl.co.uk/~phil/stl/stl.htmlx Standard C++ Library User Guide and Tutorial : http://www.roguewave.com/support/docs/stdug/index.cfm STL Quick Reference: http://yotam.freehosting.net/stl/stl.html
J.6
J.6.1
GNU: http://www.gnu.org ftp://ftp.matrix.com.br/pub/gnu/ Open-source : http://www.opensource.org Reposit orio de programas livres: http://www.sourceforge.net Software Livre - Unicamp (Nou-Rau): http://www.dicas-l.unicamp.br http://www.rau-tu.unicamp.br/nou-rau/softwarelivre/ http://www.softwarelivre.unicamp.br/sl http://www.rau-tu.unicamp.br/ http://www.rau-tu.unicamp.br/linux/ Site com refer encias para comandos do shell: http://www.ss64.com/index.html Linux pdfs: http://users.urbi.com.br/ricardomartins/Linux/ Id eias/Discuss oes: http://www.dicas-l.com.br/brod/ Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
732
J.6.2
Portabilidade
J.6.3
Software multiplataforma
GCC Home Page - GNU Project - Free Software Foundation (FSF) : http://gcc.gnu.org/ Mirror da GNU : ftp://ftp.matrix.com.br/pub/gnu/ autoconf : http://www.gnu.org/software/autoconf/ automake : http://www.gnu.org/software/automake/ libtool : http://www.gnu.org/software/libtool/ GNU Autoconf, Automake and Libtool : http://sources.redhat.com/autobook/ GNU Coding Standards (FSF) : http://www.gnu.org/prep/standards_toc.html Autoconf, Automake, and Libtool: C Language Portability : http://sources.redhat.com/autobook/autobook/autobook_111.html LUV talk: An introduction to Linux/Unix programming : http://www.luv.asn.au/overheads/prog/
J.6.4
Auditoria e proler
Programas de auditoria e prolers valgrind : http://valgrind.org/ callgrind : http://spi.cern.ch/extsoft/packages.php?pkg=callgrind oprole : http://oprofile.sourceforge.net/ kcachegrind : http://kcachegrind.sourceforge.net/cgi-bin/show.cgi Manual do gprof : http://www.delorie.com/gnu/docs/binutils/gprof_toc.html Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
733
J.6.5
CVS
A casa do cvs: http://www.cvshome.org/ Interface gr aca para o cvs: http://www.cvsgui.org/download.html http://www.lincvs.org Interface gr aca para o cvs no GNU/LINUX: http://cervisia.sourceforge.net/
J.6.6
Documenta c ao
Doxygen: http://www.stack.nl/~dimitri/doxygen/index.html DocBook - Linux Productivity Magazine : http://www.troubleshooters.com/lpm/200210/200210.htm DocBook with Ly X: http://bgu.chez.tiscali.fr/doc/db4lyx/ emacs - reportagem: http://bazar.conectiva.com.br/~godoy/emacs/psgml/ sgml - reportagem: http://bazar.conectiva.com.br/~godoy/sgml/docbook/porque/ Welcome to GraphViz : http://www.graphviz.org/ Graphviz - Diagramas UML: http://www.research.att.com/sw/tools/graphviz/refs.html
J.7
PVM - Parallel Virtual Machine http://www.epm.ornl.gov/pvm/pvm_home.html. LAM/MPI (Local Area Multicomputer / Message Passing Interface http://www.mpi.nd.edu/lam OOMPI : http://www.osl.iu.edu/research/oompi/ Threads http://www.humanfactor.com/pthreads/ Beowulf : http://www.beowulf.org Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
734
Extreme Linux Software from Red Hat : http://www.redhat.com/extreme,http://www.extremelinux.org Jaceks Beowulf-utils : ftp://ftp.sci.usq.edu.au/pub/jacek/beowulf-utils bWatch - cluster monitoring tool : http://www.sci.usq.edu.au/staff/jacek/bWatch UTC - Tutorial de Unied Parallel C http://anahy.org/Tools/UnifiedParallelC/index.html, http://upc.gwu.edu/ Informa co es gerais sobre cluster: http://www.buyya.com/cluster
J.8
J.8.1
Sites Bibliotecas
Bibliotecas e ferramentas
http://www.trumphurst.com/cpplibs1.html http://www.thefreecountry.com/developercity/freelib.html
Lista de bibliotecas:
Biblioteca Common c++: http://www.voxilla.org/projects/projape.html boost: http://www.boost.org/ blitz++: http://oonumerics.org/blitz/ Ferramentas de C++: http://development.freeservers.com redhat.com|Cygwin: http://www.redhat.com/software/tools/cygwin/ Qt: http://trolltech.com.br/. http://doc.trolltech.com/4.2/index.html Bibliotecas matem aticas e cient cas da GNU: http://www.files-library.com/library/gnu-scientific-library.html http://gfemlib.sourceforge.net/ http://sscilib.sourceforge.net/ Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
735
J.8.2
Programa c ao cient ca
SAL - Numerical Analysis - Miscellaneous Software : http://lem.ch.unito.it/linux/B/0/ SourceForge.net: Project Info - Common C++ Libraries : http://sourceforge.net/projects/cplusplus/ Biblioteca matpack++: http://www.matpack.de/ HPC++: http://www.extreme.indiana.edu/hpc++/index.html Blitz++ Home Page : http://oonumerics.org/blitz/ The Graph Template Library (GTL) : http://www.infosun.fmi.uni-passau.de/GTL/ sl++ project : http://ldeniau.home.cern.ch/ldeniau/html/sl++.html PLAPACK: http://www.cs.utexas.edu/users/plapack/ Numerical Recipes Home Page : http://www.nr.com/ Iterative Methods Library in C++ : http://math.nist.gov/iml++/ The Object-Oriented Numerics Page : http://oonumerics.org/oon/#libraries GNU Scientic Library : http://www.gnu.org/directory/GNU/GNUsl.html Signal Processing Using C++ Classes : http://spuc.sourceforge.net/ The Programming Sharehouse : http://development.freeservers.com/
J.9
Sites Grupos
Grupo de discuss ao de C++: comp.lang.c++, alt.comp.lang.learn.c-c++ Diversas listas de discuss ao de software livre est ao disponibilizadas em: http://listas.softwarelivre.org/ Grupo de GNU/Linux na UFSC: http://www.softwarelivre.ufsc.br Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
J.10
Sites Revistas
J.11
. . .
Livros de C++
J.12
Fedora
Ap endice K
K.1
A linguagem C/C++ possui um conjunto extenso de arquivos denominados arquivos de cabe calho. Estes arquivos incluem as fun co es e classes da biblioteca padr ao de C e C++. Em sistemas GNU/Linux estes arquivos est ao localizados em /usr/include/ (arquivos de cabe calho de C) e /usr/include/c++/vers aoCompilador/ (arquivos de cabe calho de C++). Nos ambientes de desenvolvimento do Windows, os arquivos de cabe calho costumam ser instalados no mesmo diret orio do compilador. Veremos a seguir os arquivos de cabe calho relacionados a: STL (veja se ca o K.4). Objetos fun co es e algoritmos gen ericos (veja se ca o K.4.2). Tratamento de erro, exce co es (veja se ca o K.5). Matem aticos, num ericos (veja se ca o K.4.3). Utilit arios (veja se ca o K.6). Entrada e sa da (streams) (veja se ca o K.2). Strings de C++ (veja se ca o K.3). Bibliotecas de C (veja se ca o K.7). Unix, GNU/Linux (veja se ca o K.8).
K.2
Entrada e sa da (streams)
<locale> Classe para considera ca o de localidades (aspectos regionais, culturais) (se ca o 22.9.2). <streambuf> Buers para streams (Cap tulo 22). <ios> Classe-base para hierarquia de streams (se ca o 22.3). 737
738 <iomanip> Manipuladores (se ca o 22.4). <istream> Classe gabarito para entrada de dados (se ca o 22.7). <ostream> Classe gabarito para sa da de dados (se ca o 22.5).
<iostream> Entrada e sa da com streams (Cap tulo 22, se co es 22.7 e 22.5). <sstream> Classes para manipula ca o de strings/streams em conjunto (se ca o 22.8). <fstream> Entrada e sa da com arquivos de disco (se ca o 23.2). <iosfwd> Recursos de E/S. "pstream.h" O arquivo de cabe calho pstream.h descrito na se ca o 23.5.4 (n ao e um arquivo padr ao). O mesmo e inclu do junto com as listagem do livro. Tamb em pode ser obtido em http://pstreams.sourceforge.net.
K.3
Strings de C++
K.4
K.4.1
<list> <deque> <stack> <queue> <map> <set>
STL
Containers da STL
Listas duplamente encadeadas (se ca o 32.2). Fila de duas pontas (se ca o 32.3). Pilha do tipo LIFO, primeiro que entra e o ultimo que sai (se ca o 33.1). Fila do tipo FIFO, primeiro que entra e o primeiro que sai (se ca o 33.2). Par associativo chave-valor, inclue as classes <map> (se ca o 34.4) e <multimap> (34.5). Conjunto de chaves, inclue as classes <set> (se ca o 34.2) e <multiset> (se ca o 34.3).
<bitset> Vetor de valores booleanos (se ca o 30.3). <iterator> Iteradores (se ca o 31.3). <valarray> Classes de vetores de alto desempenho (a dica e usar a biblioteca Blitz++,). Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
739
K.4.2
<utility> Operadores e pares. <functional> Objetos fun co es (Cap tulo 36). <algorithm> Algoritmos gen ericos, fun co es gen ericas (Cap tulo 35). <numeric> Opera co es gen ericas (Cap tulo 35).
K.4.3
<limits> Deni ca o de limites num ericos (Cap tulo 9.1, veja exemplo na listagem 9.3). <complex> Classe dos n umeros complexos (se ca o 30.2). <valarray> Classes de vetores de alto desempenho. <numeric> Opera co es gen ericas (se ca o 35.3).
K.5
<exception> Tratamento de exce co es, classes de exce ca o (Cap tulo 26). <stdexcept> Exce co es-padr ao (Cap tulo 26).
K.6
<new>
Utilit arios
Aloca ca o din amica de mem oria (se ca o 15.3.1). Aloca ca o de mem oria e containers.
K.7
Bibliotecas de C
Observe que em vers oes antigas de C, estes arquivos de cabe calho n ao tinham a letra inicial c e inclu am uma extens ao .h. Por exemplo, o arquivo de cabe calho <ctime> se chamava <time.h>. Nota: e nesta se ca o colocamos apenas uma breve descri ca o da fun ca o. Para maiores detalhes importante lembrar que algumas classes de bibliotecas consulte os manuais e sites de C. E externas, como Blitz++, substituem com vantagens estas fun co es. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
740
K.7. BIBLIOTECAS DE C
K.7.1
<cstdlib>
Aborta o processor currente e retorna c odigo de erro. Retorna o valor absoluto de um n umero inteiro passado como par ametro. Converte string para double. Converte string para int. Converte string para long. Pesquisa binaria. calloc() Aloca um array de mem oria. div() *ecvt() exit() *fcvt() free() *gcvt() *itoa() labs() ldiv() Divide dois n umeros inteiros. Converte n umeros oating point para string. Termina o processo. Converte n umeros oating point para string. Desaloca memoria alocada dinamicamente. Converte n umeros oating point para string. Converte n umero inteiro para string. Retourna valor absoluto de par ametro long int. Divide dois n umeros long int.
<cstdlib> Fun co es padr oes de C. Veja http://www.cplusplus.com/ref/. abort() abs() atof() atoi() atol() bsearch()
*lfind() Pesquisa linear. *lsearch() Pesquisa linear. *ltoa() *max() *min() *putenv() Cria ou modica vari avel de ambiente. qsort() rand() realloc() Realoca bloco de mem oria. srand() Inicializa gerador de n umeros rand omicos. strtod() Converte string para double. strtol() Converte string para long int. strtoul() Converte string para unsigned long int. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno Ordena ca o usando algoritmo tipo quicksort. Gera n umero randomico. Converte n umero long int para string. Retorna o maior valor de dois parametros. Retorna o menor valor de dois parametros. malloc() Aloca bloco de mem oria.
K.7. BIBLIOTECAS DE C *swab() *ultoa() Converte unsigned long int para string. Troca bytes.
741
K.7.2
<cstdio>
<cstdio> Fun co es de entrada e sa da de C. Veja http://www.cplusplus.com/ref/. clearerr() Reseta o indicador de erros. fclose() Fecha a stream. feof() Checa se End Of File ocorreu. ferror() Checa por erros. fflush() Descarrega a stream. fgetc() fgets() Obt em uma string a partir de uma stream. fopen() fprintf() Imprime dados formados para uma stream. fputc() Escreve um caracter em uma stream. fputchar() Escreve um caracter em stdout. fputs() fread() Escreve uma string em uma stream. L e um bloco de dados de uma stream. Abre arquivo. Obt em o pr oximo caracter da stream. fgetpos() Obt em posi ca o da stream (ponteiro get).
freopen() Reabre um arquivo usando outro modo de abertura. fscanf() L e dados formatados de uma stream. fseek() Reposiciona posi ca o do ponteiro de leitura (stream s position indicator ). Retorna posi ca o corrente do ponteiro de arquivo. Obt em pr oximo caracter. Obt em uma string de stdin. Obt em o pr oximo valor de uma stream.
fsetpos() Reposiciona ponteiro para arquivo salvo numa determinada localiza ca o. ftell() getc() gets() getw() fwrite() Escreve um bloco de dados em uma stream. getchar() Obt em pr oximo caracter de stdin.
perror() Imprime mensagem de erro. printf() Imprime dados formatados para stdout. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
742 putc() putchar() Escreve um caracter para stdout. puts() putw() Escreve uma string para stdout. Escreve um inteiro em uma stream. Escreve um caracter para stream.
K.7. BIBLIOTECAS DE C
remove() Apaga um arquivo. rename() Renomeia um arquivo ou diret orio. rewind() Reposiciona ponteiro de arquivo a partir do in cio da stream. scanf() L e dados formatados de stdin. setbuf() Muda stream buferizada. setvbuf() Muda stream buferizada. sprintf() Formata dados para string. sscanf() L e dados formatados da string. tmpfile() Abre temporariamente um arquivo. tmpnam() Gera um arquivo tempor ario e u nico. ungetc() Coloca um caracter de volta na stream.
K.7.3
<ctime>
<ctime>
Data e hora no formato de C, rel ogio do sistema (antigo time.h). Veja http: //www.cplusplus.com/ref/. asctime() Converte uma estrutura tm para string. clock() ctime() Retorna o n umero de clock ticks desde que o processo foi iniciado. Converte time_t para string.
difftime() Retorna a diferen ca entre dois time_t. gmtime() Converte o valor time_t para uma estrutura UTC. localtime() Converte o valor time_t para uma estrutura tm como hora local. mktime() Converte uma estrutura tm para time_t. time() Obt em tempo corrente.
K.7.4
<cstring>
<cstring> Antigas fun co es para tratamento de strings de C. Veja http://www.cplusplus.com/ref/. memchr() Procura caracter no buer. memcmp() Compara dois buers. memcpy() Copia bytes de um buer para outro buer. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
K.7. BIBLIOTECAS DE C memmove() Copia bytes de um buer para outro buer. memset() Preenche o buer com o caracter especicado. strcat() Adiciona cstring no modo append. strchr() Procura caracter numa cstring. strcmp() Compara duas cstrings. strcoll() Compara duas cstrings usando informa co es do locale. strcpy() Copia cstrings. strcspn() Search string for occurrence of charcter set strerror() Obt em ponteiro para mensagem de erro da cstring. strlen() Retorna dimens ao da cstring. strncat() Adiciona substring em uma cstring. strncmp() Compara alguns caracteres das duas strings. strncpy() Copia caracteres de uma string para outra. strpbrk() Procura na cstring caracteres especicados. strrchr() Procura u ltima ocorr encia de um caracter na cstring. strspn() Obt em a dimens ao da substring. strstr() Procura substring. strtok() Trunca a cstring sequencialmente se o delimitador foi localizado. strxfrm() Transforma a cstring usando caracter sticas do locale.
743
K.7.5
Diversos
<cassert> Inclui a macro assert. <cerrno> Tratamento de erro. <cctype> Deni ca o de caracteres (classica ca o). <cwtype> Deni ca o de caracteres longos (classica ca o). <cwchar> Antigas fun co es para tratamento de strings de C longas. <clocale> Fun co es para considera ca o de localidades (aspectos regionais, culturais). <climits> Deni ca o de limites num ericos. <cfloat> Macros de limites num ericos (ponto utuante). <cstddef> Suporte de linguagem. <cstdarg> Tratamento de argumentos (lista de argumentos). <csignal> Tratamento de sinais. <cmath> Fun co es matem aticas padr oes (se ca o 30.1).
<unistd.h> Fun co es padr oes do Unix, GNU/Linux. Inclui fun co es como: chown, link, unlink, symlink, rmdir, chdir. Veja listagem ??. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
744
K.8
Unix, GNU/Linux
<unistd.h> Fun co es diversas de Unix, GNU/Linux (veja Parte ?? - Programa ca o Multiplataforma com Software Livre e Parte ?? Cluster de Computadores e Processamento Paralelo. <sys/stat.h> Fun co es Unix, incluindo: chmod(), mkdir(), getcwd().
Ap endice L
L.1
Introdu c ao
As licen cas de muitos software s ao desenvolvidas para restringir sua liberdade de compartilh alo e mud a-lo. Contr aria a isso, a Licen ca P ublica Geral GNU pretende garantir sua liberdade de compartilhar e alterar software livres garantindo que o software ser a livre e gratuito para os seus usu arios. Esta Licen ca P ublica Geral aplica-se ` a maioria dos software da Free Software Foundation e a qualquer outro programa cujo autor decida aplic a-la. (Alguns outros software da FSF s ao cobertos pela Licen ca P ublica Geral de Bibliotecas, no entanto.) Voc e pode aplic a-la tamb em aos seus programas. Quando nos referimos a software livre, estamos nos referindo a liberdade e n ao a pre co. Nossa Licen ca P ublica Geral foi desenvolvida para garantir que voc e tenha a liberdade de distribuir c opias de software livre (e cobrar por isso, se quiser); que voc e receba o c odigo-fonte ou tenha acesso a ele, se quiser; que voc e possa mudar o software ou utilizar partes dele em novos programas livres e gratuitos; e que voc e saiba que pode fazer tudo isso. Para proteger seus direitos, precisamos fazer restri co es que impe cam a qualquer um negar estes direitos ou solicitar que voc e deles abdique. Estas restri co es traduzem-se em certas responsabilidades para voc e, se voc e for distribuir c opias do software ou modic a-lo. 745
E L.2. LICENCA PUBLICA GERAL GNU CONDIC OES PARA COPIA, DISTRIBUIC AO 746 MODIFICAC AO Por exemplo, se voc e distribuir c opias de um programa, gratuitamente ou por alguma quantia, voc e tem que fornecer aos recebedores todos os direitos que voc e possui. Voc e tem que garantir que eles tamb em recebam ou possam obter o c odigo-fonte. E voc e tem que mostrarlhes estes termos para que eles possam conhecer seus direitos. N os protegemos seus direitos em dois passos: (1) com copyright do software e (2) com a oferta desta licen ca, que lhe d a permiss ao legal para copiar, distribuir e/ou modicar o software. Al em disso, tanto para a prote ca o do autor quanto a nossa, gostar amos de certicar-nos que todos entendam que n ao h a qualquer garantia nestes software livres. Se o software e modicado por algu em mais e passado adiante, queremos que seus recebedores saibam que o que eles obtiveram n ao e original, de forma que qualquer problema introduzido por terceiros n ao interra na reputa ca o do autor original. Finalmente, qualquer programa e amea cado constantemente por patentes de software. Queremos evitar o perigo de que distribuidores de software livre obtenham patentes individuais, o que tem o efeito de tornar o programa propriet ario. Para prevenir isso, deixamos claro que qualquer patente tem que ser licenciada para uso livre e gratuito por qualquer pessoa, ou ent ao que nem necessite ser licenciada. Os termos e condi co es precisas para c opia, distribui c ao e modica ca o se encontram abaixo:
L.2
Licen ca p ublica geral GNU condi c oes para c opia, distribui c ao e modica c ao
0. Esta licen ca se aplica a qualquer programa ou outro trabalho que contenha um aviso colocado pelo detentor dos direitos autorais informando que aquele pode ser distribu do sob as condi co es desta Licen ca P ublica Geral. O Programa abaixo refere-se a qualquer programa ou trabalho, e trabalho baseado no Programa signica tanto o Programa em si como quaisquer trabalhos derivados, de acordo com a lei de direitos autorais: isto quer dizer um trabalho que contenha o Programa ou parte dele, tanto originalmente ou com modica co es, e/ou tradu ca o para outros idiomas. (Doravante o processo de tradu ca o est a inclu do sem limites no termo modica ca o.) Cada licenciado e mencionado como voc e. Atividades outras que a c opia, a distribui ca o e modica ca o n ao est ao cobertas por esta Licen ca; elas est ao fora de seu escopo. O ato de executar o Programa n ao e restringido e o resultado do Programa e coberto apenas se seu conte udo contenha trabalhos baseados no Programa (independentemente de terem sido gerados pela execu ca o do Programa). Se isso e verdadeiro depende do que o programa faz. 1. Voc e pode copiar e distribuir c opias eis do c odigo-fonte do Programa da mesma forma que voc e o recebeu, usando qualquer meio, deste que voc e consp cua e apropriadamente publique em cada c opia um aviso de direitos autorais e uma declara ca o de inexist encia de garantias; mantenha intactas todos os avisos que se referem a esta Licen ca e ` a aus encia total de garantias; e forne ca a outros recebedores do Programa uma c opia desta Licen ca, junto com o Programa. 2. Voc e pode modicar sua c opia ou c opias do Programa, ou qualquer parte dele, assim gerando um trabalho baseado no Programa, e copiar e distribuir essas modica co es ou trabalhos sob os temos da se ca o 1 acima, desde que voc e tamb em se enquadre em todas estas condi co es: a) Voc e tem que fazer com que os arquivos modicados levem avisos proeminentes armando que voc e alterou os arquivos, incluindo a data de qualquer altera ca o. Andr e Duarte Bueno
E L.2. LICENCA PUBLICA GERAL GNU CONDIC OES PARA COPIA, DISTRIBUIC AO MODIFICAC AO 747 b) Voc e tem que fazer com que quaisquer trabalhos que voc e distribua ou publique, e que integralmente ou em partes contenham ou sejam derivados do Programa ou de suas partes, sejam licenciados, integralmente e sem custo algum para quaisquer terceiros, sob os termos desta Licen ca. Se qualquer programa modicado normalmente l e comandos interativamente quando executados, voc e tem que fazer com que, quando iniciado tal uso interativo da forma mais simples, seja impresso ou mostrado um an uncio de que n ao h a qualquer garantia (ou ent ao que voc e fornece a garantia) e que os usu arios podem redistribuir o programa sob estas condi co es, ainda informando os usu arios como consultar uma c opia desta Licen ca. (Exce ca o: se o Programa em si e interativo mas normalmente n ao imprime estes tipos de an uncios, seu trabalho baseado no Programa n ao precisa imprimir um an uncio.)
c)
Estas exig encias aplicam-se ao trabalho modicado como um todo. Se se co es identic aveis de tal trabalho n ao s ao derivadas do Programa, e podem ser razoavelmente consideradas trabalhos independentes e separados por si s o, ent ao esta Licen ca, e seus termos, n ao se aplicam a estas se co es quando voc e distribui-las como trabalhos em separado. Mas quando voc e distribuir as mesmas se co es como parte de um todo que e trabalho baseado no Programa, a distribui ca o como um todo tem que se enquadrar nos termos desta Licen ca, cujas permiss oes para outros licenciados se estendem ao todo, portanto tamb em para cada e toda parte independente de quem a escreveu. Desta forma, esta se ca o n ao tem a inten ca o de reclamar direitos os contestar seus direitos sobre o trabalho escrito completamente por voc e; ao inv es disso, a inten ca o e a de exercitar o direito de controlar a distribui ca o de trabalhos, derivados ou coletivos, baseados no Programa. Adicionalmente, a mera adi ca o ao Programa de outro trabalho n ao baseado no Programa (ou de trabalho baseado no Programa) em um volume de armazenamento ou meio de distribui ca o n ao faz o outro trabalho parte do escopo desta Licen ca. 3. Voc e pode copiar e distribuir o Programa (ou trabalho baseado nele, conforme descrito na Se ca o 2) em c odigo-objeto ou em forma execut avel sob os termos das Se co es 1 e 2 acima, desde que voc e fa ca um dos seguintes: a) O acompanhe com o c odigo-fonte completo e em forma acess vel por m aquinas, que tem que ser distribu do sob os termos das Se co es 1 e 2 acima e em meio normalmente utilizado para o interc ambio de software ; ou, O acompanhe com uma oferta escrita, v alida por pelo menos tr es anos, de fornecer a qualquer um, com um custo n ao superior ao custo de distribui ca o f sica do material, uma c opia do c odigo-fonte completo e em forma acess vel por m aquinas, que tem que ser distribu do sob os termos das Se co es 1 e 2 acima e em meio normalmente utilizado para o interc ambio de software ; ou, O acompanhe com a informa ca o que voc e recebeu em rela ca o ` a oferta de distribui ca o do c odigo-fonte correspondente. (Esta alternativa e permitida somente em distribui ca o n ao comerciais, e apenas se voc e recebeu o programa em forma de c odigo-objeto ou execut avel, com oferta de acordo com a Subse ca o b acima.)
b)
c)
O c odigo-fonte de um trabalho corresponde ` a forma de trabalho preferida para se fazer modica co es. Para um trabalho em forma execut avel, o c odigo-fonte completo signica Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
E L.2. LICENCA PUBLICA GERAL GNU CONDIC OES PARA COPIA, DISTRIBUIC AO 748 MODIFICAC AO todo o c odigo-fonte de todos os m odulos que ele cont em, mais quaisquer arquivos de deni ca o de interface, mais os scripts utilizados para se controlar a compila ca o e a instala ca o do execut avel. Contudo, como exce ca o especial, o c odigo-fonte distribu do n ao precisa incluir qualquer componente normalmente distribu do (tanto em forma original quanto bin aria) com os maiores componentes (o compilador, o kernel etc.) do sistema operacional sob o qual o execut avel funciona, a menos que o componente em si acompanhe o execut avel. Se a distribui ca o do execut avel ou c odigo-objeto e feita atrav es da oferta de acesso a c opias de algum lugar, ent ao ofertar o acesso equivalente a c opia, do mesmo lugar, do c odigofonte equivale ` a distribui ca o do c odigo-fonte, mesmo que terceiros n ao sejam compelidos a copiar o c odigo-fonte com o c odigo-objeto. 4. Voc e n ao pode copiar, modicar, sub-licenciar ou distribuir o Programa, exceto de acordo com as condi co es expressas nesta Licen ca. Qualquer outra tentativa de c opia, modica ca o, sub-licenciamento ou distribui ca o do Programa n ao e valida, e cancelar a automaticamente os direitos que lhe foram fornecidos por esta Licen ca. No entanto, terceiros que de voc e receberam c opias ou direitos, fornecidos sob os termos desta Licen ca, n ao ter ao suas licen cas terminadas, desde que permane cam em total concord ancia com ela. 5. Voc e n ao e obrigado a aceitar esta Licen ca j a que n ao a assinou. No entanto, nada mais o dar a permiss ao para modicar ou distribuir o Programa ou trabalhos derivados deste. Estas a co es s ao proibidas por lei, caso voc e n ao aceite esta Licen ca. Desta forma, ao modicar ou distribuir o Programa (ou qualquer trabalho derivado do Programa), voc e estar a indicando sua total aceita ca o desta Licen ca para faz e-los, e todos os seus termos e condi co es para copiar, distribuir ou modicar o Programa, ou trabalhos baseados nele. 6. Cada vez que voc e redistribuir o Programa (ou qualquer trabalho baseado nele), os recebedores adquirir ao automaticamente do licenciador original uma licen ca para copiar, distribuir ou modicar o Programa, sujeitos a estes termos e condi co es. Voc e n ao poder a impor aos recebedores qualquer outra restri ca o ao exerc cio dos direitos ent ao adquiridos. Voc e n ao e respons avel em garantir a concord ancia de terceiros a esta Licen ca. 7. Se, em conseq u encia de decis oes judiciais ou alega co es de infringimento de patentes ou quaisquer outras raz oes (n ao limitadas a assuntos relacionados a patentes), condi co es forem impostas a voc e (por ordem judicial, acordos ou outras formas) e que contradigam as condi co es desta Licen ca, elas n ao o livram das condi co es desta Licen ca. Se voc e n ao puder distribuir de forma a satisfazer simultaneamente suas obriga co es para com esta Licen ca e para com as outras obriga co es pertinentes, ent ao como conseq u encia voc e n ao poder a distribuir o Programa. Por exemplo, se uma licen ca de patente n ao permitir aa redistribui ca o, livre de royalties, do Programa, por todos aqueles que receberem c opias direta ou indiretamente de voc e, ent ao a u nica forma de voc e satisfazer a ela e a esta Licen ca seria a de desistir completamente de distribuir o Programa. Se qualquer parte desta se ca o for considerada inv alida ou n ao aplic avel em qualquer circunst ancia particular, o restante da se ca o se aplica, e a se ca o como um todo se aplica em outras circunst ancias. O prop osito desta se ca o n ao e o de induzi-lo a infringir quaisquer patentes ou reivindica ca o de direitos de propriedade outros, ou a contestar a validade de quaisquer dessas reivindica co es; esta se ca o tem como u nico prop osito proteger a integridade dos sistemas de distribui ca o de software livres, o que e implementado pela pr atica de licen cas p ublicas. Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
E L.2. LICENCA PUBLICA GERAL GNU CONDIC OES PARA COPIA, DISTRIBUIC AO MODIFICAC AO 749 V arias pessoas t em contribu do generosamente e em grande escala para os software distribu dos usando este sistema, na certeza de que sua aplica c ao e feita de forma consistente; ca a crit erio do autor/doador decidir se ele ou ela est a disposto a distribuir software utilizando outro sistema, e um licenciado n ao pode impor qualquer escolha. Esta se ca o destina-se a tornar bastante claro o que se acredita ser conseq u encia do restante desta Licen ca. 8. Se a distribui ca o e/ou uso do Programa s ao restringidos em certos pa ses por patentes ou direitos autorais, o detentor dos direitos autorais original, e que colocou o Programa sob esta Licen ca, pode incluir uma limita ca o geogr aca de distribui ca o, excluindo aqueles pa ses de forma a tornar a distribui ca o permitida apenas naqueles ou entre aqueles pa ses ent ao n ao exclu dos. Nestes casos, esta Licen ca incorpora a limita ca o como se a mesma constasse escrita nesta Licen ca. 9. A Free Software Foundation pode publicar vers oes revisadas e/ou novas da Licen ca P ublica Geral de tempos em tempos. Estas novas vers oes ser ao similares em esp rito ` a vers ao atual, mas podem diferir em detalhes que resolvem novos problemas ou situa co es. A cada vers ao e dada um n umero distinto. Se o Programa especica um n umero de vers ao espec co desta Licen ca que se aplica a ele e a qualquer nova vers ao, voc e tem a op ca o de aceitar os termos e condi co es daquela vers ao ou de qualquer outra vers ao publicada pela Free Software Foundation. Se o programa n ao especica um n umero de vers ao desta Licen ca, voc e pode escolher qualquer vers ao j a publicada pela Free Software Foundation. 10. Se voc e pretende incorporar partes do Programa em outros programas livres cujas condic o es de distribui ca o s ao diferentes, escreva ao autor e solicite permiss ao. Para o software que a Free Software Foundation det em direitos autorais, escreva ` a Free Software Foundation ; ` as vezes n os permitimos exce co es a este caso. Nossa decis ao ser a guiada pelos dois objetivos de preservar a condi ca o de liberdade de todas as deriva co es do nosso software livre, e de promover o compartilhamento e reutiliza ca o de software em aspectos gerais. AUSENCIA DE GARANTIAS LICENCIADO SEM ONUS, HA QUALQUER 11. UMA VEZ QUE O PROGRAMA E NAO GARANTIA PARA O PROGRAMA, NA EXTENSAO PERMITIDA PELAS LEIS APLICAVEIS. EXCETO QUANDO EXPRESSADO DE FORMA ESCRITA, OS DETENTORES DOS DIREITOS AUTORAIS E/OU TERCEIROS DISPONIBILIZAM O PROGRAMA NO ESTADO, SEM QUALQUER TIPO DE GARANTIAS, EXPRES LIMITADO A, AS GARANTIAS IMSAS OU IMPL ICITAS, INCLUINDO, MAS NAO A QUALQUER PROPLICITAS DE COMERCIALIZAC AO E AS DE ADEQUAC AO POSITO. O RISCO TOTAL COM A QUALIDADE E DESEMPENHO DO PROGRAMA SEU. SE O PROGRAMA SE MOSTRAR DEFEITUOSO, VOCE ASSUME OS CUSE TOS DE TODAS AS MANUTENC OES, REPAROS E CORREC OES. A MENOS QUE EXIGIDO PELAS LEIS APLICAVEIS 12. EM NENHUMA OCASIAO, OU ACORDO ESCRITO, OS DETENTORES DOS DIREITOS AUTORAIS, OU QUALQUER OUTRA PARTE QUE POSSA MODIFICAR E/OU REDISTRIBUIR O PRO RESPONSABILIZADOS POR GRAMA CONFORME PERMITIDO ACIMA, SERAO VOCE POR DANOS, INCLUINDO QUALQUER DANO EM GERAL, ESPECIAL, ACI DENTAL OU CONSEQUENTE, RESULTANTES DO USO OU INCAPACIDADE DE LIMITADO A, A PERDA DE DAUSO DO PROGRAMA (INCLUINDO, MAS NAO DOS OU DADOS TORNADOS INCORRETOS, OU PERDAS SOFRIDAS POR VOCE Programa ca o Orientada a Objeto com C++ Andr e Duarte Bueno
750
L.3. COMO APLICAR ESTES TERMOS AOS SEUS NOVOS PROGRAMAS OU POR OUTRAS PARTES, OU FALHAS DO PROGRAMA AO OPERAR COM QUALQUER OUTRO PROGRAMA), MESMO QUE TAL DETENTOR OU PARTE TENHAM SIDO AVISADOS DA POSSIBILIDADE DE TAIS DANOS. FIM DOS TERMOS E CONDIC OES
L.3
Se voc e desenvolver um novo programa, e quer que ele seja utilizado amplamente pelo p ublico, a melhor forma de alcan car este objetivo e torn a-lo software livre que qualquer um pode redistribuir e alterar, sob estes termos. mais seguro anex Para isso, anexe os seguintes avisos ao programa. E a-los logo no in cio de cada arquivo-fonte para refor carem mais efetivamente a inexist encia de garantias; e cada arquivo deve possuir pelo menos a linha de copyright e uma indica ca o de onde o texto completo se encontra. <uma linha que forne ca o nome do programa e uma id eia do que ele faz.> Copyright (C) <ano> <nome do autor> Este programa e software livre; voc e pode redistribu -lo e/ou modic a-lo sob os termos da Licen ca P ublica Geral GNU, conforme publicada pela Free Software Foundation ; tanto a vers ao 2 da Licen ca como (a seu crit erio) qualquer vers ao mais nova. Este programa e distribu do na expectativa de ser u til, mas SEM QUALQUER GARANTIA; ou de ADEQUAC A QUALsem mesmo a garantia impl cita de COMERCIALIZAC AO AO QUER PROPOSITO EM PARTICULAR. Consulte a Licen ca P ublica Geral GNU para obter mais detalhes. Voc e deve ter recebido uma c opia da Licen ca P ublica Geral GNU junto com este programa; se n ao, escreva para a Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Inclua tamb em informa co es sobre como contact a-lo eletronicamente e por carta. Se o programa e interativo, fa ca-o mostrar um aviso breve como este, ao iniciar um modo interativo: Gnomovision vers ao 69, Copyright (C) ano nome do autor O Gnomovision n ao possui QUALQUER GARANTIA; para obter mais detalhes digite show w. Ele e software livre e voc e est a convidado a redistribui-lo sob certas condi co es; digite show c para obter detalhes. Os comandos hipot eticos show w e show c devem mostrar as partes apropriadas da Licen ca P ublica Geral. Claro, os comandos que voc e usar podem ser ativados de outra forma que show w e show c; eles podem at e ser cliques do mouse ou itens de um menu o que melhor se adequar ao programa. Voc e tamb em deve obter do seu empregador (se voc e trabalha como programador) ou escola, se houver, uma declara ca o de aus encia de direitos autorais sobre o programa, se necess ario. Aqui est a um exemplo; altere os nomes: Yoyodyne, Inc., aqui declara a aus encia de quaisquer direitos autorais sobre o programa Gnomovision (que executa interpreta co es em compiladores) escrito por James Hacker. <assinatura de Ty Coon>, 1o. de abril de 1989 Ty Con, Vice-presidente Esta Licen ca P ublica Geral n ao permite incorporar seu programa em programas propriet arios. Se seu programa e uma biblioteca de sub-rotinas, voc e deve considerar mais u til permitir ligar aplica co es propriet arias com a biblioteca. Se isto e o que voc e deseja, use a Licen ca P ublica Geral de Bibliotecas GNU, ao inv es desta Licen ca.
Indice Remissivo
<algorithm>, 737 <bitset>, 736 <cmath>, 525 <complex>, 737 <cstdio>, 739 <cstdlib>, 738 <cstring>, 740 <ctime>, 740 <deque>, 736 <exception>, 737 <fstream>, 736 <functional>, 737 <iomanip>, 736 <ios>, 735 <iosfwd>, 736 <iostream>, 736 <istream>, 736 <iterator>, 736 <limits>, 737 <list>, 736 <locale>, 735 <map>, 736 <memory>, 737 <new>, 737 <numeric>, 737 <ostream>, 736 <queue>, 736 <set>, 736 <sstream>, 736 <stack>, 736 <stdexcept>, 737 <streambuf>, 735 <string>, 736 <sys/stat.h>, 742 <typeinfo>, 737 <unistd.h>, 742 <utility>, 737 <valarray>, 736, 737 <vector>, 736 #dene, 638 #if, 639 #if...#elif...#elif...#endif, 641 #if...#else, 640 #ifdef, 638 #ifdef...#else, 640 #ifndef, 639 #undef, 639 Abstra ca o, 69 abstratas, 77 acesso a disco, 429 Agrega ca o, 125 Algoritmos gen ericos, 595 Ambiente gr aco, 151 Ambientes de desenvolvimento, 151, 152, 727 Ambiguidade, 327 Ambiguidade em heran ca m ultipla, 347 An alise de dom nio, 115 An alise orientada a objeto, 105, 119 Ansi C, 183 Ansi C++, 183 AOO, 105, 119, 133 Armazenando e lendo objetos, 434 Arquivo de cabe calho, 187 Arquivo de implementa ca o, 188 Arquivo de projeto, 187 Arquivos de Cabe calho, 735 Arquivos de disco, 429 Arquivos de disco bin arios, 442 Assinatura, 77 associa ca o, 112 Associa co es, 124, 157, 521 Associa co es - identica ca o, 122 Assuntos, 116 assuntos, 116 Atividade, 79 ator, 111 Atribui ca o, 194 Atributo de liga ca o, 521 Atributos, 73, 259 751
752 atributos, 120, 156 Atributos - identica ca o, 120 Atributos - Uso avan cado, 264 Atributos com mutable, 264 Atributos com volatile, 265 Atributos const, 263 Atributos de classe, 261 Atributos de objeto, 260 Atributos est aticos, 261 auto ptr, 686 Base comum, 347 Biblioteca gr aca, 151 biblioteca gr aca, 151 Biblioteca padr ao - stl, 541 Bibliotecas, 402 bibliotecas, 150, 174 Bibliotecas de C, 525 Blocos, 195 break, 671 C odigo Aberto, 53 Cancelamento, 78 Casos de uso, 111 casos de uso, 111 cast, 462 catch, 475 Cen ario, 111 Chamada explicita do construtor, 340 class <bitset>, 532 class <complex>, 528 class <deque>, 569 class <fstream>, 429 class <iomanip>, 409 class <ios>, 413 class <ios base>, 403 class <istream>, 415 class <list>, 563 class <map>, 587 class <multimap>, 592 class <multiset>, 586 class <ostream>, 412 class <priority queue>, 580 class <queue>, 578 class <set>, 583 class <sstream>, 420 class <stack>, 575 class <string>, 447 class <vector>, 555 Classe, 125 Programa ca o Orientada a Objeto com C++
INDICE REMISSIVO Classe de associa ca o, 125 Classes, 72, 249 Classes abstratas, 129, 367 Classes aninhadas, 254 Classes de armazenamento, 195, 645 Classes friend, 381 Classes identica ca o, 119 Classes templates, 494, 511 Classica ca o, 77, 602 colabora ca o, 136 Coment arios, 193 Compara ca o, 598 Compartilhamento, 77 Compila ca o condicional, 638 Compilador - mensagens de erro, 357 Compilar, 185 Compondo namespace, 246 Composi co es, 125 composi co es, 126 composta, 131 comunica ca o, 136 Concep ca o, 105, 110 conjuntos, 604 const, 651 Construtor de c opia, 317 Construtor de convers ao, 461 Construtor default, 315 Construtor e Ambiguidade, 327 Containers, 543 continue, 672 Controle, 147, 665 controle, 149 Conven ca o para nomes de objetos, 197 Convers ao com reinterpret cast, 466 Convers ao de ponteiros, 686 Convers ao din amica, 464 Convers ao est atica, 464 Convers ao explicita, 463 Convers oes, 78, 459 CRC, 171 Cria ca o e destrui ca o dos objetos, 349 Debugar, 185 Declara ca o, 194 Declara ca o de um m etodo, 269 Declara co es, 211 declara co es, 197 Deni ca o, 194 Deni ca o de um m etodo, 270 deni co es, 198 Andr e Duarte Bueno
INDICE REMISSIVO Denindo um namespace, 243 Delega ca o, 76 delete, 300 Depend encias, 130 Destrutores, 314 Dev C++, 153 dia, 93 Diagrama de atividade, 142 Diagrama de atividades com raios de nata ca o, 144 Diagrama de caso de uso, 111 Diagrama de classes, 122 Diagrama de classes com associa co es, 124 Diagrama de classes com heran cas, 128 Diagrama de colabora ca o, 136 Diagrama de componentes, 158 Diagrama de estados compostos ou sub-estados, 139 Diagrama de estrutura composta, 131 Diagrama de execu ca o, 159 Diagrama de intera ca o geral, 145 Diagrama de m aquina de estado, 138 Diagrama de objetos, 130 Diagrama de pacotes, 116 Diagrama de pacotes (assuntos), 116 Diagrama de sequ encia, 134 Diagrama de tempo, 145 Diagramas da UML, 85 Diagramas de estados concorrentes, 140 Diagramas UML, 93 Dicion ario, 171 Diretrizes de pr e-processador, 637 Diretrizes de pr e-processamento, 196 Diversos, 741 do a ca o while (teste);, 671 Documenta ca o, 106, 167 Documenta ca o do programa, 167 dynamic cast, 464 Efeitos do projeto nas associa co es, 157 Efeitos do projeto nas heran cas, 157 Efeitos do projeto nos m etodos, 156 Elabora ca o, 105, 114 Elementos da UML, 88 elipse..., 678 Empacotamento, 172 empacotamento, 172 Encapsulamento, 70, 250, 253 Engenharia de Software, 99 engenharia de software, 101 Programa ca o Orientada a Objeto com C++
753 Entrada e sa da, 401, 735 Entrada e sa da no C++, 401 Entrada na linha de comando, 675 Enumera co es, 699 enumerated, 699 Enviando comandos para outro programa, 442 escala, 83, 175 Escopo, 195, 651 escopo, 211 Especializa ca o, 112 especica ca o, 110 Especica co es, 110 Especicador, 195 Especicador de acesso, 250 Especicador de heran ca, 337 estado, 138 estados, 137 Estados identica ca o, 137 Estere otipos, 89 Estruturas, 695 Estruturas aninhadas, 697 Etapas de desenvolvimento de um programa, 109 Evento, 79 Eventos, 133, 134 Exce co es, 79 exce co es-padr ao, 476 Excess oes, 471 Exemplos de objetos, 62 explicit, 463 express ao? a ca -verdadeira : a ca o-falsa;, 669 Extens ao, 113 eXtreme Programming, 104 FAQ, 728 fase de pr e-processamento, 637 FIFO, 578 for(in cio;teste;incremento) a ca o;, 669 Framework, 174 framework, 174 Friend, 379 friend, 78 Fun ca o main(), 675 Fun co es, 73, 675 Fun co es friend, 382 Fun co es gen ericas, 598 Fun co es objetos, 613 Fun co es recursivas, 677 Fun co es template, 492 Andr e Duarte Bueno
754 Gabaritos, 489, 505 Generaliza ca o, 112 Generaliza ca o e heran ca, 128 get(), 442 GNU, 53 GNU//Linux, 53 GNU/Linux (Unix), 151 GPL, 52 heap, 477 Heapsort, 604 Heran ca, 74, 335 Heran ca m ultipla, 75, 345, 355 heran ca m ultipla, 127 Heran ca m ultipla virtual, 350 Heran ca simples, 355 Heran cas, 157 heran cas, 127, 157 Heran cas - identica ca o, 127 Hereditariedade, 74 Hist oria de C++, 181 HOWTO, 725 IDE, 151 Identidade, 76 Identica ca o de agrega co es, 125 Identica ca o de associa co es, 122 Identica ca o de classes, 119 Identica ca o de composi co es, 125 Identica ca o de estados, 137 Identica ca o de eventos e mensagens, 133 Identica ca o de heran cas, 127 Identica ca o de pacotes, 116 Identicadores, 193, 197 if, 666 if......else if......else if......else, 667 if.....else, 666 Implementa ca o, 160 Implementa ca o do programa, 106 Impressora, 441 Inclus ao, 113 Inclus ao de arquivos, 637 Inicializa ca o dos atributos, 316 Inst ancia, 63, 76 Instru co es de guarda, 642 Interface, 77, 128, 148 interface, 54, 117 Inverter, 600 Itera ca o, 132, 145 Iteradores, 547 Programa ca o Orientada a Objeto com C++ Iterators, 547 kdevelop, 154 kernel num erico, 55
INDICE REMISSIVO
Liga ca o din amica, 78 Liga ca o est atica, 78 linguagem de modelagem unicada, 85 linha de comando, 55 Linkar, 185 Links, 725 Linux, 53 Literais, 194 locale, 422 Lvalues, 196 M etodos, 73, 267 m etodos, 121, 156 M etodos - identica ca o, 121 M etodos const, 279 M etodos construtores, 313 M etodos de convers ao, 462 M etodos destrutores, 314 M etodos est aticos, 282, 361 M etodos friend, 381 M etodos inline, 284 M etodos n ao virtuais, 361 M etodos normais, 276, 361 M etodos virtuais, 363 M etodos virtuais puros, 367 m odulos, 116 Mac OS System X, 151 Macros, 641 Macros pr e-denidas, 641 Manuten ca o, 172 Manuten ca o do programa, 106 Matem aticos, 603 mecanismo de recupera ca o, 56 Mensagens, 133, 134 Mesclar, 600 Metodologia, 162 Misturar, 600 Modelagem, 81 Modelagem Orientada a Objeto, 49, 81 Modelagem orientada a objeto, 84 Modelo, 81 modelo, 133, 156 Modelo baseado em prototipagem, 102 Modelo de objetos, 119 Modelo din amico, 133 Andr e Duarte Bueno
INDICE REMISSIVO Modelo espiral, 102 Modelo funcional, 142 Modelo incremental, 102 Modelo iterativo, 102 Modelo RAD, 102 Modelo RUP, 103 Modelo selecionado, 105 Modelo sequencial linear, 101 Modelo TMO, 103 Modelo XP, 104 modelos, 101 Modicadores de acesso, 650 modo gr aco, 57 modo texto, 56 Modularidade, 79 Namespace, 241 Necessidade de convers ao, 460 new, 300, 481 Nome dos objetos, 197 Nomes, 193 Nomes de classe, 77 NonVirtual Interface, 253 Novidades e vantagens de C++, 183 NVI, 253 O que e engenharia de software, 99 Objeto, 63 objetos, 61 Objetos din amicos, 299 Objetos fun co es, 613 Objetos identica ca o, 130 Oculta ca o, 70 Open Source Initiative, 53 Operador condicional, 660 Operador de resolu ca o de escopo, 662 Operador decremento, 660 Operador delete, 662 Operador incremento, 660 Operador m odulo, 661 Operador new, 662 Operador size t, 234, 662 Operador sizeof, 662 Operador typedef, 662 Operador v rgula, 661 Operadores, 194, 655 Operadores aritim eticos, 656 Operadores bits, 659 Operadores compostos, 657 Operadores de atribui ca o, 657 Programa ca o Orientada a Objeto com C++
755 Operadores l ogicos, 658 Operadores relacionais, 657 Operadores sobrecarregados, 386 Ordem de cria ca o, 351 Ordem de cria ca o e destrui ca o dos objetos, 325 Ordem de destrui ca o, 351 Ordena ca o, 601 otimiza co es, 157 Pacotes, 79 pair, 583 Palavras chaves, 193 Palavras chaves do C++, 196 Par ametros por c opia, 272 Par ametros por ponteiro, 273 Par ametros por refer encia, 272 Persist encia, 76 Pesquisar, 600 Pilhas, 604 Plataforma de programa ca o, 149 Plataformas, 147 plataformas, 149 Polimorsmo, 75, 361, 365 Ponteiro de fun ca o, 689 Ponteiro para m etodos, 690 Ponteiro para ponteiro, 685 Ponteiro this, 302 Ponteiro void, 684 Ponteiros, 78, 297, 683 Ponteiros const, 303 Ponteiros para const, 303 POO, 61, 64, 156 Preced encia dos operadores, 656 Preenchimento, 598 Proler, 185 programa, 51 Programa ca o em grande escala, 175 Programa ca o estruturada, 63 Programa ca o orientada a objeto, 64 Programas, 51 Projeto do sistema, 105, 147 Projeto orientado a objeto, 106, 156 Propriedades, 73 prot otipo, 117 Prot otipo catch, 472 Prot otipo classe template, 495 Prot otipo const cast, 466 Prot otipo construtor, 314 Prot otipo convers oes, 459 Prot otipo destrutor, 314 Andr e Duarte Bueno
756 Prot otipo dynamic cast, 465, 466 Prot otipo exce co es, 476 Prot otipo fun co es template, 490 Prot otipo heran ca m ultipla, 345 Prot otipo heran ca m ultipla virtual, 350 Prot otipo m etodo convers ao, 462 Prot otipo para construtores e destrutores, 314 Prot otipo para declarar e denir atributos, 259 Prot otipo para declarar e denir classes, 249 Prot otipo para declarar e denir m etodos, 268 Prot otipo para enumera co es, 227, 700 Prot otipo para friend, 380 Prot otipo para heran ca, 335 Prot otipo para heran ca m ultipla, 345 Prot otipo para templates, 490 Prot otipo refer encias, 305 Prot otipo reinterpret cast, 466 Prot otipo sizeof, 234 Prot otipo sobrecarga de operador, 386, 394, 397 Prot otipo static cast, 464 Prot otipo template e argumentos pr e-denidos, 498 Prot otipo throw, 472 Prot otipo try, 472 Prot otipos de sobrecarga, 394 Prot otipos para convers oes, 459 Prot otipo struct, 224, 695 Protocolos, 77, 147, 148 Prototipo delete, 301 Prototipo new, 300 pstream.h, 736 put(), 442 Rapid Application Development, 102 Rational Unied Process, 103 read(), 434 Realiza ca o, 130 Recursos, 147 Redeclara ca o, 340 Redirecionamento, 437 Refer encias, 78, 297, 304 refer encias, 297 Refer encias e dynamic cast, 466 reinterpret cast, 466 Remo ca o, 599 Responsabilidades, 77 Restri co es, 130 Retorno de um m etodo, 271 Reusabilidade, 172 Programa ca o Orientada a Objeto com C++ Reuso, 172 reuso de classes, 172 reuso de m etodos, 173 Revistas, 734 robustes de c odigo, 253 RUP, 103
INDICE REMISSIVO
S mbolos, 193 Sa da aux liar, 441 seekg(), seekp(), 439 Sele ca o de bibliotecas externas, 150 Sequ encia de controle, 476 Sinergia, 79 Sintaxe de Cpp, 193 sizeof, 234, 355 Sobrecarga de M etodos, 293 sobrecarga de m etodos, 78 Sobrecarga de operador, 385 sobrecarga de operador, 78 Sobrecarga de operador como fun ca o friend, 387 Sobrecarga de operador como m etodo membro da classe, 388 software, 51 Software Livre, 52 software livre, 52 Software propriet ario, 52 softwares, 51 static, 652 static cast, 464 std, 242 STL, 539 stl, 541 strings de C++, 447 Superclasse, 77 switch....case, 667 Tecnologia de Modelagem de Objetos, 103 tellg(),tellp(), 439 Templates, 79, 489, 505 Teste, 161 Teste de Software, 161 Teste e depura ca o, 106 throw, 474 Tipica ca o, 76, 237 Tipos, 215 Tipos de programa ca o em C++, 184 Tipos denidos em bibliotecas externas, 228 Tipos derivados, 195 Tipos do usu ario, 223 Andr e Duarte Bueno
INDICE REMISSIVO Tipos e intervalos, 217 Tipos param etricos, 494, 511 Tipos pr e-denidos, 195 Transforma ca o, 602 Trocas, 599 try, 474 Tutoriais, 728 Typedefs, 546 typeid, 236 umbrello, 94 UML, 85, 726 Uni oes, 698 union, 698 Uso de tipos pr e-denidos de C++, 215 Vari aveis, 73 Vis ao desorganizada, 64 Vis ao orientada a objeto, 64 Vis oes da UML, 85 Visual Paradigm, 96 volatile, 651 while (teste)instru ca o;;, 670 Windows, 151 write(), 434 XP, 104
757