Вы находитесь на странице: 1из 149

Programar em C++

PDF gerado usando o pacote de ferramentas em cdigo aberto mwlib. Veja http://code.pediapress.com/ para mais informaes. PDF generated at: Thu, 06 Feb 2014 01:28:45 UTC

Contedo
Pginas
Objetivo Por que C++? Diferenas entre C e C++ Introduo Al, Mundo! Variveis e constantes Ponteiros Vetores Estruturas Operadores Deciso e controle de fluxo Estruturas de repetio Funes Referncias de dados Entrada e sada de dados Entrada e sada de dados 2 Manipulando strings Classes Encapsulamento Herana Polimorfismo Friend Classes internas Sobrecarga de operadores Alocao dinmica de memria Excees Namespace Templates Containers Compilao Lista de Palavras Reservadas do C++ Lista de Sequncias de Escape Tabela ASCII C++11 1 1 2 3 6 12 18 20 29 34 37 42 49 51 56 65 80 88 103 106 119 124 126 127 129 136 136 136 138 138 140 141 142 143

Referncias
Fontes e Editores da Pgina Fontes, Licenas e Editores da Imagem 144 145

Licenas das pginas


Licena 146

Objetivo

Objetivo
O livro Programar em C++ tem por objetivo apresentar os fundamentos desta linguagem, de modo que o estudante possa desenvolver diferentes tipos de softwares em alto e baixo nvel para os diversos ambientes existentes, desde aplicaes para GNU/Linux ou Windows at programas para microcontroladores, alm de fornecer a base para os estudos avanados de C++. Por ser um livro especfico sobre a linguagem C++, altamente recomendvel que o leitor tenha conhecimentos prvios sobre a linguagem C. Espera-se que este livro aborde: Aspectos tericos Aspectos prticos Os erros comuns Para tanto cada tpico dever ter uma explicao terica, citar os erros mais comuns e exerccios.

Por que C++?


Imagine que voc deve fazer um programa para fazer a mquina de um pequeno relgio de pulso funcionar, ento voc pensa: Bom, isso pode ser feito com Assembly... Porm, pensando melhor, voc decide mudar de linguagem quando voc pondera. O problema maior que se eu tiver que mudar o processador do relgio, vou ter que refazer o programa. melhor usar linguagem "C". Depois voc termina por avaliar outra possibilidade: Bem, se eu j estou pensando em "C" melhor usar "C++", depois vai ser mais fcil de entender o cdigo, reaproveitar em outras coisas e ainda vai ser mais fcil de expandir para outros modelos de relgio. E assim o que podemos perceber como C++ poderosa, flexvel e abrangente. Ela pode ser usada para programar qualquer tipo de hardware, desde os mais simples at os mais complexos. Alm disso, C++ uma linguagem que gera programas em cdigo de mquina, que funcionam com ou sem a participao de sistemas operacionais no dispositivo. Alguns profissionais afirmam que C++ a linguagem mais poderosa que existe, veja algumas caractersticas dela: um superconjunto da linguagem C, e contm vrios melhoramentos; Deu origem a grandes linguagens como Java e D; a porta para a programao orientada a objetos; C++ pode virtualmente ser efetivamente aplicado a qualquer tarefa de programao; H vrios compiladores para diversas plataformas tornando a linguagem uma opo para programas multiplataforma.

A linguagem C++ utilizada em projetos como: Compiladores; Editores; Ferramentas de programao; Jogos;

Programas de redes. At ao momento foram realizadas 3 grandes revises linguagem:

Por que C++? 1 em 1985; 2 em 1990; 3 em 1998 a que deu origem ao ANSI \ ISO standard a que ficou comummente denominada de Standard C++. Esta verso suportada por todos os compiladores C++ famosos incluindo Microsofts Visual C++, Borlands C++ Builder e GCC. Esta foi revista em 2003. C++ considerada uma linguagem que est entre linguagem de alto nvel (em ingls, high level language) e linguagem de baixo nvel (em ingls, low level language). Dito de outra forma, uma linguagem que est prxima da linguagem humana (linguagem de alto nvel), mas ao mesmo tempo permite estar prximo da maneira como o computador processa, prximo do Assembly (uma linguagem de baixo nvel).

Diferenas entre C e C++


Quem sabe programar em C++, capaz de programar C, devido semelhana entre as linguagens e o fato do C++ ser uma extenso do C. Contudo o C no completamente um subconjunto do C++. Grande parte de cdigo C pode ser perfeitamente compilado em C++, mas existem algumas pequenas diferenas sintticas e semnticas entre as linguagens que tornam alguns trechos de cdigo C vlidos em cdigo C++ invlido, ou cdigos que exibem comportamentos diferentes em cada linguagem. Algumas diferenas bsicas: O C permite a converso implcita entre o tipo de dado void* para ponteiros para outros tipos, algo que o C++ no permite. O C permite que constantes de caracteres sejam inseridas em chamadas de funes com parmetros tipo char*, em C++ preciso declarar o parmetro como const char *; Alm destas pequenas diferenas, C++ tem um conjunto de caractersticas que a torna fundamentalmente diferente de "C". Esse conjunto, torna possvel programar em C++ de um modo totalmente diferente do modo de programar da linguagem "C". O que traz a diferena o modo da orientao na montagem do cdigo. Chamamos o modo de programar em "C" de orientado a procedimentos e chamamos o modo do "C++" de orientado a objetos. Muitas pessoas confundem as coisas quando comeam a programar usando um compilador C++, pois esta linguagem permite programar nos dois modos. Essa uma das caractersticas que a torna mais flexvel. Apesar de C++ permitir programar em modo orientado a procedimentos, podemos dizer que nestes casos estamos programando em "C", usando um compilador C++. Quando usamos C++ programamos em modo orientado a objetos. Devido a estas caractersticas, o C++ permite programar em modo misto, ou seja, escrevendo partes do cdigo orientadas a procedimentos e outras orientadas a objetos. As diferenas entre os dois modos de programar sero esclarecidas nos captulos subsequentes. Por hora nos basta deixar claro que os dois modos so diferentes. Usar estes dois modos de programar ao mesmo tempo uma das facilidades que o C++ permite, enquanto que outras linguagens orientadas a objetos como Java, Eifel, etc, no permitem.
Esta pgina um esboo de informtica. Ampliando-a voc ajudar a melhorar o Wikilivros.

Introduo

Introduo
Pensando no cdigo
Considerando o conjunto de operaes e eventos que nosso programa deve executar temos diversas maneiras de criar o cdigo, porm o mais difcil criar um cdigo eficiente, rpido e compacto. Na verdade, diversos fatores podem interferir nestes aspectos da programao, entre eles, a escolha do compilador, o mtodo de estruturar o cdigo, a orientao do mesmo, etc... Em termos gerais, um cdigo torna-se mais prximo do ideal a medida que suas partes tornam-se mais simples de se analisar e quando todos os processos esto bem definidos e especializados. Quando temos um cdigo que contm muito mais excees do que regras, este precisa de uma reestruturao. Podemos definir C++ como um "superconjunto" da linguagem C, ou seja, uma linguagem com mais funcionalidades que a linguagem C. Embora este seja o ponto de vista de quem j tem um conhecimento da linguagem C, ela muito mais que isto. Podemos mudar completamente a forma de criar o programa quando usamos os recursos avanados da linguagem, as estruturas de deciso (por exemplo, if-else ou switch) podem ser simplificadas e a organizao do cdigo pode ser bem mais globalizada e genrica, possibilitando a reutilizao do cdigo em diversas situaes diferentes. Vejamos como as funcionalidades da linguagem C++ podem ajudar a redefinir os meios de programao que aprendemos com o bom e velho estilo C.

Dois modos de programar


Observando o modo de programar que as linguagens oferecem desde os primrdios da computao, podemos notar vrios mtodos que foram sendo superados e outros que se estabelecem por um momento. O modo de programar mais usual e bem mais difundido conhecido como modelo estruturado sequencial. Em sntese, refere-se a forma de programar onde uma instruo segue a outra numa sequncia que inicia e termina em um fluxo parcialmente "previsvel". A programao estruturada ainda pode ser classificada em dois modos: um orientado a procedimentos e outro orientado a objetos. Os dois podem ser confundidos por quem no tem muita experincia, mas o uso de um ou do outro implica em caractersticas prprias para cada caso. Logo, preciso entender bem os conceitos antes de definir se um cdigo procedural ou orientado a objetos. O modelo sequenciado procedural bem simples de implementar, porm, aumenta a complexidade para tarefas mais bem trabalhadas e sofisticadas. Isto ocorre devido a estrutura do modelo, que exige rotinas cada vez mais extensas. No raramente possvel encontrar rotinas que, em alguns casos, tornam-se comparveis a programas completos, usando como referncia o nmero de linhas de instrues. O uso deste modelo, muitas vezes dificulta a manuteno e expanso do cdigo, caso isto no seja feito de maneira muito bem organizada. O segundo modelo o orientado a objetos. O que significa isso e o que muda no modo de programar, caso o adotemos em vez do modelo anterior? A orientao define o modo de abordar o problema para tentar solucion-lo: O modelo de orientao a procedimentos se preocupa em fornecer meios para resolver o problema sem contabilizar, a princpio, os dados que sero usados durante o processo. O modelo de orientao a objetos se preocupa com os elementos que so necessrios para a soluo de um problema. Sob este ngulo, os dados so os elementos principais na anlise do problema. Este livro traz uma viso dos problemas sob a ptica da orientao a objetos, enquanto que o livro "Programar em C" traz a anlise sob a ptica da orientao a procedimentos. Isto no quer dizer que devamos escolher a orientao a objetos como o modo mandatrio de programao, mas que podemos contar com seus recursos sempre que esta escolha facilite a resoluo do problema. Portanto, cabe sempre uma anlise para definir se o problema melhor

Introduo tratado por uma abordagem orientada a objetos ou a procedimentos.

Um pouco sobre orientao a objetos


A programao orientada a objetos um paradigma de programao que visa organizao, produtividade e sustentabilidade. A apresentao dos conceitos de orientao a objetos bastante abrangente, o que implica na abordagem de diversos aspectos, como modelagem, estudo de performance de modelos, aplicabilidade de tcnicas, estruturao de objetos, otimizao, manuteno do cdigo, entre outros. Por este motivo, nosso objetivo aqui no apresentar a orientao a objetos em sua totalidade. Para um estudo mais detalhado do tema sugerimos o livro POO, que trata especificamente deste tema. O objetivo aqui apresentar como a orientao a objetos se aplica na linguagem C++, porm os conceitos aqui apresentados devem ser suficientes para a estruturao de programas de bom nvel. A ideia principal por traz do modelo de programao orientado a objetos est em transformar entidades do mundo real em identificadores dentro do programa (objetos), trabalhando-os como entidades da linguagem que possuem caractersticas e operaes prprias. Esta abordagem transforma o programa em um meio de simulao de situaes virtuais por meio de entidades de cdigo que tem comportamento predefinido. Esta abstrao uma aliada do programador por permitir idealizar sistemas mais sofisticados de uma maneira bastante intuitiva. Todas as linguagens orientadas a objetos contm os princpios de: Encapsulamento um mecanismo para esconder os detalhes envolvidos no processamento de uma ao. Por exemplo, quando usamos um telefone, no precisamos lidar diretamente com o circuito interno; a interface do telefone cuida desse problema. Polimorfismo Isso permite o uso de uma nica interface uma nica forma de uso para objetos de tipos diferentes; em particular, a mesma interface para objetos de uma classe e objetos de classes derivadas dessa. Herana Como o nome sugere, isso permite que uma classe herde de outra suas caractersticas, podendo tambm introduzir suas prprias ou alterar as caractersticas herdadas. O uso de herana acaba poupando trabalho e melhorando a organizao do cdigo.

Paradigmas da Programao:
Desde o incio da programao, j passamos pelos seguintes paradigmas: No estruturada - exemplos: COBOL, FORTRAN, BASIC (anos 50-60) Procedimental ou Procedural - exemplos: C, Pascal (anos 70) Modular - exemplo: Modula II (anos 80) Abstrao de tipos de dados - exemplo: Ada (anos 80) Programao Orientada a Objetos - exemplos: C++, Java, Delphi (Object Pascal) entre outras. (dcadas 80-90-2000)

Introduo

Objetos
Objeto , genericamente, uma entidade de armazenamento e manipulao de dados. O mesmo deve ser criado para processar os dados que armazena e recebe, sendo sensvel a entradas do programa principal para fornecer as sadas esperadas pelo mesmo. Por estes motivos o objeto deve ser pensado como uma entidade de dados autnoma, encarregada de processar todos os dados que mantm. Da mesma forma que podemos usar tipos de dados nativos da linguagem podemos criar nossos tipos de dados. Na linguagem C podemos criar tipos de dados compostos que chamamos de estruturas, estes so criados com a palavra chave struct. C++ possibilita o uso de estruturas de dados e introduz um novo tipo chamado de classe. Como o nome sugere, uma classe refere-se a um conjunto de caractersticas dadas a um grupo de "indivduos", ou seja, grupo de objetos. Por este motivo, classe a definio de tipo de objeto. Em C++ as classes de objetos so criadas atravs da palavra chave class. Esta nomenclatura usada por muitas outras linguagens de programao mais caracteristicamente restritas a orientao a objetos. Estes aspectos facilitam um pouco o aprendizado por programadores j familiarizados com estas linguagens quando iniciam a programao em C++. O processo de criao de um objeto segue a sequncia: Definir os dados e procedimentos que a classe deve conter; Criar a classe de objetos; Declarar (instanciar) o objeto. A definio de uma classe de objetos deve ser feita de forma a tornar, preferencialmente, todos os dados protegidos de interferncias de cdigos externos ao objeto. Por este motivo um objeto deve ser uma parte do cdigo do programa com uma certa autonomia. Este deve ter controle sobre seus dados e ser capaz de prov-los e lidar com eventos a eles relacionados. Dentro de seu escopo de responsabilidades, a entidade deve essencialmente "ter vida prpria".

Al, Mundo!

Al, Mundo!
Ol mundo!
comum, no aprendizado de uma linguagem de programao, que seu primeiro programa faa com que o computador exiba "Ol mundo!". Na linguagem C++ este primeiro programa j introduz muitos conceitos sobre a linguagem. Veja o cdigo do nosso primeiro programa: #include <iostream> using namespace std; int main () { cout << "Ol mundo!"; return 0; } Assim como para comear a dirigir no necessrio saber toda a mecnica do carro, para programar no precisamos logo de incio nos prender a todos os detalhes. No programa acima, vamos dar ateno apenas ao contedo que se encontra entre as chaves: { cout << "Ol mundo!"; return 0; } cout << "Ol mundo!"; A palavra cout vem de Console OUT (sada do console), onde geralmente temos a sada no monitor. O cout seguido do operador << e da frase que se quer informar entre aspas: "Ol mundo!", intuitivamente, isso nos leva a ideia de que a sequncia de caracteres ser levada ao cout. return 0; Este comando termina o programa, o estudaremos melhor no captulo sobre funes e retornos. ATENO: Caso seu sistema operacional seja o Microsoft Windows, voc deve adicionar imediatamente antes de return 0; a seguinte linha: system ("pause"); A funo system() executa um comando do Windows. como se o prprio usurio digitasse pause no prompt do MSDOS. Este comando deve ser evitado, pois diminui a portabilidade do programa, j que pause s existe nos sistemas Microsoft. No entanto, se est usando Windows necessrio adicionar esta linha, caso contrrio o computador escreveria "Ol mundo!" e fecharia o programa antes que pudssemos ler qualquer coisa. Uma forma elegante de lidar com estas peculiaridades do Windows usar predefinies, de forma que o programa seja portvel para qualquer sistema operacional: #if defined(_MSC_VER) // estas linhas sero executadas apenas quando o programa // for compilado por alguma verso do Microsoft Visual C system("pause");

Al, Mundo! #endif Em sistemas parecidos com UNIX, como GNU/Linux ou FreeBSD, pode-se usar um terminal de linha de comando facilmente, pois os mesmos possuem o recurso facilmente acessvel, mesmo quando o usurio est usando a interface grfica. Por isso, para esses sistemas um comando para solicitar pausa ao sistema no necessrio.

Entrada de dados e comentrios no cdigo


Comentrio um recurso muito til em programao. Ele permite que o programador adicione texto ao programa para facilitar o entendimento do programa por parte de outros programadores, ou at dele mesmo. Os comentrios so usados para explicar trechos de cdigo, adicionar clusulas e qualquer texto em geral. Vamos agora para um programa mais completo com entrada de dados e comentrios dentro do cdigo: // Este um comentrio de uma linha /* Este um comentrio de vrias linhas */ #include <iostream> using namespace std; int main () { int x; cout << "Digite um nmero: "; cin >> x; cout << "\nVoc digitou o nmero: " << x << endl; return 0; }

Comentrios no programa
Observemos esta linha: // Este um comentrio de uma linha Esta uma linha de comando para o preprocessador (ou precompilador). O que o preprocessador? Durante o processo de montagem do programa em formato binrio existem trs fases principais: O preprocessamento, a compilao e a fase de ligao (link). O preprocessador um programa invocado pelo compilador para remover comentrios e substituir certas partes do programa conforme a necessidade do cdigo criado pelo programador. O preprocessador faz algumas alteraes no texto fonte, que basicamente consistem em eliminar pedaos de cdigo e/ou substitu-los por outros (copy-paste). Enfim, o mesmo altera o cdigo fonte contendo comandos iniciados com # e outros comandos especficos, por outro cdigo sem comandos de preprocessamento, puramente em linguagem C++.

Al, Mundo! Ao analisar o cdigo, o preprocessador encontra a sequncia // e vai eliminar o texto que est a seguir at ao fim da linha. Mais uma forma de adicionar comentrios: /* Este um comentrio de vrias linhas */ A linguagem C++ permite tambm fazer comentrios por mais do que uma linha. Chama-se comentrio por bloco e o que faz eliminar tudo o que encontrar entre a sequncia inicial /* e o final */. A vantagem de termos esta possibilidade poder comentar o nosso cdigo. Existem algumas regras de boa conduta para comentrios que foram criadas por pessoas que j tm muito tempo nisto: Uma criar logo no topo um comentrio a dizer o que o nosso programa, e o que faz numa forma geral; Outra fazer comentrios a cada funo que aparece no cdigo a explicar; Outra comentar uma linha mais obscura, mais difcil de entender, que no bvia; A outra no comentar tudo. O comentar deve ser para sobressair. Esta ltima regra pode ser esquecida quando o programa didtico, neste caso pode-se usar o programa como texto comentado.

Incluindo cabealhos
#include <iostream> O smbolo # uma chamada de ateno ao compilador a dizer que aquela linha para o preprocessador, depois temos o "include" (que basicamente diz para incluir cdigo). Incluir o qu? Deve incluir o ficheiro/arquivo iostream. (in+out+stream, "fluxo de entrada e sada", padro) (na maioria das vezes, como entrada padro temos o teclado e como sada temos o monitor) (este ficheiro/arquivo contm declaraes das funes e definies que o nosso cdigo fonte ir necessitar) Este cdigo que ser includo chamado de cabealho devido a uma caracterstica evidente, o fato de ser cdigo de declarao inicial do programa, que deve estar no topo do arquivo/ficheiro. Existem outros arquivos (ficheiros cabealho), o iostream para fluxos de entrada e sada, mas temos muitos mais para matemtica, manipulao de tempo, tratamento de caracteres, etc... Na maioria das vezes, os arquivos de cabealho fazem parte de uma biblioteca. Podemos ver na parte dos anexos, algumas bibliotecas que existem juntamente com as funes de cada uma. Ns prprios podemos criar uma biblioteca com cdigo e nosso prprio cabealho. E at podemos comprar bibliotecas existentes comercialmente, atravs de empresas especializadas em desenvolvimento, que tambm tero seus arquivos/ficheiros de cabealhos. Mas, o que so bibliotecas? So arquivos com um conjunto de cdigos que algum fez antes. As que enunciamos antes so as "standard", so aquelas que tm as funcionalidades bsicas, pertencentes aos padres da linguagem. Repare-se que precisamos da biblioteca at para escrever (no ecr)/(na tela) (stream + out) que nos permite utilizar o cout. O ficheiro/arquivo iostream est envolvido em < >, isto significa que o preprocessador deve procurar o ficheiro/arquivo no stio/diretrio usual (que onde o compilador usa como padro para os "includes"). Se tivssemos o ficheiro/arquivo iostream envolvido em "" significaria que o preprocessador deveria procur-lo dentro de uma lista de diretrios de incluso, "includes", iniciando pelo diretrio atual.

Al, Mundo! As bibliotecas so compostas por 2 partes: um ndice de todas as funes e definies e declaraes, o cabealho, e depois a definio de todas as funes existentes no ndice, arquivos de cdigo. As diretivas de preprocessamento no terminam com o ponto e vrgula como nas instrues.

Namespace
using namespace std; Observando esta linha, alguns tradicionais programadores em linguagem C, tm uma novidade: namespaces so espaos de nomes dentro do cdigo, eles funcionam, entre outras coisas, como um meio de evitar duplicao de nomes dentro de um projeto extenso, que geralmente contam com inmeros arquivos. O C++ usa os namespaces para organizar os diferentes nomes usados nos programas. Cada nome usado no ficheiro/arquivo biblioteca "standard iostream" faz parte do "namespace" chamado de std. O objeto de sada padro, cout, est definido dentro do "namespace" std, ele um objeto da classe "ostream" "output stream", para acess-lo temos que referenci-lo como "std::cout". Para evitar que tenhamos que informar "std::" todas as vezes que precisarmos usar os recursos deste "namespace", podemos informar que estamos usando-o dentro do arquivo atual, conforme vemos na linha declarada no incio deste tpico. O "namespace" permite que as variveis sejam localizadas em certas regies do cdigo. Declarar o "namespace std" permite que todos os objetos e funes da biblioteca "standard input-output" possam ser usados sem qualquer qualificaes especficas, desta maneira, no mais necessrio o uso de "std::". Este um conceito avanado que podemos explorar mais, vamos deix-lo para depois.

Funo "main"
int main(){} Como na linguagem C, a funo principal de entrada do programa a partir do sistema operacional a funo main. Por isso mesmo ela obrigatria em qualquer programa. Se no existisse uma "main function", no haveria entrada para que o sistema iniciasse o programa. Todas as funes so declaradas e usadas com o operador ( ), assim que o compilador reconhece que estas so funes. A ideia de ter funes permitir o encapsulamento de uma ideia ou operao, dar um nome a isso e depois chamar essa operao de vrias partes do programa simplesmente usando o seu nome. As funes declaradas como membros de uma classe de objetos podem ser chamadas de mtodos. Do ponto de vista funcional, um cdigo dentro de uma funo executa operaes em outra parte do programa, que no aquela de onde foi chamada, por este motivo as mesmas contam com um mecanismo de passagem de dados, ao declarar uma funo indicamos quais os dados que entram e o que ela deve fornecer a quem lhe chamou. Pode-se dizer que, tal qual uma funo matemtica, a funo em C/C++ poder ser substituda, depois de sua execuo, pelo valor que ela retorna, este valor ser especificado antes do nome da funo na declarao da mesma, conforme vemos no incio deste tpico. O int significa que a funo vai retornar um inteiro. Existem outros tipos de dados como, por exemplo, os seguintes: int que a abreviatura de inteiro; char que a abreviatura de caratere; float que a abreviatura de "floating point number", ou seja, uma representao para nmero real. Vejamos um exemplo: Quando criamos uma funo soma, obviamente s para ilustrao pois isso no necessrio, podemos fazer: int soma(int a, int b) { return a + b; }

Al, Mundo! Agora imagine que tenhamos que somar 2 e 3, colocando o resultado em outra varivel chamada valor, para isto faremos: valor = soma(2, 3); Primeiro analisamos qual o resultado e depois substitumos a funo pelo valor que ela retorna: valor = 5; Simples, no? ; - Final de sequncia de instrues O ponto e vrgula funciona como ponto final, separa as instrues e contextos. Repare que apenas as funes, ou melhor, as definies de funes e as diretivas de preprocessamento que no tm o ";" importante notar que o cdigo poderia ser todo escrito quase numa linha tipo: int main (){int a; cout << "Hello world! Digite um nmero:\n"; cin >> a;cout << "Voc digitou o nmero: " << a<<"\n";return 0;} realmente o ";" que faz a terminao das instrues. Ao encontrar as chaves "{}", o compilador reconhece como um delimitador de bloco, ou "body", corpo. O corpo de uma funo ou bloco de cdigo comea com "{" e termina com "}", como temos as instrues agrupadas, j no h necessidade de colocar o ";" no final para indicar onde o fim do bloco. No nosso exemplo existem 2 instrues no corpo da funo. As instrues so executadas por ordem: do topo at ao fim a menos que existam funes que alterem o fluxo da leitura ou que existam cdigos de controle de execuo "execution control codes", que alteram o caminho de execuo.

10

Entrada e sada (cin/cout)


cout << "Hello world! Digite um nmero:\n"; (c+out) Podemos utilizar este objeto porque pusemos o header e o namespace std. As informaes sero direcionadas atravs do iostream, um subsistema de entrada e sada da biblioteca padro. O que este objeto nos permite enviar o que temos entre aspas para a sada (out), que o monitor neste caso. Quem j conhece a linguagem C, certamente est familiarizado com os streams da biblioteca padro, o stdin, o stdout e o stderr... A linguagem C++ implementa os mesmos dispositivos sob a forma de objetos. O cout envia dados para o "standard output device", que usualmente o monitor, a abstrao do elemento de sada padro observada na presena de um objeto que representa a sada fsica de dados para o meio externo. Observa-se que temos o operador <<, neste caso podemos verificar mais uma das funcionalidades da linguagem, pois este operador usado para deslocamento de bits na sua funcionalidade padro, neste caso a sua funo foi substituda por outra, transferir os dados a sua direita para o "output stream" do seu lado esquerdo. O cout um objeto da biblioteca "standard C++" que tem como uma de suas funes imprimir strings no "standard output" (que normalmente o/a ecr/tela). Da mesma forma que podemos formatar o texto enviado a sada padro na linguagem C, tambm podemos faz-lo com os objetos do C++, por exemplo, se acrescentssemos "<< hex <<" entre uma varivel e a sada: cout<< hex << n; O resultado seria impresso em hexadecimal; Para entrada de dados temos: cin >> a;

Al, Mundo! O que esta linha faz colocar o valor que foi digitado numa rea de memria que foi chamada de "a". Da mesma forma que o cout existe para sada de dados, temos outro objeto para entrada atravs do teclado, este objeto chamado de Console IN - cin, seguindo a mesma analogia. Observe que o operador >> usado para dar ideia de que os dados esto vindo do cin para a varivel "a". cout << "Voc digitou o nmero: " << a << "\n"; Aqui voltamos a utilizar o objeto cout primeiro para imprimir no/na ecr/tela a frase "Voc digitou o nmero: ", depois vai buscar o valor que est naquela rea de memria a que chamamos de "a" e por fim coloca o fim de linha atravs de "\n", em C++ podemos usar um finalizador de linha chamado endl, o uso do mesmo mais eficiente pois descarrega os dados do stream logo aps a finalizao da linha.

11

funo system("pause")
system ("pause"); A maioria dos compiladores quando esto executando em modo grfico fecha o console de sada assim que o programa finaliza. Isto impede que possamos ver o que aconteceu, principalmente quando o programa contm apenas umas poucas instrues. A funo system(), faz parte do padro da linguagem C, ela executa uma chamada de sistema, ou seja, ela passa um comando para o sistema, que neste caso "pause", como j informamos no incio deste captulo, este comando destinado a sistemas da Microsoft. Coloquei esta linha para que o programa no finalizasse sem que pudssemos ver uma janela com o resultado, se no o fizesse a janela abriria e fecharia sem que pudssemos ver o aconteceu durante a execuo do programa. Em sistemas como GNU/Linux, FreeBSD, Solaris, etc... temos acesso a terminais de console e compiladores em linha de comando, assim basta compilar o programa sem esta linha e depois execut-lo, para ver o resultado.

Retornando valor
return 0 Faz com que a funo retorne o valor zero, como esta funo a principal do programa, por onde o sistema operativo/operacional iniciou a execuo do mesmo, este retorno recebido pelo sistema, comum que valores diferentes de zero sejam interpretados como erro do programa. Esta instruo manda retornar o valor zero para o sistema operativo/operacional (Windows, Unix, ...). Este zero representa a dizer que o programa finalizou normalmente. Pode acontecer que o programa no finalize como seria de esperar, ele tem um crash (ou porque ficou com falta de memria.). O sistema operativo/operacional necessita de lidar com estas terminaes anormais de uma forma diferente das normais. Por isso que o programa diz ao sistema operativo/operacional que terminou normalmente. Questo: porque que o sistema operativo necessita de saber que o programa terminou bem?

Variveis e constantes

12

Variveis e constantes
Constantes
Compatvel com a linguagem C, o C++ mantm as constantes bsicas e introduz algumas novas funcionalidades possibilitadas pelo modificador const. O uso do modificador const tem duas funes principais: 1. Resguarda da inviolabilidade de valores apontados por ponteiros; 2. Auxlio na compreenso das caractersticas de funes, durante a implementao.

Simblicas
Constantes simblicas podem ser criadas com as diretivas do preprocessador #define. Neste modo os valores, de fato, no so interpretados imediatamente pelo compilador, antes so identificados e substituidos pelo preprocessador no estgio anterior compilao. Por exemplo: #define BUFFER_LENGTH 2048 ... ... ... char data[BUFFER_LENGTH]; Observe que o valor 2048 ser usado logo abaixo no cdigo, depois que o preprocessador substituir a constante simblica BUFFER_LENGTH pelo valor que lhe foi atribudo. Note que as constantes so escritas com todas as letras maisculas, isso no uma regra, mas ajuda a identificar o que constante simblica dentro do programa, sendo adotado pela maioria dos desenvolvedores como uma boa prtica de programao. Neste caso, podemos definir valores simblicos compostos, por exemplo: #define BUFFER_LENGTH 2048 #define N_BUFFERS 100 #define MASTER_LENGTH ( BUFFER_LENGTH * N_BUFFERS ) ... ... ... char screen[MASTER_LENGTH]; Os valores podem ser simblicos em formato de cdigo, o que permite criar programas com melhor legibilidade. Para isso podemos colocar expresses com funcionalidades bem definidas substitudas por nomes que as identifiquem. Por exemplo: float a[3]; #define PRINT_VECTOR cout << a[0] << " , " << a[1] << " , " << a[2] << endl ... ...

Variveis e constantes

13

PRINT_VECTOR; Desta forma, todas as vezes que quisermos mostrar o valor do vetor de trs coordenadas podemos usar a constante PRINT_VECTOR.

Literais
Constantes literais podem ser declaradas da mesma forma que na linguagem "C", ou seja, podemos definir valores fixos em qualquer parte do programa, expressando-os diretamente no cdigo atravs de seu valor significativo. Por exemplo, podemos definir nmeros: 256 //decimal 0400 //octal 0x100 //hexadecimal Tambm podemos definir valores para caracteres ou cadeias de caracteres, como segue: 'a' // um caractere "abc" // uma cadeia de caracteres "\xF3\x23\x12" // uma cadeia de caracteres representada por seus valores em hexadecimal Temos ainda a possibilidade de declarar constantes compostas por valores e operadores: (4.23e14 * (12.75 + 12976.18/36)) // constante composta

Enumeraes
Valores enumerados so muito recorrentes nos ambientes de programao, por isso podemos contar com a declarao de enum em C++ tambm, o que segue a mesma sintaxe que temos em "C": enum seq {A,B,C,D}; seq x; ou ainda: enum nomes {LANY=100,SANDRA=200,MARCIA=300,RODRIGO=400}; nomes x; Porm, observamos uma diferena: a palavra enum pode ser dispensada na declarao da varivel, enquanto que em C obrigatrio,apesar desta pequena diferena a funcionalidade do recurso a mesma, ou seja, pode-se definir variveis que assumem estritamente os valores presentes na declarao de enumerao. Este recurso torna-se til na padronizao de valores a serem usados como entrada de funes, por exemplo. Pode ser considerada como uma funcionalidade mnemnica, seu uso no altera o cdigo final caso modifiquemos o programa para que use variveis inteiras ou strings de mesmo valor do enum. A seguinte sintaxe: seq x = 3; No permitida, mesmo que o valor presente no enum seja avaliado como 3 pelo compilador em tempo de compilao. Isso pode parecer confuso, mas lembre-se de que os valores sero atribuidos pelo compilador, logo isso

Variveis e constantes evita que o mesmo programa seja compilado em ambientes diferentes e tenha comportamento diferente.

14

Variveis
As variveis no C++ podem ser usadas da mesma forma que na linguagem "C", porm algumas poucas diferenas podem ser destacadas, principalmente aquelas que trazem linguagem C++ caractersticas prprias da orientao a objetos.

Tipos
Como na linguagem "C", os tipos nativos do compilador em uso so referenciados por: char int float double Que correspondem a nmeros com tamanho relativos, com os significados respectivos: caractere, inteiro, ponto flutuante e ponto flutuante de dupla preciso. De qualquer forma a extenso dos mesmos depende da mquina que se pretende programar. Considerando que nem sempre teremos que programar apenas computadores, poderemos ter extenses bem distintas dependendo do hardware a ser programado, por exemplo, computadores domsticos tipicamente tem processadores de 32 ou 64 bits hoje em dia, enquanto que dispositivos embarcados podem ter processadores de 8, 16 ou 32 bits. Portanto, o compilador para cada caso atribui faixas diferentes para cada tipo em cada situao. A linguagem C++ introduz o tipo bool, que representa o valor booleano, falso ou verdadeiro, o que no existe na linguagem "C", porm seu tamanho na memria depende da capacidade de otimizao do compilador usado. Tipicamente os compiladores para computadores usam uma varivel do tamanho de char para representar o valor, o que poderia ser considerado um desperdcio, mas devido abundncia de memria no chega a ser inadequado. Porm em sistemas pequenos h compiladores que armazenam o valor booleano em apenas um bit. Obviamente, se o processador possuir recursos de manipulao de bits isso muito til e pode ser usado como um fator de melhoria da qualidade do software desenvolvido. Em outros ambientes, onde a manipulao de bits traga prejuzo para o desempenho usa-se a estratgia padro de desperdiar um pouco de espao em favor de uma agilidade maior nas operaes. Portanto, embora as variaes de utilizao do espao sejam muitas, o compilador sempre far a mais apropriada para cada ambiente de utilizao da linguagem.

Modificadores
O C++ conta com os modificadores de amplitude (short,long) presentes na linguagem "C" e modificadores de acesso, alguns exclusivos do C++, que esto diretamente ligados a caractersticas da POO (programao orientada a objetos). Desta forma descreveremos apenas os tipos relevantes exclusivamente para a programao na linguagem escopo do livro presente sem nos aprofundarmos na teoria por trs dos mesmos. A prtica do uso dos mesmos melhor indicada como meio de aprofundamento do tema. Assim contamos com os modificadores da linguagem "C": static short long unsigned signed

Variveis e constantes const A linguagem C++ introduz um novo modificador chamado const, que tem comportamento variado dependendo do local onde est sendo declarado. Sua funo, basicamente, estabelecer um vnculo entre declarao e obrigatoriedade da coerncia no uso do smbolo declarado. A princpio, quando declaramos uma constante com este modificador fazemos com que seja obrigatrio o uso do smbolo de forma que o mesmo no possa ter seu valor alterado. Assim, se fizermos: const int x = 4; O inteiro x no poder deixar de ter valor igual a 4. Qualquer tentativa de modificar o valor da constante ao longo do programa ser reportada como erro pelo compilador. Porm podemos considerar esta funcionalidade como bvia e trivial, ainda temos o uso do modificador de uma forma mais proveitosa, na passagem de parmetros para funes, por exemplo: void inhibitX(const int *x) { ... ... BASEADDRESS = z*((*x) - 23p*71); ... ... } Neste caso, a funo acima recebe um valor inteiro atravs de um ponteiro, que no obrigatoriamente precisa ser constante no escopo fora da funo, porm dentro da mesma a varivel ser constante. Fazendo este simples procedimento teremos como fazer com que um smbolo seja varivel fora da funo e constante dentro da mesma, de forma que dentro do escopo da mesma s faamos leituras do seu valor. O artifcio cria duas consequncias importantes: a primeira a melhor legibilidade do cdigo, visto que ao usarmos uma funo teremos certeza de que os valores no sero alterados dentro da funo; a segunda que poderemos evitar erros inadvertidos de atribuio de valores varivel quando da construo da funo. volatile Uma varivel "voltil", como a prpria expresso sugere, uma varivel que pode ser modificada sem o conhecimento do programa principal, mesmo que esta ainda esteja declarada dentro do escopo onde o programa est sendo executado. Isso est relacionado, principalmente a processos concorrentes e "threads", estes podem alterar o contedo da varivel em eventos fora da previsibilidade do tempo de compilao. Em outras palavras, o compilador no pode prever com segurana se pode otimizar trechos de programa onde esta varivel se encontra. A palavra reservada volatile destinada as situaes onde uma varivel pode ter seu valor alterado por fatores diversos, e portanto, no pode ser otimizada. Usando-a o programador informa ao compilador que no deve interferir na forma com que o programa foi escrito para acesso a esta varivel. Desta forma impede que erros inseridos por otimizao estejam presentes na verso final do executvel. O uso desta palavra implica em mudana no comportamento do compilador durante a interpretao do cdigo. As classes de objetos do tipo volteis s podero ser acessadas por rotinas que declarem aceitar como entrada dados volteis, da mesma forma que apenas objetos volteis podem acessar variveis volteis. Esta "amarrao" faz com que o uso de tais variveis se torne mais seguro. Podemos declarar variveis volteis da seguinte forma: volatile int x;

15

Variveis e constantes Enquanto que para funes que acessam tais variveis teremos consequncias visveis na montagem do cdigo, por exemplo, se tivermos o seguinte trecho de programa: int x = 1265; void main_loop() { while( x == 1265) { // fazer alguma coisa } } Poderemos ter uma otimizao gerada pelo compilador como segue: int x = 1265; void main_loop_optimized() { while( true ) { // fazer alguma coisa } } Considerando que em um programa que foi desenhado para ambiente multitarefa isso no pode ser considerado verdadeiro, pois o programa pode estar esperando que uma das tarefas modifique o estado da varivel para prosseguir seu curso, a otimizao acima ser um desastre, uma vez que a funo acima jamais ser encerrada. Para evitar isso fazemos: volatile int x = 1265; void main_loop() { while( x == 1265) { // fazer alguma coisa } } E o compilador no poder mais avaliar que o valor de x pode ser otimizado para o valor corrente, pois informamos na declarao que o valor da varivel pode ser alterado sem seu conhecimento. Desta forma o mesmo no alterar o algortmo e far o teste da varivel dentro do while.

16

Variveis e constantes

17

Nomeando tipos
A linguagem "C" possui recursos de nomeao de tipos simples e compostos atravs das palavras chaves typedef e struct. Adicionada a estas o C++ acrescenta a palavra chave class. Vejamos como devemos definir um novo tipo atravs desta palavra chave. A palavra class atribui a um conjunto de tipos de dados o estado de modelo de objeto. Este conceito fundamental para o modo avanado de programar usando o C++. Com este identificador declaramos objetos, da mesma forma que declaramos estruturas. Uma classe pode ser definida em um cabealho "header", da seguinte forma:
class nome_da_classe { <tipo_1> variavel_1; <tipo_2> variavel_2; . . . <tipo_n> variavel_n; ----<tipo_n> nome_funcao ( <tipo_1> variavel_1, <tipo_2> variavel_2, <tipo_3> variavel_3 ...); };

O mais interessante de observar a presena de uma funo dentro da declarao acima. Ento poderamos perguntar: Por que colocar uma funo dentro de um tipo? A resposta simples: Para manipular os dados dentro do tipo! No apenas por esta caracterstica, mas por vrias outras que aboradaremos nos captulos seguintes, o tipo class extremamente flexvel e poderoso. importante ressaltar que em C++ a declarao do identificador: enum, struct, class, etc... dispensado quando se declara uma varivel ou objeto para o referido tipo. Desta forma podemos ter tambm as seguintes declaraes como vlidas, alm do uso padro da linguagem "C": struct data{ int a; int b; int c; }; class object{ int a; char b; long w; float p; void getData(); }; ... ... ... ... void func() { data x; object y;

Variveis e constantes ... ... y.getData(); } Como podemos ver na funo acima se a varivel x for declarada para uma estrutura data o uso da palavra struct no obrigatrio, assim como tambm no o para outros tipos de dados compostos.

18

Ponteiros
Ponteiros
Em linguagem "C", podemos definir variveis ponteiro, ou seja, variveis que armazenam o endereo de outras variveis. Este recurso largamente explorado pela linguagem, embora que deva ser usado com cautela por iniciantes devido ao seu poder destrutivo. Como linguagem "irm mais nova" o C++ tambm permite o uso de ponteiros, o que a distingue de muitas outras linguagens orientadas a objeto. Embora seja muito difundida a idia da criao de linguagens que no suportem acesso a ponteiros, basicamente pressupondo que todos os programadores so inexperientes, a falta deste recurso limita as capacidades de interao de programas com o hardware. Em outras palavras, a falta de um meio de manipular ponteiros faz a linguagem limitada ou dependente de fabricantes de bibliotecas que acessem o hardware. A disponibilidade do uso de ponteiros em C++ agrega um poder a mais ao conjunto da linguagem, porm implica em necessidade de cautela na elaborao de programas que usam deste recurso. Certamente, nem todos os programadores precisam ser considerados inaptos, a priori, atravs da supresso ou insero de complicadores de recursos criados explicitamente para for-los a no usar dos recursos. Por isso, a linguagem C++ disponibiliza o recurso para quem deseja utiliz-lo e tambm apresenta diversos outros recursos que so alternativas ao uso de ponteiros quando eles no so imprescindveis.

O operador *
O operador *, chamado de apontador, funciona em C++ da mesma forma que em C. Considerando que tenhamos uma varivel ponteiro p: Em p armazena-se o endereo de memria que queiramos manipular. Na maioria das vezes obtemos o endereo de outra varivel e colocamos em p; Se p um ponteiro, *p o valor apontado por p, ou seja, o valor que est armazenado no endereo de memria que queremos ler ou alterar. Na declarao de variveis, uma varivel declarada com * um ponteiro. Exemplo: int *px; Muitas vezes, iniciantes podem se sentir confusos porque quando declaramos um ponteiro usamos o * e quando atribumos endereos a ele no usamos o *. A conceituao bsica a seguinte: Declaramos o ponteiro com *, para que o compilador identifique que a varivel um ponteiro; Usamos o ponteiro sem *, para acessar o endereo que ele aponta na memria; Usamos o ponteiro com *, para acessar o valor do dado armazenado na posio de memria;

Ponteiros

19

O operador &
Na linguagem "C", o operador & tem duas funes bsicas, funciona como operador da funo lgica AND e como operador de leitura de endereos. Para operaes com vetores, isso usado da seguinte forma: int a = 12; int *pa; ... ... pa = &a; ... ... *pa = 100; Ou seja, declaramos a varivel a, depois declaramos um ponteiro pa, atravs do operador & obtemos o endereo de a e atribumos o valor 100 varivel usando o ponteiro ao invs da varivel a. Desta forma alteramos o valor de a indiretamente. Um outro uso de & (que no tem similar em "C") pode ser visto mais adiante, em ../Referncias de dados/, mas, para isto, necessrio estudar o que so ../Funes/.

O ponteiro "this"
Imagine que tenhamos criado um objeto qualquer de uma classe X, se quisermos ter acesso ao ponteiro que contm a posio de memria onde est armazenado este objeto basta chamar o ponteiro "this". O ponteiro "this" uma das caractersticas dos objetos em C++ e algumas outras linguagens que suportam orientao a objetos. Ele um membro inerente a todos os objetos que instanciamos em programas escritos em C++. Faremos uma breve explanao a respeito de objetos para esclarecer este tpico. Objeto so parecidos com estruturas, uma diferena bsica que estes possuem "habilidades especficas" representadas por funes que esto dentro do seu escopo. Vejamos um exemplo: struct Data { int x,y; int get_x(){ return x;} int get_y(){ return y;} int set_x(int a){ return x=a;} int set_y(int b){ return y=b;} }; Observe que a estrutura acima apresenta dois inteiros e duas funes para cada um deles, uma que atribui o valor e outra que l o valor de uma das mesmas. Detalhes das implicaes a respeito desse modo de operar os valores sero dados nos captulos seguintes que tratam de objetos. Por ora vamos nos ater a um conceito fundamental importante para a noo de ponteiros em C++, a identidade de um objeto. Veja, temos uma estrutura de dados que est na memria, os dados esto l (variveis x e y), porm as funes no estaro l, pois se tivssemos que copiar uma funo para cada estrutura que crissemos o programa tomaria um tamanho monstruoso. O que se faz apenas guardar o endereo da estrutura em um ponteiro especial, o ponteiro this. Assim, o compilador poder criar uma nica cpia de funo para todas as estruturas que criarmos e depois quando a funo quiser manipular os dados de uma estrutura em particular, o far atravs do ponteiro this. Examinemos os detalhes mais de perto... Digamos que instanciemos um objeto "A" da classe Data:

Ponteiros Data A; A.set_x(2); A.set_y(7); Para acessar estas funes o compilador far: Data A; A.set_x(2); // { Data *this = &A; // return this->x = 2; // } A.set_y(7); // { Data *this = &A; // return this->y = 7; // } Desta forma podemos perceber como diferentes conjuntos de dados podem ser manipulados pela mesma funo. Quando declaramos uma funo dentro de uma estrutura de dados esta rotina recebe um ponteiro com o endereo do conjunto de dados que deve tratar toda vez que for invocada pelo programa. Assim, sempre acessar os dados atravs deste ponteiro, o this. Como todos os objetos precisam ser identificados por esse ponteiro, ele definido para qualquer objeto com o mesmo nome: this.

20

Vetores
Vetores e Matrizes
Faamos uma pequena reviso de conceitos: Vetores e matrizes so variveis compostas homogneas, ou seja, so agrupamentos de dados que individualmente ocupam o mesmo tamanho na memria e so referenciados pelo mesmo nome, geralmente so individualizadas usando-se ndices. Vetores distinguem-se das matrizes apenas pela caracterstica de ter dimenso (1 x n) ou (n x 1), essencialmente vetores so matrizes linha ou matrizes coluna. Em linguagem "C" vetores e matrizes so usados abundantemente para compor estruturas de dados necessrias para composio de diversos recursos. Esta usa, mais explicitamente, vetores de caracteres para definir cadeias de texto, o que conhecido como o mais trivial uso de vetores. Alm deste recurso, o "C" tambm define meio de criao de matrizes tipo (n x m), provendo, desta forma os recursos necessrios para criao destes conjuntos de dados. A linguagem "C++" suporta os mesmos recursos e permite a criao de matrizes de objetos. Uma vez que um objeto essencialmente um tipo de dado criado pelo programador, todas as caractersticas bsicas legadas aos "tipos" em geral so observados nos tipos criados (classes de objetos).

Vetores

21

Vetores
Os vetores em C++ seguem a mesma notao da linguagem "C", via de regra declara-se o tipo seguido de um asterisco. Para acessar o valor apontado pela varivel usa-se um asterisco de forma semelhante, como pode ser visto no trecho de cdigo abaixo:
int *x; int a = 3; x = &a; cout <<" O valor do contedo da posio 0x"; // O valor da posio 0x23A0209112

cout << hex << x << "de memria " << *x << endl; // de memria 3

Matrizes
Podemos imaginar que uma matriz um conjunto de vetores que ocupam uma determinada rea de memria referenciada por um nome comum. Matrizes de tipos primitivos so conseguidas atravs de associaes do operador [ ], como por exemplo: char A[32][16]; int B[12][26][10]; Definindo nossas classes de objetos poderemos declarar matrizes de objetos: class Record { int D; float X,Y; char desc[12]; public: Record(); void addFData(float A, float B); float getFDataX(); float getFDataY(); ... ... ... }; void function() { Record A[32][16]; ... ... ... Ou seja, podemos adotar a mesma sintaxe para criar matrizes de objetos. Este procedimento pode ser usado com o cuidado de se avaliar antes a quantidade de memria disponvel para que a matriz no ultrapasse esse limite fsico, muitas vezes delimitada pelo hardware ou pelo sistema operacional. Lembremos que, um objeto precisa do espao

Vetores equivalente a soma de suas variveis internas para ser alocado na memria.

22

Declarando arranjo
Os arrays permitem fazer o seguinte: int a1, a2, a3,.a100; equivalente a ter int a[100];

Ou seja permite declarar muitas variveis de uma forma bem simples, poupa escrita e bastante compreensvel. O nmero que est dentro de brackets [] o size declarator. Ele que vai permitir ao computador dizer quantas variveis a serem geradas e logo quanta memria dever ser reservada. A memria reservada para as variveis vo ser todas seguidas, um int a seguir ao outro H uma forma para no dizer o valor deste size declarator, mas isso apenas acontece antes da compilao, ou seja o compilador que vai fazer esse preenchimento por ns, visualizando o nosso cdigo e contanto os membros que colocmos. Isto um automatismo dos compiladores recentes. chama-se a isto iniciao implcita que vamos ver nesta seco. As variveis geradas pelos arrays vo ser todos do mesmo tipo. Reparem que o valor do size declarator um nmero. literal, ele no vai mudar quando o programa estiver a correr. Por isso quando no soubermos o nmero de elementos o que fazemos? Veja uma tentativa: #include <iostream> using namespace std; int main () { int numTests; cout << "Enter the number of test scores:"; cin >> numTests; int testScore[numTests]; return 0; } Isto vai dar um erro de compilao, porque o array est a espera de uma constante e no uma varivel. H uma maneira de contornar isto que atravs da memria dinmica que vamos dar mais tarde, num capitulo prprio, pois isto vai envolver muitos conceitos.

Constantes
Reparem que h uma diferena entre literais e constantes, apesar de em ambos os casos o valor no alterado durante a execuo do programa, a constant um nome que representa o valor, o literal o valor.

Declarar constantes
exatamente como declarar uma varivel com duas diferenas: 1. A declarao comea com a palavra const. Isto vai dizer ao compilador que uma constante e no uma varivel 2. Teremos de atribuir logo o valor na declarao, ou seja, fazer a iniciao Exemplo: const int numTests = 3; Portanto se tentarmos colocar um outro valor ao numTest, isso vai dar um erro de compilao

Vetores Array index


a[100] composto por a[0], a[1], a[99] ( De a[0], a[1], a[99] existe 100 posies)

23

Pergunta: Porque que o ndex comea em zero e no um? Ou seja temos as 100 posies que pedimos mas o ndex comea no zero e no no 1. A razo disto tem a ver com offset que refere ao valor adicionado para o endereo base para produzir a segunda address. Bem no entendi bem! Eu explico de novo: O endereo (address) do primeiro elemento do array, o mesmo do que o endereo base do prprio array. ah espera a, o que esto a dizer que o endereo do array igual ao do primeiro elemento do array. Assim o valor que teria de ser adicionado, ao endereo base do array, para conseguirmos o endereo do primeiro elemento seria zero. Agora sim, percebi! Erro: Um erro comum esquecer que o index comea no zero, e portanto quando se querem referir ao ltimo elemento, esquecem-se que tm de subtrair uma unidade. O que advm desse esquecimento que podem estar a alterar memria pertencente a uma varivel, instruo,..de um outro programa. Ou seja vai existir violao de dados. Se o array for declarado globalmente em vez de ser localmente, ento cada elemento inicializado ao valor defaut que zero.

Iniciao
Iniciao, se bem se recordam atribuir um valor a uma varivel ao mesmo tempo que declaramos a varivel. Podemos fazer a iniciao de um array de 2 maneiras: 1) explicit array sizing
int testScore[3] = { 74, 87, 91 };

float milesPerGallon[4] = { 44.4, 22.3, 11.6, 33.3}; char grades[5] string days[7] = {'A', 'B', 'C', 'D', 'F' }; = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"};

Pergunta: O que que acontece se dermos mais valores de atribuio do que elementos do array? int a[3] = { 74, 87, 91, 45 }; Isto vai dar um erro de compilao too many initializers Pergunta: O que que acontece se tivermos menos valores do que os elementos int a[3] = { 74 }; No acontece nada simplesmente no temos valores para a[1] e a[2]. Porm em alguns compiladores os elementos no inicializados ficam com os valores defaut, que no caso dos ints 0 no caso dos floats 0.0 e nos caracteres o caractere nulo ("\0"). No entanto se no inicializarmos um dos elementos, os restantes elementos tero de ser no inicializados pois caso contrrio teremos um erro de compilao 2) implicit array sizing int testScore[ ] = { 74, 87, 91 }; float milesPerGallon[ ] = { 44.4, 22.3, 11.6, 33.3}; char grades[ ] = {'A', 'B', 'C', 'D', 'F' }; Aqui o compilador faz o trabalho por ns, conta os elementos e preenche o nmero de elementos

Vetores

24

Caracter array
char name[ ] char name[ ] = {'J', 'e', 'f', 'f', '\0' }; = "Jeff";

Ambas as inicializaes so permitidas. Porm tomar ateno ultima iniciao! Quando colocmos as aspas duplas o compilador acrescenta o "\0" na array que cria! No tem []!! Esta at costuma ser a preferida pelos programadores, ao estilo de strings (Na verdade as strings so arrays de char mas vamos falar disso num capitulo prprio) O char "\0" o escape sequence para caracterer null. Este escape sequence sinaliza ao cout o fim do character array. o ltimo elemento do array preenchido! Se no tivssemos este carcter apareceriam estranhos caracteres a seguir ao "jeff", chamados "caracteres-lixo". (porqu?) Isto no significa que o ltimo elemento deva ser sempre o null carcter

Arrays de vrias dimenses


Podemos ter duas dimenses tipo_da_varivel nome_da_varivel [altura][largura]; como tambm poderamos ter infinitas tipo_da_varivel nome_da_varivel [tam1][tam2] ... [tamN];

Iniciando
float vect [6] = { 1.3, 4.5, 2.7, 4.1, 0.0, 100.1 }; int matrx [3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; char str [10] = { 'J', 'o', 'a', 'o', '\0' }; char str [10] = "Joao"; char str_vect [3][10] = { "Joao", "Maria", "Jose" }; Peguemos no exemplo: int a [2][3]={1,2,3,4,5,6,} Na memria teramos as coisas assim. ou seja os elementos so seguidos e do mesmo tipo
a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 1 2 3 4 5 6

Portanto ter int a [2][3] equivalente a ter int a [6] o nome que se d que diferente. Pergunta: ser pedido espao par 6 ints ou antes um espao com o tamanho de 6 ints? Como ns sabemos que os arrays os elementos tm endereos de memoria consecutivos, por isso, no podem ser pedidos 6 ints, pois se fosse esse o caso, poderia acontecer que eles no ficassem juntos.

Vetores

25

Const Constant arrays


const int daysInMonth [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; Recordar que temos de inicializar quando queremos fazer uma constante array

Atribuir valores ao array


#include <iostream> using namespace std; int main () { int testScore[3]; cout << "Enter test score cin >> testScore[0]; cout << "Enter test score cin >> testScore[1]; cout << "Enter test score cin >> testScore[2]; cout << "Test score #1: " cout << "Test score #2: " cout << "Test score #3: " return 0; }

#1: "; #2: "; #3: "; << testScore[0] << endl; << testScore[1] << endl; << testScore[2] << endl;

Podemos atribuir o valor 1 a 1, mas para poupar escrita de programao melhor utilizar as funes anteriormente revistas como o for #include <iostream> using namespace std; int main () { int testScore[3]; for (int i = 0; i < 3; i++) { cout << "Enter test score #" << i + 1 << ": "; cin >> testScore[i]; } for (i = 0; i < 3; i++) { cout << "Test score #" << i + 1 << ": " << testScore[i] << endl; } return 0; } Ou melhor ainda podemos usar uma constante, para tornar o nosso cdigo mais abstracto. #include <iostream> using namespace std; const int MAX = 3; int main ()

Vetores { int testScore[MAX]; for (int i = 0; i < MAX; i++) { cout << "Enter test score #" << i + 1 << ": "; cin >> testScore[i]; } for (i = 0; i < MAX; i++) { cout << "Test score #" << i + 1 << ": " << testScore[i] << endl; } return 0; } Lembram-se da histria de termos o endereo do array igual ao endereo do 1 elemento do array?
#include <iostream> using namespace std; const int MAX = 3; int main () { int testScore[3] = { 74, 87, 91 }; cout << cout << return 0; } testScore[0] <<"\n"; testScore <<"\n"; //array base e no um elemento particular do array

26

Pois bem vemos que quando mandamos imprimir o array, ele d um endereo. Pois o valor do nome do array o endereo do array.

Arrays como statements de funes


Pegando no programa #include <iostream> using namespace std; const int MAX = 3; int main () { int testScore[MAX]; for (int i = 0; i < MAX; i++) { cout << "Enter test score #" << i + 1 << ": "; cin >> testScore[i]; } for (i = 0; i < MAX; i++) { cout << "Test score #" << i + 1 << ": " << testScore[i] << endl; } return 0;

Vetores } Vamos torn-lo mais modular, escrevendo uma funo para atribuir valores ao array e outa funo para mostrar os valores do array #include <iostream> using namespace std; void assignValues(int[], int); void displayValues(int[], int); const int MAX = 3; int main () { int testScore[MAX]; assignValues(testScore, MAX); displayValues(testScore, MAX); return 0; } void assignValues(int tests[], int num) { for (int i = 0; i < num; i++) { cout << "Enter test score #" << i + 1 << ": "; cin >> tests[i]; } } void displayValues(int scores[], int elems) { for (int i = 0; i < elems; i++) { cout << "Test score #" << i + 1 << ": "<< scores[i] << endl; } }

27

Arrays como argumentos de funes


// arrays as parameters #include <iostream> using namespace std; void printarray (int array[], int length) /*funo com 2 argumentos,um deles um array */ { for (int n=0; n<length; n++) cout << array[n] << " "; cout << "\n"; } int main () { int a[] = {5, 10, 15}; printarray (a,3); return 0; //passo array como argumento

Vetores
}

28

Este exemplo por acaso est muito curioso Pergunta: mas agora deveramos perguntar se neste caso tnhamos uma passagem por valor ou referncia. Quando um array passado para uma funo, a funo recebe no a cpia do array mas invs disso o endereo, address do primeiro elemento do array, que igual ao valor do array (base). Assim todas as modificaes que se efectuarem na funo que foi chamada iro repercutir-se no array passado. Vamos confirmar: #include <iostream> using namespace std; void doubleThem(int a[], int size); int main() { int a; int myInts[10] = {1,2,3,4,5,6,7,8,9,10}; doubleThem(myInts, 10); //passei o array base for (a=0; a<10; a++) { cout << myInts[a] <<\t; } return 0; } void doubleThem(int a[], int size) { int i; for (i = 0; i < size; i++) { a[i] = 2 * a[i]; } }

Estruturas

29

Estruturas
Breve reviso
Conceito
Da linguagem "C" tambm temos o conceito de estrutura, do qual faremos uma pequena reviso agora. Como todos sabemos, nem todos os dados que precisamos usar podem ser agrupados em matrizes. Frequentemente usamos dados de diversos tipos diferentes, com tamanhos diferentes. Para tipos de dados de diferentes tamanhos existem estruturas de armazenamento de dados heterogneos. O especificador struct usado para esta finalidade. Com ele podemos criar tipos que armazenam dados compostos por agrupamentos de outros tipos primitivos da linguagem. Geralmente, os dados so armazenados de forma a facilitar a identificao de cada campo de dados que pretende-se manter, para isso usamos nomes para cada campo dentro da estrutura de dados, de forma a ter um meio de acess-la depois. Estruturas so blocos bsicos de informao e so manipulados de maneira primitiva. Basicamente o compilador instrui a montagem de um cdigo que manipula-as de forma a copiar, referenciar e obter posio na memria. Todas as outras formas de tratar os dados devem ser providas pelo cdigo do programa.

Implementao
Para criar um tipo de dados composto heterogneo, basicamente, cria-se uma lista de tipos e nomes de variveis separadas por ponto e vrgula. Podemos imaginar esta lista como um bloco de cdigo, em linguagem C, onde esto presentes apenas as declaraes de variveis. Para isso temos a seguinte sintaxe: struct Estrutura { <Tipo A> NomeVariavelA; <Tipo A> NomeVariavelA2; <Tipo A> NomeVariavelA3; <Tipo B> NomeVariavelB; <Tipo C> NomeVariavelC; <Tipo D> NomeVariavelD; ... ... <Tipo Z> NomeVariavelZ;

} [<NomeVariavelComposta>]; O nome da varivel composta pode ser omitido na declarao da estrutura e depois definido onde for mais apropriado, geralmente, dentro de algum bloco de cdigo onde venha a ser usado. Podemos ver logo abaixo, o exemplo de uma declarao de estrutura: struct Estrutura { int Inteiro; double PontoFlutuante; char Caracteres[10]; };

Estruturas

30

int main() { Estrutura MinhaVariavelComposta; ... ... ... return 0; }

Acessando dados internos


O modo de acesso a variveis internas de uma estrutura feito atravs do operador ponto ".", porm, quando usamos ponteiros para guardar o endereo de uma estrutura usamos o operador seta "->". Vejamos um pequeno trecho de cdigo: Estrutura st; Estrutura *pst; st.Inteiro = 200; pst = &st; pst->PontoFlutuante = 23.976;

Estruturas em C++
As estruturas em C++ funcionam de modo anlogo ao apresentado em linguagem "C". A diferena, a princpio, notvel entre elas nas duas linguagens que em "C++" o especificador struct no precisa ser escrito quando criamos a estrutura: Em C, para criar uma estrutura de dados chamada st, declaramos: struct Estrutura st; Para fazer o mesmo em C++, declaramos: Estrutura st;

Este simples detalhe revela uma caracterstica importante das estruturas em C++: Nesta linguagem as estruturas so tratadas como tipos primitivos de objetos. Elas tm caractersticas semelhantes s classes, que veremos nos captulos subsequentes. As estruturas em C++ tambm podem conter funes alm de dados. Este fato vem da ideia de modelo de objeto que as estruturas mantm nesta linguagem. Objetos devem ter propriedades (variveis) e mtodos (funes membro), por isso temos a possibilidade de criar funes dentro do corpo das estruturas, com a finalidade de lidar com os dados que elas mantm.

Estruturas

31

Construtores
Os construtores so funes que so criadas automaticamente sempre que tentamos criar um objeto. Eles funcionam da mesma maneira que construtores de classe. A esses que so criados automaticamente so os chamados de defaut. Se escrevermos o cdigo:
#include <iostream> #include <string> using namespace std; const int MAX = 3; struct Person { string name; int height; }; int main () { Person p1; cout << "The person's name is " << p1.name << " and height is " << p1.height << endl; system (pause); return 0; }

O resultado : The person's name is and height is -858993460

Aqui criado um defaut constructor no momento em que criamos a instncia p1 ie com a linha Person p1; Como as variveis membro no foram iniciadas, o valor de name est vazio e o na varivel height est um valor qualquer que lixo! Constructor sem argumentos Podemos ter um construtor sem argumentos que ao contrrio do defaut constructor designa valores defaut s variveis membro. struct Person { string name; int height; Person() //construtor sem argumentos { name = "No name assigned"; height = -1; } }; O nome do construtor sempre igual ao nome da estrutura, sem exceo. O construtor no retorna qualquer valor, sem exceo Refazendo o nosso exemplo

Estruturas
#include <iostream> #include <string> using namespace std; const int MAX = 3; struct Person { string name; int height; Person() { name = "No name assigned"; height = -1; } }; int main () { Person p1; cout << "The person's name is "<< p1.name << " and height is " << p1.height << endl; system (pause); return 0; }

32

Repare que demos valores defaut s variveis. Agora no estamos no caso de ter p1.name=??? Por mais instncias que criemos eles vo ter sempre valores padro. Constructor com argumentos Termos um constructor sem argumentos um melhoramento face ao defaut constructor pois agora temos valores defaut para as variveis membro. Porm seria melhor se consegussemos inicializar as variveis membro com valores dados pelo utilizador enquanto o programa estivesse e a correr. E realmente podemos fazer se passarmos argumentos.
#include <iostream> #include <string> using namespace std; const int MAX = 3; struct Person { string name; int height; Person() { name = "No name assigned"; height = -1; } Person(string s, int h) { name = s; height = h; } //constructor com 2 argumentos //constructor sem argumentos

Estruturas
}; int main () { int metro; string strName; cout << "Entre com o nome da pessoa: "; getline(cin, strName); cout << "Enter height in metro: "; cin >> metro; cin.ignore(); Person p1(strName,metro); cout << "The person's name is " << p1.name << " and height is " << p1.height << endl; system (pause); return 0; }

33

Repare que os argumentos do construtor tm de estar na ordem esperada Separar o construtor prototype da implementao
#include <iostream> #include <string> using namespace std; const int MAX = 3; struct Person { string name; int height; Person(); Person(string, int); }; Person::Person() { name = "No name assigned"; height = -1; } Person::Person(string s, int h) { name = s; height = h; } int main () { //construtor sem argumento //construtor com dois parmetros, apenas

necessrio dizer o tipo dos parmetros o nome no necessrio)

Estruturas
int metro; string strName; cout << "Enter person's name: "; getline(cin, strName); cout << "Enter height in inches: "; cin >> metro; cin.ignore(); Person p1(strName, inches); cout << "The person's name is " << p1.name << " and height is " << p1.height << endl; system (pause); return 0; }

34

Vamos ver a funo main(): declarmos 2 variveis uma int e outra string. Pedimos para a pessoa escrever o nome e colocmos o valor na varivel string, depois pedimos a altura e colocmos na varivel int. Depois chammos o construtor com dois argumentos e passamos as variveis anteriores como argumentos. Por fim mandmos imprimir os valores das variveis membro da estrutura. Repare que para definirmos fora o construtor recorremos ao operador scope :: Person::Person() Person::Person(string s, int h) Repare que no prototype dos construtor apenas tivemos de dizer o tipo dos parmetros

Operadores
Os operadores realizam, como o nome sugere, operaes entre dois tipos de dados. Existem muitos operadores, mas citaremos aqui os fundamentais e, conforme as necessidades dos tpicos posteriores, citaremos todos os demais.

Compatibilidade
Os operadores padres da linguagem "C" podem ser usados de forma semelhante na linguagem C++. Aliadas s funcionalidades tradicionais do "C" podemos criar operaes diferentes para os operadores. Esta funcionalidade conhecida como sobrecarga de operadores e ser descrita em captulo posterior.

Como C++ interpreta os operadores


Para dar uma base de entendimento para a sobrecarga de operadores iremos introduzir o modo como o compilador C++ entende os operadores. Este modo de interpretar os operadores implementado para dar suporte aos recursos de POO da linguagem. O entendimento do modo de funcionamento do mecanismo de compilao pode diminuir as dvidas que surgem no estudo de operadores em C++. importante entender que a linguagem deve servir de base para a criao de entidades de dados autnomas e operveis. Logo, o compilador deve ser generalista ao enxergar operaes com tipos primitivos e tipos criados pelo programador (classes). Por estes fatores, o compilador utiliza-se de uma interface funcional para implementao dos recursos de operadores. Os operadores so tratados como funes, de forma a possibilitar a alterao do seu comportamento em determinados casos. Os operandos so tratados como argumentos de funes, enquanto que o resultado da operao tratado como retorno da funo do operador. Esta interface faz com que possamos programar o comportamento das

Operadores operaes e alter-las quando nos seja conveniente.

35

Entendendo o operador
Basicamente, temos dois tipos de implementao para operadores, o tipo global e o tipo membro de classe. Os dois tipos so usados regularmente nas implementaes mais comuns. Analisaremos o tipo global, uma vez que ainda no temos uma noo de classes suficiente para abordar o tipo membro de classe. Digamos que temos uma estrutura ponto, como definida abaixo: struct Ponto { int x; int y; }; Uma vez que tenhamos definido um ponto, nada mais natural que queiramos somar, subtrair, enfim operar, pontos diferentes de acordo com nossas necessidades. Para isso podemos criar operadores para fazer isso, da seguinte forma: Observamos a quantidade de parmetros, o retorno e a forma de chamar o operador que queiramos definir e criamos uma funo que execute a operao desejada; Inserimos o cdigo da referida funo dentro de uma chamada de operador, usando a palavra reservada operator seguida do operador que desejamos definir: Ponto operator+ ( Ponto a, Ponto b ) { Ponto soma; soma.x = a.x + b.x; soma.y = a.y + b.y; return soma; } E assim, o operador entendido como uma funo, sendo a sobrecarga um processo de definio da operao a ser executada. Recebe esse nome porque todo operador j existe e a definio de uma nova funcionalidade apenas adiciona (sobrecarrega) as habilidades anteriores do operador. Embora isto seja comum, bom lembrar que operaes de tipos primitivos no podero ser modificadas, restando apenas a funcionalidade de criar operadores para nossos tipos (classes).

Os argumentos
Agora vejamos como os argumentos so vistos pelo compilador durante a chamada ao operador. Essa sintaxe, muitas vezes, confunde iniciantes, mas bastante intuitiva. Veja: c = a + b; Consideremos que a,b,c so pontos. Em termos gerais, qualquer operador binrio (com dois argumentos) definido em escopo global, receber a e b como primeiro e segundo argumento da funo que define o operador. Podemos ver a chamada da seguinte forma: c = operator+( a, b );

Operadores

36

Operadores aritmticos
Operadores aritmticos so utilizados para efetuar operaes matemticas entre dados. So 5 operadores aritmticos em C++:
#include <iostream> using namespace std; int main() { int soma = 5 + 5; // o operador '+' realiza somas. double subtracao = 5 - 5; // o operador '-' efetua subtrao. float multiplicacao = 5.1 * 0.5; // o operador '*' efetua multiplicao. char divisao = 100 / 2; // o operador '/' efetua diviso. int modulo = 51 % 5; // retorna o resto da diviso inteira. cout << "Resultados: " << soma << ", " << subtracao << ", " << multiplicacao << ", " << divisao << ", " << modulo << endl; } A sada desse programa gera no console o seguinte: <source lang=cpp> Resultados: 10, 0, 2.55, 2, 1.

O quarto resultado '2' pois 50 o cdigo decimal deste caracter.

Tipo de retorno
Voc pode realizar operaes aritmticas, obviamente, entre nmeros. Como dito no tpico anterior, voc tambm pode realizar operaes aritmticas com os tipos char e wchar_t. O retorno da operao ser tambm um nmero (real, inteiro ou at mesmo um caracter, conforme os tipos dos operandos).

Diviso inteira e diviso real


Existe, para a linguagem, diferena entre uma diviso entre nmeros inteiros e entre nmeros reais (ponto flutuante). Se voc fizer a diviso entre os inteiros 3 e 2, o resultado no ser 1.5, ser 1. J se fizer a diviso entre os nmeros reais (em ponto flutuante) dos deles, ento sim obter 1.5. O motivo que h 2 tipos de diviso: a inteira e a decimal. Diviso inteira e o operador mdulo A diviso inteira retorna o quociente da diviso sem a parte fracionria. Isso ocorre porque a linguagem efetua a diviso enquanto o resto for maior que o divisor (logo, a diviso nunca apresentar parte fracionria). Para obter o resto da diviso, voc pode usar o operador mdulo (%). Esse operador retorna, em vez do quociente, o resto da diviso inteira. por isso que no nosso exemplo 51 % 5 resultou em 1, pois 5x10 + 1 = 51, onde 5 o divisor, 10 o quociente, 1 o resto e 51 o dividendo.

Operadores Diviso real A diviso real aquela efetuada entre tipos ponto flutuante ou entre ponto flutuante e inteiros/caracteres. Isso efetuar a diviso at que o resto seja zero, ou quando o resto repetir-se indefinidamente (no caso de dzimas peridicas como, por exemplo, 10/3). Se quisermos que a diviso entre inteiros retorne a diviso real, deveremos efetuar uma converso explcita, conforme o exemplo: int num = 3; int num2 = 2; cout << "Resultado: " << (float) num/num2 << endl; // o resultado foi convertido para ponto flutuante explicitamente.

37

Deciso e controle de fluxo


Controle de fluxo em C++
Aqui vamos criar funes que nos permitam alterar a leitura de execuo do cdigo. Ou seja, j dissemos que a leitura de execuo do cdigo de cima para baixo (l a primeira linha de cdigo executa, l a 2 linha --executa,..e por a adiante) O que agora vamos fazer e criar mecanismos para alterar esse leitura sequencial e permitir: Execuo de cdigo de acordo com a condio Repetio de execuo de cdigo sujeito a condio Saltar linhas de cdigo

Deciso em C++
Em C++ os mtodos de tomada de deciso presentes na linguagem C esto disponveis para as tarefas mais corriqueiras que o programa deve executar. Alm desta forma de controle de decises, C++ prov certas funcionalidades relacionadas a objetos que modificam a forma como o cdigo estruturado e, por consequncia, decidem como o programa deve se comportar em determinadas situaes. Examinemos os mtodos bsicos e analisemos de forma simples as estruturas de deciso presentes no modelo de programao orientado a objetos, para entender como isso poder nos ajudar a tornar o cdigo mais bem construdo. De modo geral, a maioria das linguagens de programao existentes utiliza-se das estruturas if-else ou switch-case.

Deciso e controle de fluxo

38

if-else
if Se voc quer que o software execute um determinado comando somente em certas situaes, utilize if para determinar isto. O programa vai, ento, executar a primeira linha de cdigo aps o if, se a declarao entre parnteses for verdadeira. Exemplo: #include <iostream> using namespace std; int main(void) { int variavel; cout << "Escreva um numero: "; cin >> variavel; if(variavel == 5) cout << "A varivel igual a 5"; return 0; } Pode-se usar valores booleanos: bool variavel; if(variavel) //if ser executado se booleano for verdadeiro, como no lhe foi atribudo valor, falso cout << "varivel verdadeira!"; Ou, se booleano tiver que ser falso para ocorrer a execuo: if(!variavel) // O ! faz com que s haja execuo da prxima linha se varivel for falsa cout << "varivel falsa!"; Mas se voc quiser que o computador execute vrias linhas aps o if se este for verdadeiro? Basta usar chaves: if(variavel) { cout << "A varivel verdadeira...\n"; cout << "E continua executando" << "at que seja fechado o if" << " com o }"; } else tambm possvel usar o bloco else para o computador executar vrias linhas de cdigo caso uma condio tenha o valor booleano falso. Por exemplo: if(temperatura < 20) { cout << "Est frio"; } else { cout << "Est calor"; } Assumindo que a varivel temperatura tem tipo inteiro (int), se esta contiver um valor, por exemplo, 20, ser apresentada na tela a mensagem "Est calor", uma vez que 20 < 20 uma expresso contradio, logo tem o valor

Deciso e controle de fluxo booleano falso. Podemos ainda encadear vrios else, e obter ainda mais possibilidades: if(deposito < 20) { cout << "Depsito de gasleo inferior a 20%"; } else if(deposito < 50) { cout << "Tem menos de metade do depsito"; } else { cout << "Ainda tem meio depsito ou mais"; } Desta forma, conseguimos distinguir o nvel de depsito de gasleo de um carro em 3 nveis diferentes. Para distinguir por mais nveis, bastaria acrescentar mais } else if(...condio...) { para distinguir os diferentes patamares. De notar que, cada caso avaliado individualmente, por ordem. Isto , primeiro seria verificado se o depsito tem menos de 20% de gasleo; apenas se esta condio for falsa que o computador avalia a segunda condio, para verificar se o depsito tem menos de 50% de gasleo, e por ainda adiante.

39

switch
O switch muito parecido com o if-else. Apenas a sintaxe e construo diferente #include <iostream> using namespace std; int main(void) { char grade; cout << "Enter your grade (A cin >> grade; switch (grade) { case 'A': cout << "Your break; case 'B': cout << "Your break; case 'C': cout << "Your break; case 'D': cout << "Your break; default: cout << "Your } return 0; }

to F): ";

average must be between 90 - 100"<< endl;

average must be between 80 - 89"<< endl;

average must be between 70 - 79"<< endl;

average must be between 60 - 69"<< endl;

average must be below 60" << endl;

Deciso e controle de fluxo Cada um dos casos tem de ser uma constante (no pode alterar durante a vida do programa), neste exemplo A, B, O defaut serve para a condio de todas as avaliaes dos casos anteriores der falsa. ( tipo o else) O break serve para terminar o switch, caso contrrio se num dado case fosse verdadeiro, iria executar todos os statementes mesmo de outros cases at terminar o switch. Aqui para cada caso no necessitamos de {} se tivermos mais do que 2 statements. o if-else mais forte do que o switch por que permite fazer coisas como: if (apples == oranges) do this; else if (sales >= 5000) do that; Para alm do ponto j dito de os casos serem obrigatoriamente constantes, no switch Tambm posso utilizar operadores lgicos no switch switch (age >= 18 && citizen == true) { case true: cout << "You are eligible to vote"; break; case false: cout << "You are not eligible to vote"; }

40

Operador condicional "?"


A sintaxe : [Relational expression] ? [statement if true] : [statement if false] Ou seja, este operador testa a expresso relacional e se o resultado for verdadeiro executa logo a 1 afirmao caso contrrio executa a segunda. ou seja isto no mais do que um if-else. H quem goste de usar este operador porque poupa escrita, mas acho que no vale a pena! #include <iostream> using namespace std; int main(void) { int num; cout << "Enter a whole number: "; cin >> num; cout << "The number is " << (num % 2 == 0 ? "even" : "odd") << endl; return 0; } Notar que o operador condicional exige 3 operandos. vamos fazer uns exerccios: 7==5 ? 4 : 3 // returns 3, since 7 is not equal to 5. 7==5+2 ? 4 : 3 // returns 4, since 7 is equal to 5+2.

Deciso e controle de fluxo 5>3 ? a : b // returns the value of a, since 5 is greater than 3. a>b ? a : b // returns whichever is greater, a or b.

41

O Comando goto
O goto realiza um salto para um local especificado. Este local determinado por um rtulo. Portanto pode ser em qualquer parte do programa. nome_do_rtulo: .... goto nome_do_rtulo; .... // goto loop example #include <iostream> using namespace std; int main () { int n=10; loop: cout << n << ", "; n--; if (n>0) goto loop; cout << "FIRE!"; return 0; } Repare no rtulo. Nota: Evite o uso de goto quando for possvel usar estruturas principais, porque pode tornar o cdigo ilegvel. Esse comando deve ser usado em ltimo caso, como sair de loops aninhados.

Terminando o programa
Esta funo definida com a biblioteca cstdlib (c+std+lib) O propsito da funo terminar com o programa com um especfico cdigo de sada O prottipo : int exit (int exitcode); Esta funo usada por alguns sistemas operativos e podem ser usadas para chamar programas. Por conveno o cdigo 0 se sada significa que o programa terminou normalmente, como previsto, se vier com outro nmero significa que houve um erro e algo de inesperado sucedeu.

Estruturas de repetio

42

Estruturas de repetio
Laos (loops em ingls), ou estruturas de repetio, so comandos existentes nas linguagens de programao destinados a executar uma ou mais instrues quantas vezes forem necessrias. Cada ciclo de um loop chamado de iterao. Podemos ter tambm loops dentro de outro loop.

While
O while, "enquanto" em ingls, um lao que ordena o computador a executar determinadas instrues enquanto uma condio for verdadeira. Isso faz com que um comando seja executado uma vez a cada verificao da condio. De modo geral o comando sempre deve ser elaborado de forma que se leve a condio de execuo a ser falsa em algum momento, de forma a interromper o lao para que o resto do programa entre em execuo.

Sintaxe
while (condio) comando; Onde condio a condio de execuo do lao while. O cdigo abaixo mostra o uso do lao while para imprimir na tela do nmero 1 ao nmero 10. Perceba o uso de uma varivel inteira intitulada contador. Esta varivel utilizada para armazenar um valor a ser impresso bem como participar da condio de execuo do lao. Assim que a varivel atingir o valor 11 o programa segue para o comando logo aps o lao. #include <iostream> using namespace std; int main() { int contador; // contador=1; // while (contador<=10) // { cout << contador << endl; // contador++; // } return 0; }

Declara a varivel contador. contador recebe o valor 1. Enquanto contador for menor ou igual a 10. Imprime contador. Incrementa contador em uma unidade.

Estruturas de repetio

43

Do-While
O lao do-while um while invertido, onde voc coloca as instrues a serem repetidas antes da verificao da condio de execuo. Isso significa que os comandos do lao sero executados ao menos uma vez.

Sintaxe
do { comando; } while (condio); Onde condio a condio de execuo do lao do-while. Os comandos pertencentes ao lao somente deixaro de se repetir quando a condio for falsa. O algoritmo abaixo mostra como seria o algoritmo exemplo usado na seo do lao while convertido para o uso do lao do-while. #include <iostream> using namespace std; int main() { int contador; contador=1; do { cout << contador << endl; contador++; } while (contador<=10); return 0; }

// Declara a varivel contador. // contador recebe o valor 1. // Imprime contador. // Incrementa contador em uma unidade. // Enquanto contador for menor ou igual a 10.

For
Como o uso de uma varivel como contador nos laos algo frequente, foi criado um outro lao que traz em sua estrutura campos para abrigar os comandos de atribuio de valor inicial e incremento/decremento do contador. O nome deste lao for, "para" em ingls.

Sintaxe
for ([iniciao]; [condio]; [incremento]) comando; Onde: iniciao: campo destinado para qualquer comando que deve ser executado, uma nica vez, logo no incio do lao. condio: campo destinado para a condio de parada. Esta condio verificada logo no incio do lao, imediatamente aps a concluso do parmetro1 e a cada passo quando o <comando> executado. incremento: campo destinado para qualquer comando que deve ser executado todas as vezes em que o lao finalizar seu ltimo comando, em todas as suas repeties. O algoritmo abaixo mostra o uso do lao for manipulando a varivel inteira contador de maneira imprimir uma contagem de 1 at 10. Esse uso do lao for o mais comum pois possibilita uma repetio de comandos de nmero

Estruturas de repetio fixo, dez no algoritmo em questo. #include <iostream> using namespace std; int main() { int contador; // Declara a varivel contador. for (contador=1; contador<=10; contador++) // Inicia o lao. cout << contador << endl; // Imprime contador. return 0; } importante deixar claro que nenhum dos trs parmetros utilizados no lao for obrigatrio. Caso no haja necessidade de utilizar um ou mais deles, basta deixar seu espao em branco. Como exemplo temos o algoritmo a seguir, que demonstra um lao infinito usando for: #include <iostream> using namespace std; int main() { for (;;) cout << "Eu sou um lao infinito." << endl; return 0; } A ausncia do 2 parmetro significa loop infinito: for (int num =1; ; num++) { cout << num << " "; } Isto vai colocar um valor a mais no num indefinidamente. Ausncia do 3 parmetro: for (int num=1; num <= 10; { cout << num << " "; num++; } )

44

Estruturas de repetio

45

Dicas
Bloco de Comandos
Em muitos casos, os laos devem repetir dois ou mais comandos. Para isso, necessitamos criar um bloco de comandos contendo todas as instrues a serem repetidas. A criao de um bloco de comandos simples, basta colocar todos os comandos entre chaves { }. Os algoritmos de exemplo dos laos while e do-while fazem uso de um bloco de comandos. Caso o lao no encontre a abertura de um bloco logo em seguida, ele assumir que o comando imediatamente abaixo o nico que deve ser repetido. Exemplo 1: while (condio) comando1; // Este comando faz parte do lao. comando2; // Este comando no faz parte do lao. Exemplo 2: while (condio) { comando1; // Este comando faz parte do lao. comando2; // Este comando faz parte do lao. }

O Comando break
O que o break faz quebrar a execuo para fora do bloco de cdigo onde ela est presente #include <iostream> using namespace std; int main(void) { int num; char choice; bool quit = false; while (true) { cout << "Enter a positive number: "; cin >> num; if (num > 0) break; else { cout << "Number must be positive; try again (Y/N): "; cin >> choice; if (choice != 'Y') { quit = true; break; }

Estruturas de repetio } } if (quit == false) cout << "The number you entered is " << num << " "; else cout << "You did not enter a positive number"; return 0; } O break faz com que a execuo do programa continue na primeira linha seguinte ao loop ou bloco

46

O Comando continue
Esta instruo bem parecida com o break, mas algo diferente. Pois em vez de mandar a execuo para fora do bloco manda-a para a avaliao do loop. Ou seja faz saltar uma determinada iterao do loop, enquanto o break faz acabar o loop #include <iostream> using namespace std; int main(void) { int num, counter = 0, total = 0; cout << "How many items do you want to buy: "; cin >> num; while (counter++ < num) { if (counter % 13 == 0) continue; total += 3; } cout << "Total for " << num << " items is $" << total; return 0; } Neste exemplo quando o conter for mltiplo de 13, a instruo seguinte saltada total+=3

Incrementar/decrementar
Aqui vamos voltar a um tpico anterior que foi abordado nos operadores Temos a=a+1 equivalente a ter a+=1 e ainda a ter a++ Mas isto tudo s no caso do incremento ser 1. Podemos ter ++a ou ainda a++. Eles so parecidos mas diferentes, a questo do prefixo e ps-fixo. A diferena que O prefixo, faz o incremento ainda durante a instruo O ps-fixo faz o incremento quando se passa para a instruo seguinte. #include <iostream> using namespace std; int main(void) {

Estruturas de repetio int num = 2; cout << num << \n; cout << ++num << \n; cout << num++ <<\n; cout << num << \n; return 0; } Portanto int num = 5; cout << (++num == 5);

47

Exerccios
Crie um programa que d o fatorial de um nmero: #include <iostream> using namespace std; int main(void) { int num, counter, total = 1; cout << "Enter a number: "; cin >> num; cout << "The factorial of " << num << " is "; for (int counter = 1; counter <= num; counter++) total *= counter; cout << total; return 0; } Crie um programa para o utilizador adivinhar um nmero de 0 a 3. D 3 hipteses para adivinhar. No caso de acertar antes de chegar ao fim das 3 hipteses termine. #include <iostream> using namespace std; int main(void) { int num, counter, secret = 3; cout << "Guess a number between 1 and 10\n"; cout << "You have 3 tries\n"; for (int counter = 1; counter <= 3; counter++) { cout << "Enter the number now: "; cin >> num; if (num == secret) { cout << "You guessed the secret number!"; break; } }

Estruturas de repetio cout << "Program over"; return 0; } Criao de menu. #include <iostream> using namespace std; int main () { int i; do { cout << "\n\nEscolha a fruta pelo numero:\n\n"; cout << "\t(1)...Mamao\n"; cout << "\t(2)...Abacaxi\n"; cout << "\t(3)...Laranja\n\n"; cin >> i; } while ((i<1)||(i>3)); switch (i) { case 1: cout << ("\t\tVoce escolheu Mamao.\n"); break; case 2: cout <<"\t\tVoce escolheu Abacaxi.\n"; break; case 3: cout << ("\t\tVoce escolheu Laranja.\n"); break; } return(0); }

48

Funes

49

Funes
Funo, do latim functio, onis, representa na computao, um pequeno algoritmo com uma funo simples e bem definida. como se cada funo fosse um micro programa, ou um tijolo na construo do programa principal. O uso de funes facilita muito o desenvolvimento, pois, divide o problema principal em pequenos problemas mais simples. Essa tcnica se chama, Dividir para conquistar. A experincia mostra que o uso de funes facilita e acelera a criao e manuteno de sistemas. Todo programa em C++ tem pelo menos uma funo, o main. Veja o exemplo do programa em C++:
#include <iostream> //Biblioteca com funes de entrada e sada de dados

using namespace std;

int main (void) //Funo principal do programa { cout << "Ol mundo!"; //cout tambm uma funo, e precisa ser importada da biblioteca iostream

//Esta funo main retorna um valor int, ou inteiro, por isso faz a operao de retornar 0 return 0; }

Do exemplo Ol mundo, vemos que toda funo em C++ tem um nome. O nome de uma funo junto com o tipo de dados que retorna chamado assinatura da funo. int main (void) //Assinatura da funo main Essa assinatura informa que a funo de nome main retorna na sua execuo um valor do tipo int, ou inteiro, e recebe void como parmetro. Receber void significa que a funo no recebe parmetro, se a funo retorna void, significa que no retorna nada. Algumas funes no precisam retornar nenhum valor para funcionar, apenas realizar alguma ao.

Sobrecarga de funes
Em C++ duas funes podem ter o mesmo nome se: Tiverem um n diferente de parmetros e/ou Se os parmetros forem de tipos diferentes (ints floats,..) A funo no pode ser overloaded apenas com diferentes tipo de retorno de funo (ie, uma funo retornar ints e a outra retornar floats) ento os parmetros que interessam. #include <iostream> using namespace std; void ConvertFToC(double f, double &c); void ConvertFToC(float f, float &c); void ConvertFToC(int f, int &c); int main() { double df, dc; float ff, fc;

Funes int i_f,i_c; //if is a reserved word df = 75.0; ff = 75.0; i_f = 75; // The compiler resolves the correct // version of ConvertFToC based on // the arguments in each call cout << "Calling ""double"" version" << endl; ConvertFToC(df,dc); cout << df << " == " << dc << endl << endl; cout << "Calling ""float"" version" << endl; ConvertFToC(ff,fc); cout << ff << " == " << fc << endl << endl; cout << "Calling ""int"" version" << endl; ConvertFToC(i_f,i_c); cout << i_f << " == " << i_c << endl << endl; system ("pause"); } void ConvertFToC(double f, double &c) { cout << "In ""double"" version" << endl; c = (f - 32.0) * 5. / 9.; } void ConvertFToC(float f, float &c) { cout << "In ""float"" version" << endl; c = (f - 32.0) * 5. / 9.; } void ConvertFToC(int f, int &c) { cout << "In ""int"" version" << endl; c = (f - 32) * 5. / 9.; } O que que acontece se tivermos um n diferente de argumentos entre a chamada e a definio? A soluo aqui proposta quando no sabemos a quantidade de parmetros que a funo vai ser chamada ou mesmo a tipologia desses argumentos, o que se sugere fazer vrias definies para a funo e dar a todas elas o mesmos nome, que o compilador vai saber escolher a definio correcta atravs do n e tipologia de argumentos. Entretanto, por boa prtica, as funes no devem ser sobrecarregadas se fizerem operaes distintas.

50

Funes

51

Parmetros default (padro)


Pode acontecer que tenhamos que declara varia vezes o mesmo valor como parmetro de uma funo. Para simplificar a chamada a funes que variam pouco podemos definir uma parmetro default. #include <stdio.h> #include <stdlib.h> /*-----------------------------Cabealho--------------------------------*/ /*Definimos uma funao*/ void function(int a,int b, int c = 100 ) { printf("Meu Primeiro argumento :%d\n",a ); printf("Meu Segundo argumento :%d\n",b ); printf("Meu terceiro argumento :%d\n",c ); getchar(); } int main (void) { function( 10, 30); /* Agora use a funo assim e veja o que acontece */ // function( 10,30,999); } Os parmetros por default devem ser os ltimos da lista, ou seja, mais direita. O parmetro padro deve ser especificado no prottipo e no na declarao da funo.

Referncias de dados
Variveis de referncia
Em C++ podemos criar variveis que podem ser uma alternativa para os ponteiros em algumas situaes. A vantagem de no usar diretamente o endereo (valor de ponteiro) em situaes onde no precisamos lidar diretamente com valores de memria torna a programao mais segura e simplificada. Podemos deixar as operaes com ponteiros apenas para quando for estritamente necessrio. Variveis de referncia podem ser criadas para dar um nome diferente para as variveis que j existem no programa, ou para passar a varivel para dentro do corpo de uma funo. Observemos, inicialmente, um caso simples: int a = 10; int &b = a; b = 20; Neste trecho de programa, criamos uma varivel de referncia b para a varivel a, o que significa que criamos outro nome para a varivel a. De fato, b a prpria varivel a com outro nome, apenas isso. Desta forma, podemos alterar o valor de a usando b.

Referncias de dados

52

Passagem de parmetros
Na linguagem "C", durante a chamada de uma funo, os argumentos (parmetros) tm seus valores copiados para a rea de processamento da funo. Depois que os mesmos foram usados dentro do bloco de processamento da funo, eles so descartados. A funo retorna o processamento para o bloco que a chamou trazendo apenas o valor de retorno. A nica maneira de fazer com que a funo modifique o valor de alguma varivel definida no bloco de programa que a chamou pass-la por um ponteiro com o seu endereo. Vejamos o fragmento de cdigo seguinte: int f( int x ) { x--; return x; } int main() { int a = 10; int b; b = f(a); ... ... Em "C", a menos que o programador seja bem malicioso e faa manipulaes de memria arriscadas, a funo f jamais alterar o valor do seu argumento x. Diferentemente da linguagem "C", a chamada a uma funo em C++ pode alterar o valor de uma varivel definida antes da chamada da funo, mesmo sem esta varivel ser explicitamente passada como um ponteiro. Este modo chamado de passagem por referncia. Em termos mais gerais, significa a passagem da varivel propriamente dita, para o corpo interno da funo com outro nome, aquele definido na lista de parmetros da funo. Em C++, uma funo pode ser chamada na forma acima e alterar o valor das suas variveis. Para isso basta declar-la como: int function(int & x) { x--; return x; } Temos em C++ o operador & que se comporta diferentemente de C, tendo uma funo a mais, a de criar variveis de referncia: &x quando usado no cdigo retorna o pointero para o endereo de x; &x quando usado na declarao de varivel, cria uma referncia; &x quando usado como parmetro na declarao de uma funo faz com que suas chamadas transfira o argumento/parmetro passando-o de forma similar a passagem de seu pointero. (Passagem por referncia). Em termos semnticos, ao passar a varivel para uma funo onde o parmetro uma referncia, o endereo da varivel atribudo ao endereo do parmetro. Desta forma, o parmetro a mesma varivel passada, no trecho de cdigo onde a funo foi invocada, assumindo um nome diferente dentro da funo. Vejamos um exemplo usando a funo anterior:

Referncias de dados int m = 4; function(m); cout << m << endl; O cdigo anterior imprime na sada padro o valor 3. Acompanhando o fluxo de execuo verificamos o seguinte: Depois que a varivel m includa na chamada da funo o seu nome muda para x e o programa passa a ser executado dentro da funo, onde a varivel decrementada. Portanto, quando a execuo retorna para o corpo principal a varivel estar decrementada.

53

Exemplo: alterando o valor da varivel usando referncia


#include <iostream> using namespace std; int main() { int val = 1; int &ref = val; cout << "val is " << cout << "ref is " << cout << "Setting val val = 2; cout << "val is " << cout << "ref is " << cout << "Setting ref ref = 3; cout << "val is " << cout << "ref is " << system ("pause"); return 0; }

val << endl; ref << endl; to 2" << endl; val << endl; ref << endl; to 3" << endl; val << endl; ref << endl;

Como se viu conseguimos alterar o valor de val alterando o valor de ref. Existe apenas umas restries para o seu uso: Teremos de inicializar e no momento da declarao teremos de atribuir de imediato o valor (se no fizermos isso gerar um erro de compilao) As referncia no podem ser reatribudas, ou seja no exemplo anterior tinha int &ref = val; se mais tarde no cdigo tentar-se fazer int &ref=m; (sendo m uma varivel j declarada e iniciada por hiptese) o que acontece que a 2 instruo completamente ignorada e ficamos sempre com a primeira. A vantagem real das referncias que quando elas so usadas para passar valores para as funes elas providenciam uma maneira de retornar valores das funes. Vejamos o exemplo #include <iostream> using namespace std; int main() { int val1 = 10; int val2 = 20;

Referncias de dados int &ref = val1; cout << "val1 is " << val1 << endl; cout << "val2 is " << val2 << endl; cout << "ref is " << ref << endl; ref = val2; //What does this do? cout << endl << "ref = val2" << endl; cout << "val1 is " << val1 << endl; cout << "val2 is " << val2 << endl; cout << "ref is " << ref << endl; val2 = 30; cout << endl << "Setting val2 = 30" << endl; cout << "val1 is " << val1 << endl; cout << "val2 is " << val2 << endl; cout << "ref is " << ref << endl; system ("pause"); return 0; }

54

Exemplo: Swap
O exemplo abaixo mostra uma forma muito comum de usar referncias. A instruo "swap", que tem por objetivo trocar os valores de duas variveis, mais naturalmente chamada como Swap(a, b) do que Swap(&a, &b); assim, mais simples declarar a funo usando referncia: #include <iostream> using namespace std; void Swap (int &i,int &j) { int t=i; i=j; j=t; } int main () { int a,b; a=5; b=10; cout<<a<<"\t"<<b; Swap (a,b); cout<<a<<"\t"<<b; system ("pause"); return 0; }

Referncias de dados

55

Comparao entre passagem por referncia e ponteiros


Para exercitar vamos criar um novo problema: Criar um funo que duplique qualquer valor colocado pelo utilizador:
1 PROGRAMA-via referncia 2 PROGRAMA via ponteiros - endereos

#include <iostream> #include <iostream> using namespace std; using namespace std; void doubleIt(int&);//prototype com endereo de variavel void doubleIt(int*); //parametro por endereo int main () int main () { { int num; int num; cout << "Enter number: "; cout << "Enter number: "; cin >> num; cin >> num; doubleIt(num); //chamo funo, passando parametro num doubleIt(&num);//passei parametro como endereo cout << "The number doubled in main is " << num << endl; cout << "The number doubled in main is " << num << endl; system ("pause"); system (pause); return 0; return 0; } } void doubleIt (int& x) void doubleIt (int* x) { { cout << "The number to be doubled is " << x << endl; cout << "The number to be doubled is " << *x << endl; x *= 2; *x *= 2; cout << "The number doubled in doubleIt is " << x << endl; cout << "The number doubled in doubleIt is " << *x << endl; } }

Ou seja nestes dois cdigos temos uma passagem por referncia e outro por endereo. Com diferenas: Na chamada da funo (dentro do main() ) doubleIt(num); doubleIt(&num); // by reference // by address

No prototype da funo (confirmar o ponto e virgula) void doubleIt(int&); void doubleIt(int*); Na function header void doubleIt (int& x) void doubleIt (int* x) // by reference // by address // by reference // by address

dentro do body function (dentro da prpria funo) x *x Podemos pensar que passando por referncia parece ser muito mais simples do que passado por address. Na verdade existem certas funes da biblioteca que s permitem a passagem por address.

Entrada e sada de dados

56

Entrada e sada de dados


Entrada e sada
Aqui vamos dar incio ao estudo de recursos que possibilitaro inserir dados e fazer reporte da falta deles. No C++ a entrada e sada podem ser feitas atravs da biblioteca iostream. Para podermos us-la deveremos colocar a linha de cdigo: #include <iostream> A estrutura de comunicao com o meio externo em modo texto composta por um conjunto de objetos. Estas, em conjunto com operadores e funes de formatao possibilitam uma forma de comunicao mais intuitiva. Devido abstrao de elementos do mundo real por recursos da orientao a objetos, a forma de entender o cdigo torna-se mais natural. Na biblioteca iosteam, temos os seguintes objetos: cin - Este objeto fornece entrada de dados "bufferizada" atravs do "standard input device", o dispositivo de entrada padro; cout - Este objeto fornece sada de dados "bufferizada" atravs do "standard output device", o dispositivo de sada padro; cerr - Este objeto fornece sada de dados no "bufferizada" para o standard error device, o dispositivo de erro padro, que inicialmente definido para a tela. clog - Este objeto fornece sada "bufferizada" atravs do "standard error device", o dispositivo de erro padro que inicialmente definido para a tela. O foco de orientao a objetos que a biblioteca iostream confere aos dispositivos de entrada e sada uma das caractersticas da linguagem C++. Ele est presente na maneira na qual o cdigo foi idealizado e est formatado, modificando a maneira como as partes do sistema de entrada/sada interagem. Desta forma, as operaes de interao entre o usurio e o software tornam-se mais intuitivas para o programador. O sistema de entrada e sada um exemplo deste modelo de programao, onde cada entidade fsica ou lgica de entrada e sada representada por objetos cujas operaes podem ser acessadas diretamente nos programas.

Buffer
Para entendermos um pouco mais sobre Buffer, se faz necessrio recordar um pouco sobre o funcionamento da memria e suas operaes relacionadas a Buffer. Bufferizao um meio de sincronizao entre dispositivos de velocidades diferentes, tais quais memria e dispositivos de armazenamento mecnicos, como discos magnticos. Para evitar que as operaes do dispositivo mais lento interfiram no desempenho do programa pode-se fazer com que os dados sejam colocados em uma memria mais rpida e depois sejam enviadas ao dispositivo mais lento a medida que ele tenha disponibilidade para receb-los, desta forma temos os seguintes modos de escrita em dispositivos de sada: unbuffered significa que qualquer mensagem ou dados sero escritos imediatamente. o caso da escrita no dispositivo cerr; buffered - significa que os dados sero mantidos num buffer de memria at que o dispositivo de destino solicite, ou que um comando de descarregamento seja executado, ou quando o buffer estiver cheio. O problema que se o programa interrompido antes do buffer ser escrito esses dados so perdidos.

Entrada e sada de dados

57

cout
cout << "hello"; cout << 120; cout << hello; // mostra a palavra hello no ecr(monitor) // mostra o nmero 120 no ecr(monitor) // mostra o contedo do pedao de memoria a que chamamos de "hello" no ecr(monitor) /* mostra a primeira string depois vai buscar o contedo da varivel age de depois a string anos de idade */ cout << "Primeira frase. "; cout << "Segunda frase.\n" << "Terceira frase."; /* imprime: Primeira frase. Segunda frase. Terceira frase. */

cout << "hello, tenho " << age<< " anos de idade";

O cout (c+out) usado em conjugao com o operador de insero << permite enviar dados para o "stream out" que por definio o ecr (monitor). Ento podemos enviar as constantes, as variveis, a conjugao das duas se nos apetecer, separadas pelo operador de insero. Temos ainda diversos recursos de formatao atravs de "escapes sequences" que detalharemos no tpico logo a seguir, o recurso usado aqui concatena as vrias frases na mesma linha. Temos de dizer explicitamente "quebra de linha", atravs do "\n", que faz com que a sequncia logo aps, seja escrita na prxima linha. Uma caracterstica muito importante do C++, presente nas instrues logo acima, o polimorfismo notvel na operao de apresentao dos dados na sada; Note que os tipos de dados que so passados para o cout so diversos, ou seja, no importa qual o tipo de dado que ser entregue ao cout, de alguma maneira ele sempre formatar de uma maneira legvel no monitor. Nos captulos mais adiante veremos como fazer com que tipos de dados diferentes sejam tratados pelo mesmo objeto.

Escape Sequences
H um conjunto de caracteres, ns chamamos de string. Mas no exemplo anterior quando usamos o "\n", ns antes dissemos que o cout com o operador << iria colocar no monitor todos os caracteres que estivessem entre aspas. Acontece que existem estas strings especiais chamadas de "escape sequences" - que de alguma forma alteram o sentido das strings. Existem muitas destas sequncias. As mais conhecidas so estas: Escape Sequences (as mais comuns) \n nova linha muda o cursor para uma linha abaixo \r retorno \t tabulador muda o cursor para o prximo ponto de tabulao \v tabulador vertical \b deleo reversa \f alimentador de pgina \a alerta (bipe) faz o computador emitir um sinal sonoro

\' aspas simples (') imprime aspas simples \" aspas duplas (") imprime aspas duplas \? sinal de interrogao (?)

Entrada e sada de dados \\ barra oposta (contrabarra) (\)

58

cin
O objeto cin obtm informao do "standard input" (que usualmente o teclado). Este objeto est tal como o cout declarado no cabealho da biblioteca <iostream> A sintaxe mais comum da instruo para obter dados do cin : cin >> [variable name]; Aqui temos o operador de extrao ">>" que diz que tudo o que o teclado escrever, coloque esses dados na varivel que me segue. Este operador consegue at traduzir o conceito de dados de fora para dentro. #include <iostream> using namespace std; int main(void) { int testScore; cin >> testScore; cout << "Your test score is " << testScore << "\n"; #ifdef WIN32 system ("pause"); /* Necessrio apenas para sistemas Microsoft, em modo grfico. Em UNIX, variantes e similares use um terminal de texto e esta funo no ser necessria. */ #endif return 0; } H mais um pormenor. O computador est espera de um "Return" ("ENTER", ou "New Line", ou Espao em Branco ) para finalizar a entrada de dados na varivel, at l o cursor aparece a piscar. Bem, na verdade, este ponto muito importante, por que Vejamos mais a baixo a questo de termos 2 entradas. Pergunta: declaramos uma varivel int testScore e se colocarmos um valor que no seja um int? Isto no a mesma situao do captulo anterior porque antes o programa ainda no tinha compilado, e agora temos entrada de dados quando o programa j est compilado e a correr/rodar. Assim se no exemplo anterior colocarmos o nome Jeff, que uma string, e o programa est a espera de um int, o que acontece que o cin no vai colocar "jeff" na varivel (ele ignora a entrada). E quando o cout chamado ele vai colocar o valor que est na varivel. Ento porque que me apareceu o nmero 858993460 quando corri/rodei o programa? que na memria fsica do computador existem dados da rea onde a varivel est alocada fisicamente, e quando declarei o testScore o compilador apenas reserva aquela memria mas no apaga o que l est. Pergunta: O que que acontece quando inserimos um nmero maior do que o limite do tipo quando o programa executar? o caso de "overflow" - estouro de memria, mas quando o programa corre/roda.

Entrada e sada de dados Aqui j no temos a questo de dar a volta ao intervalo permitido, aqui temos o caso em que vai ser colocado um nmero estranho. Isto no est perfeitamente explicado. Chama-se prompt quando dito ao utilizador o que deve fazer, o que no deixar como no exemplo anterior o cursor a piscar sem o utilizador saber o que fazer. Alm de que temos o problema de overflow em execuo, portanto bom que o utilizador cumpra os requerimentos. De uma maneira muito conveniente, os dados recebidos pelo cin so tratados de forma a tornar o processo polimrfico, da mesma forma que no caso de cout, assim temos como receber os dados da maneira que precisamos, ou seja, quando declaramos uma varivel int e a usamos para receber um dado do cin, o mesmo convertido na entrada para inteiro, quando usamos uma varivel de outro tipo, a entrada convertida para o tipo da varivel.

59

Lendo um caractere
Ler um caractere at simples, basta utilizar o objeto cin e ser guardado o valor digitado na varivel. char nivel; cout << "Entre um nvel: "; cin >> nivel; Porm teremos de pressionar a tecla ENTER depois de digitar o caractere. Isto leva a vrias questes. O problema pressione uma tecla para continuar...
#include <iostream> using namespace std; int main(void) { char ch; do { cout << "Pressione S ou s para sair, qualquer outra tecla para continuar: "; cin >> ch; if (ch != 'S' && ch != 's') cout << "Deseja continuar?"<<endl; else cout << "Saindo..."<<endl; } while (ch != 'S' && ch != 's'); #ifdef WIN32 system ("pause"); #endif return 0; }

O programa funciona bem se pressionarmos S ou s para sairmos; O programa funciona bem se pressionarmos qualquer outra tecla com caractere imprimvel; Mas se pressionarmos a tecla ENTER, nada acontece, o cin continua espera de entrada. A razo o operador de extrao ">>" ignora os espaos em branco e os caracteres "nova linha" resultantes do pressionamento da tecla enter.

Entrada e sada de dados

60

A funo cin.get()
J tivemos oportunidade para discutir a funo getline (funo membro) do objeto cin. cin.getline(name,80); Aqui vamos utilizar uma outra funo, a cin.get(). Esta funo pode ser chamada, tal como a getline(), atravs de 3 argumentos, onde o primeiro o array de caracteres, mas tambm o pode ser sem argumentos ou ainda apenas um argumento. No caso de no conter argumentos apenas ir ler um caractere, em vez de uma cadeia de caracteres. No caso de ter um argumento, ela aceita qualquer tecla incluindo o enter. (o que no se passa com o cin e o operador de extrao). Aqui um exemplo
#include <iostream> using namespace std; int main(void) { char ch; do { cout << "Pressione S ou s para sair, \nqualquer outra tecla para continuar: "; cin.get(ch); if (ch != 'S' && ch != 's') cout << "Deseja continuar?"<<endl; else cout << "Saindo..."<<endl; } while (ch != 'S' && ch != 's'); #ifdef WIN32 system ("pause"); #endif

return 0; }

Porm se pressionarmos uma tecla de caractere imprimvel, no conseguiremos inserir o prximo prompt, parece que houve um salto. Estranho! Para explicar a razo deste novo problema necessitamos de explicar o conceito de buffer. O "input buffer" uma rea de memria que guarda os caracteres de entrada, por exemplo do telado, at que essa entrada seja atribuda pelo cin e o operador de extrao >>, ou por funes como get() ou getline() do objeto cin. Quando o loop comea, o "input buffer" est vazio. Se digitarmos apenas o enter, sendo este o primeiro e nico caractere no "imput buffer", ele removido do input buffer e atribudo varivel ch, ento o "input buffer" est vazio na prxima iterao do loop; Se digitarmos x e enter. Temos 2 caracteres. A funo get() retira o primeiro caractere do "input buffer" e atribui varivel ch, mas nisto o caractere nova linha permanece no "input buffer". Isto faz com que na prxima iterao do loop, no haja a oportunidade para entrar com dados.

Entrada e sada de dados Ou seja, na segunda iterao, retirado o caractere nova linha que ficou da 1 iterao - e colocado na varivel ch. Agora o "input buffer" est vazio.

61

cin.ignore()
Uma soluo limpar o caractere nova linha do "input buffer" antes da chamada da funo getline(). E fazemos isso usando a funo ignore() do objeto cin. Esta funo membro tal com a get() e a getline() so sobrecarregadas, podem ser chamadas sem argumentos, com um ou dois argumentos. Utilizar a funo ignore() sem argumentos, permite que o prximo caractere no "input buffer" seja lido e depois descartado,- e isto exatamente aquilo que queramos. A funo com 1 ou 2 argumentos usada para cadeias de caracteres. Com um argumento, o argumento o nmero mximo de caracteres a ser removido do "input buffer". Exemplo: cin.ignore(80); // Remove at 80caracteres do input buffer Com dois argumentos, o segundo argumento o delimitador, um caractere que se encontrado, antes do nmero de caracteres especificado no primeiro paramento, faz com que a remoo pare. Exemplo: cin.ignore (80, '\n'); // Remove 80 caracteres se at l no encontrar o nova linha. Reescrevendo o cdigo anterior utilizando o cin.ignore()
#include <iostream> using namespace std; int main(void) { char ch; do { cout << "Pressione S ou s para sair,\n qualquer outra tecla para continuar: "; cin.get(ch); cin.ignore(); if (ch != 'S' && ch != 's') cout << "Deseja continuar?"<<endl; else cout << "Saindo..."<<endl; } while (ch != 'S' && ch != 's'); #ifdef WIN32 system ("pause"); #endif

return 0; }

Ora este programa funciona muito bem, MAS

Entrada e sada de dados Se pressionarmos a tecla Enter para continuar, teremos de fazer isso duas vezes, pois a primeira vez ignorada. A razo: que no existe nada no "input buffer" quando a funo ignore chamada, por isso que a tecla enter necessita de ser pressionada 2 vezes, colocando um caractere nova linha a mais no "buffer" para a funo ignore() remover. Se tentarmos modificar isto atravs do if?
#include <iostream> using namespace std; int main(void) { char ch; do { cout << "Pressionar S ou s para sair,\n qualquer outra tecla para continuar: "; cin.get(ch); if (ch != '\n') cin.ignore(); if (ch != 'S' && ch != 's') cout << "Deseja continuar?"<<endl; else cout << "Saindo..."<<endl; } while (ch != 'S' && ch != 's'); #ifdef WIN32 system ("pause"); #endif return 0; }

62

Agora sim temos todos os problemas resolvidos e isto agora funciona!!

cin, cin.get(), cin.getline()


O problema anterior do caractere nova linha permanece quando usamos o cin, o get() e o getline() juntos num programa, uma vez que o enter usado para terminar a entrada. #include <iostream> using namespace std; int main(void) { char name[80]; int courseNum; cout << "Informe o nmero do curso: "; cin >> courseNum; cout << "Informe seu nome: "; cin.getline(name, 80);

Entrada e sada de dados cout << "O nmero do curso : " << courseNum << endl; cout << "Seu nome : " << name << endl; #ifdef WIN32 system ("pause"); #endif return 0; } Aqui, neste exemplo, ns no tivemos a oportunidade de colocar o nome. Quando digitamos o nmero e depois pressionamos a tecla enter, o cin coloca o nmero no courseNUm mas o caractere nova linha permanece no "input buffer", que fica para o enter name, pois o getline l espaos em branco. A soluo pode ser: #include <iostream> using namespace std; int main(void) { char name[80]; int courseNum; cout << "Informe o nmero do curso: "; cin >> courseNum; cin.ignore(); cout << "Informe seu nome: "; cin.getline(name, 80); cout << "O nmero do curso : " << courseNum << endl; cout << "Seu nome : " << name << endl; #ifdef WIN32 system ("pause"); #endif return 0; } A partir destes exemplos podemos criar umas regras: 1. Colocar sempre a funo ignore() depois do cin e do >>; Razo: O "cin>>" deixa sempre o nova linha no "input buffer". Assim devemos elimin-lo com a funo ignore(). 2. No colocar a funo ignore(), no caso de ser sem parmetros, depois do getline(); Razo:O getline() remove o caractere nova linha que termina a entrada do "input buffer", portanto no necessrio o ignore(). 3. Verificar se temos o caractere nova linha no "input buffer" depois de utilizar o get(), se tivermos deveremos utilizar o ignore().

63

Entrada e sada de dados Razo: A funo get() com um argumento deixa o caractere nova linha no "input buffer" se pressionarmos um caractere e o enter. mas no deixar, se apenas pressionarmos o enter. portanto necessrio confirmar.

64

Entrada de valores para variveis mltiplas


Podemos fazer com que o programa receba vrios valores ao mesmo tempo cin >> [first variable] >> [second variable] >> [third variable]; Neste caso o utilizador separa os dados por espaos (o enter tambm d) e como anteriormente o utilizador fecha utilizando o enter
#include <iostream> #include <string> using namespace std; int main(void) { int peso, altura; string nome; cout << "escreva o seu nome, peso e altura \n separe os valores por espaos\n"; cin >> nome >> peso >> altura; cout << "o seu nome :" << nome << "\n"; cout << "o seu peso :" << peso << "\n"; cout << "a sua altura : " << altura<< "\n"; #ifdef WIN32 system ("pause"); /* Necessrio apenas para sistemas Microsoft, em modo grfico. Em UNIX, variantes e similares use um terminal de texto e esta funo no ser necessria. */ #endif return 0; }

Note-se que no exemplo anterior poderamos colocar as 3 variveis, mesmo no caso de elas serem de tipos diferentes. Temos de ter ateno na ordem de entrada. Pergunta: se escrevssemos duas palavras para o nome, apenas a primeira que apareceria a 2 palavra que estava separada da primeira para um espao seria colocada na varivel peso.

Entrada e sada de dados 2

65

Entrada e sada de dados 2


Entrada/Sada em ficheiros (arquivos)
Nota introdutria: Este capitulo geralmente colocado uns captulos mais para o fim, mas acho por bem que se torne as coisas mais interativas, o que possvel introduzindo agora operaes em arquivos, d muito mais entusiasmo. Encontramos aqui conceitos avanados mas podero ser deixados para depois se o leitor no quiser observar o tema neste momento.

Gravar (Salvar) os dados para um ficheiro(arquivo)


Os dados que mantemos nos programas esto guardados na memria RAM, que limpa quando o programa ou computador para de funcionar. Isso implicaria que perderamos toda a informao! Porm existe uma maneira para tornar os dados persistentes que gravar os dados num ficheiro (arquivo) no "hard drive" (disco rgido) ou no outro meio persistente. Nas formas mais diretas de escrita podemos passar os dados em formato binrio para o ficheiro(arquivo). Outros meios avanados para guardar dados podem envolver bases de dados relacionais ou XML.

O que um ficheiro(arquivo)?
Um arquivo uma coleo de dados que esto localizados numa memria persistente tipo hard drive, cd-rom, etc. Para identificarmos o arquivo podemos atribuir-lhe um nome (filename). Os "filenames" tm usualmente uma extenso, que determina o tipo de arquivo em sistemas operacionais semelhantes aos da Microsoft, mas que podem ser dispensados em sistemas operacionais que guardam as caractersticas dos arquivos no meio de armazenamento, tais quais sistemas UNIX e seus similares GNU/Linux, FreeBSD, etc... A extenso representada por 3 ou 4 letras que seguem aps o nome do arquivo e um ponto ".". Por exemplo: "joao.doc" ou "joao.odt". Isto diz-me que temos um ficheiro(arquivo) que se chama "joao", e que tem a extenso .doc que refere usualmente a documentos do WORD no primeiro caso e com extenso ".odt" do OpenOffice no segundo. Outros tipos de extenses podem ser ".xls" para documentos EXCEL, ".ods" para planilhas do OpenOffice. ou ainda ".cpp" para ficheiros(arquivos) de cdigos de c++.

Ficheiros(Arquivos) binrios e tipo texto


Existem na verdade dois tipos de ficheiros(arquivos): os do tipo texto e os do tipo binrio. Os arquivos tipo texto apenas armazenam texto obedecendo uma codificao de caracteres, a mais comum a ASCII, isto implica no uso do cdigo para armazenamento, ou seja, pode ser que a codificao seja interpretada antes de ser efetivada no meio de armazenamento. Os arquivos binrios podem guardar mais informao, como imagens, base de dados, programasPor exemplo, editores de texto com formatao, como o OpenOffice e o Word, guardam os seus arquivos em formatos binrios, porque eles possuem alm do texto, informao acerca da formatao do texto, para as tabelas, as listas numeradas, tipo de fonte, etc... da aparecerem os caracteres de formatao tipo 6, L, h5 Os arquivos binrios podero ser mais bem explorados em um tpico avanado, vamos trabalhar inicialmente com arquivos tipo texto, que poderemos operar de maneira mais simplificada.

Entrada e sada de dados 2

66

biblioteca padro fstream


At agora temos usado a biblioteca iostream (i de input + o de output + stream), que suporta, entre vrias funcionalidades, o objeto cin para ler da "standard input" (que usualmente o teclado) e o objeto cout para "standard output" (que usualmente o monitor) Ora, agora queremos ler e escrever para ficheiros(arquivos) e isso requer a biblioteca fstream (f de file + stream). Esta biblioteca define 3 novos tipos de classe: ofstream (apenas para sada "out to a file". serve para criar, manipular ficheiros (arquivos) e escrever, no serve para ler). ifstream (apenas para entrada "in from a file" . serve para ler ficheiros (arquivos), receber dados dos mesmos, no serve para criar nem escrever). fstream (este conjuga os dois tipos anteriores, "input and output to file". cria ficheiros (arquivos), escreve e l informao dos mesmos.

Abrir um ficheiro(arquivo)
Um ficheiro(arquivo) deve ser aberto pelo programa para que o mesmo possa ser manipulado, a abertura do arquivo implica, entre outras coisas, em atribuir um identificador que nos permita ter acesso aos seus dados. necessrio criar uma linha de comunicao entre o arquivo e o objeto stream. Podemos recorrer a dois mtodos para abrir um ficheiro (arquivo): 1. Usando um construtor; 2. Usando a funo membro chamada de "open".

Usando o Construtor
O construtor uma funo que automaticamente chamada quando tentamos criar uma instncia de um objeto. fstream afile; de afile // criado uma instncia do fstream chamada

Os construtores de objetos podem ser sobrecarregados, ou seja, para a mesma classe podemos ter um construtor sem argumentos, com um argumento, dois argumentos, etc. No exemplo anterior criamos um sem argumentos. Os construtores no retornam valores, geralmente o compilador reporta erro quando se declara funes que retornam valor e estas tm o mesmo nome da classe, pois este nome reservado para os construtores. Vamos dar um exemplo com dois argumento: ofstream outfile ("joao.doc", ios::out); Chama o construtor com dois argumentos, criando uma instncia de ofstream e abrindo o ficheiro(arquivo) "joao.doc" para operaes de sada.

Usando a funo membro "open"


Esta funo tem como primeiro argumento o nome e localizao do ficheiro/(arquivo) a ser aberto, o segundo argumento especifica o modo de abertura. Sobre a questo da localizao existem 2 tipos, o "path" relativo e o "path" absoluto. Para este ltimo indicamos o caminho todo: "c:\\....\\joao.doc" em sistemas Microsoft ou "/home/joao/joao.odt" para sistemas UNIX e similares. O "path" relativo dispensa essa descrio se o ficheiro/(arquivo) estiver (na mesma directoria)/(no mesmo diretrio) que o programa. Sobre a questo do modo de abertura temos as seguintes modalidades:

Entrada e sada de dados 2

67

Modo do abertura ios::app

sinalizador (Flag) "Append mode"

Descrio

Todos os dados do arquivo so preservados e qualquer sada escrita a partir do fim do arquivo.

ios::ate

Se o arquivo j existe,o programa vai diretamente ao seu fim.O modo de escrita ento feito de forma aleatria.Usado normalmente com arquivos do modo binrio(binary mode). "Binary mode" "Input mode" "Output mode" Informaes so escritas na forma binria e no na forma textual(text mode).

ios::binary

ios::in ios::out

Leitura de informaes de arquivo(no ir criar um arquivo novo) Informaes sero escritas no arquivo.

ios::trunc

Se o arquivo j existe,suas informaes sero truncadas, outra forma de se dizer: deletadas e reescritas.

Os sinalizadores (flags) so nmeros em potncias da base binria, portanto podemos ter vrios flags ao mesmo tempo se usarmos o operador unrio para a operao "OU", como no exemplo abaixo: ofstream outfile; //crio o objeto outfile outfile.open("students.dat", ios::binary | ios::app); /*chamo a funo membro open do objeto, com o 1 parmetro que o nome do arquivo e o 2 o modo de abertura. */ Observe que estamos abrindo o arquivo "students.dat" em modo binrio e ao mesmo tempo com o modo "append", isto significa que abriremos o arquivo e poderemos preservar o seu contedo anterior inserindo os novos dados no fim do arquivo.

Comparando os dois mtodos (pela funo membro e pelo construtor)


O primeiro mtodo similar a ter int age; age=39; O segundo mtodo similar a int age=39; A escolha do melhor mtodo em cada situao depende do contexto em que estamos criando o cdigo, geralmente quando j temos o objeto criado e ele est fechado podemos abrir um novo arquivo com ele e depois fech-lo novamente, isto nos sugere que usemos a funo open quando o objeto deve abrir arquivos diferentes em cada trecho de cdigo, embora que possam surgir outras funcionalidades, dependendo de como o projeto foi idealizado.

Entrada e sada de dados 2

68

Abrir um arquivo para leitura


A histria aqui a mesma s tem uma diferena: que no caso de leitura, no ser criado nenhum ficheiro (arquivo) caso ele no exista. ifstream arq; arq.open (joo.doc); "arq", com o //cria objeto "arq" //chama funo membro open ao objeto //parmetro do nome do ficheiro Poderamos fazer o mesmo com o construtor: ifstream arq (joo.doc); Ou ainda fstream bloco; bloco.open("joao.doc", ios::in) ou ainda fstream b(joao.doc, ios::in) H mais uma nota a fazer, se quisermos ler e escrever, no podemos usar o ofstream e o ifstream ao mesmo tempo, teremos de usar o fstream. Teremos de fazer: fstream a (joo.doc, ios::in | ios::out); Neste caso, o comportamento padro preservar o contedo do ficheiro (arquivo) ou cri-lo caso ele no exista.

Verificar se o ficheiro (arquivo) foi aberto.


Vamos verificar o que acontece quando tentamos abrir um arquivo que no existe, a primeira verso do nosso exemplo observa o comportamento bsico do fstream:
#include <fstream> #include <iostream> using namespace std; int main () { ifstream arq; ifstream - leitura arq.open("joao.doc"); //chamo funo membro open //imprime o objeto //chamo funo membro fail //crio objeto "arq" da classe

cout << "(arq) = " << arq << endl;

cout << "(arq.fail()) = " << arq.fail() << endl; #ifdef WIN32 system ("pause"); #endif return 0;

Entrada e sada de dados 2


}

69

No caso do ficheiro (arquivo) joao.doc no existir: (arq) = 00000000 (arq.fail()) = 1 No caso do ficheiro (arquivo) joao.doc existir no mesmo diretrio que o programa: (a) = 0012FE40 (a.fail()) = 0 Repare que o resultado a impresso do endereo, do objeto a de ifstream. d um ponteiro!! Agora, vajamos um exemplo mais completo:
#include <fstream> #include <iostream>

using namespace std;

int main () { ifstream arq; ifstream - leitura string str; //crio objeto "arq" da classe

arq.open("joao.doc");

//chamo funo membro open

if (arq.is_open() && arq.good()) { arq >> str; cout << "contedo: \n " << str << endl; //imprime o contedo do arquivo

arq.close(); }

#ifdef WIN32 system ("pause"); #endif

return 0; }

Observe que aqui verificamos se o arquivo foi aberto com a funo membro is_open() que retorna verdadeiro "true" caso o arquivo foi aberto, depois verificamos se o arquivo foi aberto satisfatoriamente atravs da funo membro good(), que tambm retorna verdadeiro se o arquivo pode ser usado.

Entrada e sada de dados 2

70

Fechar um ficheiro (arquivo)


Devemos fechar depois de ler e/ou escrever. Mas por que, se o objeto do ficheiro ir ser fechado assim que o programa acabar? Porque estamos a utilizar recursos com um ficheiro (arquivo) aberto, porque alguns sistemas operativos (operacionais) limitam o n de ficheiros (arquivos) abertos, e estando este aberto impede que outros se possam abrir e por fim porque se no fecharmos, outros programas no podero abri-lo at que o fechemos. Este comportamento faz parte de um esquema de controle de acesso usado pelo sistema para assegurar que os arquivos no sero usados por processos diferentes ao mesmo tempo. ofstream outfile; outfile.open("students.dat"); // .... outfile.close(); Vamos criar um exemplo mais real. Queremos criar um programa que escreva informao inserida pelo utilizador num ficheiro por ns escolhido
#include <fstream> #include <iostream> using namespace std; int main () { char data[80]; ofstream outfile; outfile.open("joao.doc"); para o objeto criado. // Esta funo membro cria o arquivo "joao.doc" if (outfile.is_open() && outfile.good()) //verificamos se est tudo bem { cout << "digite o seu nome: "; cin.getline(data, 80); do objeto cin para //ler o que foi escrito pelo usurio outfile << data << endl; outfile.close(); } #ifdef WIN32 system ("pause"); #endif return 0; //coloca o array no objeto criado. //fechamos o objeto. //imprime no ecr (monitor) a frase //chama funo membro getline //criamos um array de 80 caracteres //criamos objeto da classe ofstream //chamamos a funo membro da classe

Entrada e sada de dados 2


}

71

Podemos ir ver o novo ficheiro/arquivo com o nome joao.doc e tem l escrito aquilo que digitamos. Agora vamos tentar ler o que escrevemos no documento criado. #include <fstream> #include <iostream> using namespace std; int main () { char data[80]; ifstream infile; infile.open("joao.doc"); if (infile.is_open() && infile.good()) //verificamos se est tudo bem { infile >> data; //colocamos os dados abertos no array cout << data << endl; infile.close(); } #ifdef WIN32 system ("pause"); #endif return 0; } Repare que se tivssemos escrito duas palavras, apenas uma era apresentada (ela pra no primeiro whitespace), para isso necessitaramos de repetir: #include <fstream> #include <iostream> using namespace std; int main () { char data[80]; ifstream infile; infile.open("joao.doc"); if (infile.is_open() && infile.good()) //verificamos se est tudo bem { infile >> data; //colocamos os dados abertos no array cout << data << endl; infile >> data; //colocamos os dados abertos no array cout << data << endl; infile.close(); } #ifdef WIN32 system ("pause"); #endif

Entrada e sada de dados 2

72

return 0; } Agora j obtemos 2 palavras e so apresentadas em linhas diferentes. Mas temos de arranjar um mtodo para no estar a repetir constantemente, podemos fazer isso com infile.getline(data, 80); Ento ficamos com: #include <fstream> #include <iostream> #include <string> using namespace std; int main () { string data; ofstream outfile; outfile.open("joao.doc"); if (outfile.is_open() && outfile.good()) //verificamos se est tudo bem { cout << "Writing to the file" << endl; cout << "===================" << endl; cout << "Enter class name: "; getline(cin, data); outfile << data << endl; cout << "Enter number of students: "; cin >> data; cin.ignore(); //esta funo membro para limpar o caractere //newline do inputbuffer depois de usar o objeto //cin com o operador de extrao >> outfile << data<< endl; outfile.close(); } ifstream infile; infile.open("joao.doc "); if (infile.is_open() && infile.good()) //verificamos se est tudo bem { cout << "Reading from the file" << endl; cout << "=====================" << endl; getline(infile, data); cout << data << endl;

Entrada e sada de dados 2 getline(infile, data); cout << data << endl; infile.close(); } #ifdef WIN32 system ("pause"); #endif return 0; }

73

Looping pelo ficheiro (arquivo).


E se no soubermos quantas linhas tem o arquivo? O objeto ifstream tem uma funo membro que a eof() (e-end+o-of+f-file). Esta funo no tem parmetros e retorna "true" se o fim do arquivo for alcanado e "false" caso contrrio. No entanto, esta funo eof() no de confiana com os ficheiros (arquivos) texto como o para os binrios ( que nos ficheiros (arquivos) binrios no existem espaos em branco). A melhor alternativa usar a funo membro fail(). ifstream infile; infile.open("joao.doc"); if (infile.is_open() && infile.good()) { infile >> data; while(!infile.fail()) { infile >> data; cout << data; } infile.close(); } Refazendo tudo #include <fstream> #include <iostream> #include <string> using namespace std; int main () { string data; ofstream outfile; outfile.open("joao.doc"); if (outfile.is_open() && outfile.good())

Entrada e sada de dados 2 { cout << "Escrevendo no arquivo" << endl; cout << "===================" << endl; cout << "Informe o nome da classe: "; getline(cin, data); outfile << data<< endl; cout << "informe o nmero de estudantes: "; cin >> data; cin.ignore(); outfile << data<< endl; outfile.close(); } ifstream infile; infile.open("joao.doc"); if (infile.is_open() && infile.good()) { cout << "Lendo do arquivo" << endl; cout << "=====================" << endl; getline(infile, data); while(!infile.fail()) { cout << data << endl; getline(infile, data); } infile.close(); } #ifdef WIN32 system ("pause"); #endif return 0; } Agora vamos fazer o nosso programa mais modular: 1. . writeFile para abrir um arquivo para escrita usando o ofstream e 2. . readFile - ler do ficheiro (arquivo) usando o ifstream 3. . Cada funo ir verificar se o ficheiro (arquivo) foi aberto com sucesso #include <fstream> #include <iostream> #include <string> using namespace std;

74

Entrada e sada de dados 2

75

bool writeFile (ofstream&, char*); bool readFile (ifstream&, char*); int main () { string data; bool status; ofstream outfile; status = writeFile(outfile, "students.dat"); if (!status) { cout << "Arquivo no pode ser aberto para escrita.\n"; cout << "Programa terminando...\n"; return 0; } else { cout << "Escrevendo no arquivo" << endl; cout << "===================" << endl; cout << "Informe o nome da classe: "; getline(cin, data); outfile << data<< endl; cout << "Informe o nmero de estudantes: "; cin >> data; cin.ignore(); outfile << data<< endl; outfile.close(); } ifstream infile; status = readFile(infile, "students.dat"); if (!status) { cout << "O arquivo no pode ser aberto para leitura.\n"; cout << "Programa terminando...\n"; return 0; } else { cout << "Lendo do arquivo" << endl; cout << "=====================" << endl; getline(infile, data); while(!infile.fail()) { cout << data << endl;

Entrada e sada de dados 2 getline(infile, data); } infile.close(); } #ifdef WIN32 system ("pause"); #endif return 0; } bool writeFile (ofstream& file, char* strFile) { file.open(strFile); return !(file.fail()||!file.is_open()||!file.good()); } bool readFile (ifstream& ifile, char* strFile) { ifile.open(strFile); return !(ifile.fail()||!ifile.is_open()||!ifile.good()); }

76

Manipuladores
Os objetos das classes "stream" podem ser configurados para fornecer e reportar os dados de maneira pr-formatada. Da mesma maneira que temos a formatao quando usamos funes de formatao, como printf() e scanf(), na linguagem C, podemos usar os manipuladores na linguagem C++ para informar os objetos streams em que formato desejamos receber os dados deles ou fornecer para eles. Abaixo temos uma srie de manipuladores teis:
Manipulator boolalpha Uso Faz com que variveis tipo bool sejam reportadas como "true" ou "false".

noboolalhpa (padro) Faz com que variveis tipo bool sejam reportadas omo 0 ou 1. dec (padro) hex oct left right internal noshowbase (padro) showbase Determina que variveis tipo inteiras (int) sejam reportadas na base 10. Determina que variveis tipo inteiras (int) sejam reportadas em hexadecimal. Determina que variveis tipo inteiras (int) sejam reportadas em octal. Faz com que textos sejam justificados a esquerda no campo de sada. Faz com que textos sejam justificados a direita no campo de sada. Faz com que o sinal de um nmero seja justificado a esquerda e o nmero seja justificado a direita. Desativa a exibio do prefixo que indica a base do nmero. Ativa a exibio do prefixo que indica a base do nmero.

noshowpoint (padro) Mostra o ponto decimal apenas se uma parte fracionria existe. showpoint Mostra o ponto decimal sempre.

Entrada e sada de dados 2

77
Nenhum sinal "+" prefixado em nmeros positivos. Mostra um sinal "+" prefixado em nmeros positivos. Faz com que espaos em branco, tabulaes, novas linhas "\n" sejam descartados pelo operador de entrada >>. Faz com que espaos em branco, tabulaes, novas linhas "\n" no sejam descartados pelo operador de entrada >> Faz com que nmeros com ponto flutuante sejam mostrados em notao fixa. Faz com que nmeros com ponto flutuante sejam mostrados em notao cientfica.

noshowpos (padro) showpos skipws (padro) noskipws fixed (padro) Scientific

nouppercase (padro) 0x mostrado para nmeros em hexadecimal e para notao cientfica. uppercase 0X mostrado para nmeros em hexadecimal e para notao cientfica.

Ajustando a largura da entrada/sada


setw(w) - Ajusta a largura da sada e entrada para w; precisa ser includo. width(w) - Uma funo membro das classes iostream.

Preenchimento de espaos em branco


setfill(ch) - Preenche os espaos em branco em campos de sada com ch; precisa ser includo. fill(ch) - Uma funo membro das classes iostream.

Ajustando a preciso
setprecision(n) - Ajusta a preciso de casas decimais em nmeros com ponto flutuante, para n dgitos. Este ajuste apenas visual, de forma que o manipulador no afeta o modo de clculo do nmero pelo programa. Exemplificando o uso de manipuladores: #include <iostream> #include <iomanip> #include <string> using namespace std; int main() { int intValue = 15; cout cout cout cout cout cout cout cout cout cout << << << << << << << << << << "Nmero inteiro" << endl; "Padro: " << intValue << endl; "Octal: " << oct << intValue << endl; "Hexadecimal: " << hex << intValue << endl; "Ativando showbase " << showbase << endl; "Decimal: " << dec << intValue << endl; "Octal: " << oct << intValue << endl; "Hexadecimal: " << hex << intValue << endl; "Desativando showbase " << noshowbase << endl; endl;

double doubleVal = 12.345678; cout << "Nmeros com ponto flutuante" << endl;

Entrada e sada de dados 2 cout cout cout cout cout cout cout << << << << << << << "Padro: " << doubleVal << endl; setprecision(10); "Preciso de 10: " << doubleVal << endl; scientific << "Notao cientfica: " << doubleVal << endl; uppercase; "Caixa alta: " << doubleVal << endl; endl;

78

bool theBool = true; cout cout cout cout << << << << "Booleano" << endl; "Padro: " << theBool << endl; boolalpha << "BoolAlpha ativo: " << theBool << endl; endl;

string myName = "John"; cout << "Strings" << endl; cout << "Padro: " << myName << endl; cout << setw(35) << right << "Com setw(35) e \"right\": " << myName << endl; cout.width(20); cout << "Com width(20): " << myName << endl; cout << endl; #ifdef WIN32 system ("pause"); #endif return 0; }

Exerccios
1. Quero colocar num documento, uma lista das combinaes possveis entre a,b,c e d. com a respectiva ordenao e quantidade; 2. . Quero que seja a pessoa a escolher o nome do ficheiro (arquivo) e escrever tambm a localizao; 3. . Quero que seja depois tansformado num sistema modular; 4. . Encontrar uma maneira para contar o n de espaos em branco, o n de caracteres "." que quisermos de um dado documento. #include <iostream> #include <fstream> using namespace std; int main() { int blank_count = 0;

Entrada e sada de dados 2 int char_count = 0; int sentence_count = 0; char ch; ifstream object("jo.txt"); if (! object) { cout << "Erro abrindo arquivo." << endl; return -1; } while (object.get(ch)) { switch (ch) { case ' ': blank_count++; break; case '\n': case '\t': break; case '.': sentence_count++; break; default: char_count++; break; } } cout << "Existem " << blank_count << " espaos em branco;" << endl; cout << "Existem " << char_count << " caracteres;" << endl; cout << "Existem " << sentence_count << " sentenas." << endl; #ifdef WIN32 system ("pause"); #endif return 0; }

79

Manipulando strings

80

Manipulando strings
"Char strings" e Strings
Os caracteres so entendidos como sendo nmeros que geralmente tm oito bits, esses nmeros so traduzidos na tabela ASCII de 128 caracteres, como existem inmeras regies no mundo com caractersticas lingusticas prprias, a tabela ASCII estendida por um bloco de caracteres acima dos 128 mais baixos que varia de acordo com as necessidades de cada lngua. A parte superior da tabela ASCII conhecida como parte estendida e referenciada por pginas de cdigos para cada propsito lingustico, isso quer dizer que podemos ter os mesmos nmeros significando caracteres diferentes para cada regio do mundo. No estilo da linguagem C quando queremos representar um conjunto de caracteres colocamos todos eles em uma matriz sequenciada na memria:
Endereo relativo 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A Dado U m a f r a s e .

Por exemplo, para declarar um espao na memria que contenha 20 caracteres fazemos: char dados[20]; Este o estilo de strings usado pela linguagem C pura. Para manipular este tipo de string preciso ter certo cuidado, pois a matriz sempre tem um tamanho definido e caso faamos um acesso a um endereo fora da matriz invadiremos outras reas de memria que no temos como definir o que so, e portanto poderemos fazer o programa parar de funcionar, em muitos sistemas pode tambm haver danos aos outros programas e at mesmo ao prprio sistema operacional, porm em sistemas operacionais mais sofisticados como o GNU/Linux, que possuem gerenciamento de memria com proteo de memria, apenas o programa que causou a falha ir parar de funcionar. Para manipular este tipo de string a biblioteca padro da linguagem C dispe de diversas funes, para mais detalhes consulte o livro Programar em C. No estilo C++, como era de se esperar, as strings so objetos, eles podem ser criados facilmente atravs da biblioteca padro referenciada pelo arquivo de cabealho <string>. As strings so objetos com recursos que permitem manipular os seus caracteres com as funcionalidades das funes da linguagem C e mais algumas caractersticas prprias possibilitadas pela orientao a objetos. // listandoCodigoASCII.cpp #include<iostream> using std::cout; using std::cin; using std::endl; #include<string> using std::string; using std::getline;

int main(){ string anyWord;

Manipulando strings cout << "Digite uma palavra: "; getline(cin, anyWord); for ( int i = 0; i < anyWord.length(); i++) cout << anyWord[i] << " - " << (int)anyWord[i] << endl; cout << endl; return 0; } //end main

81

Funes de caracteres teis.


As seguintes funes esto no cabealho da biblioteca <cctype> toupper() (to+upper) retorna a maiscula de uma letra. uma funo de um argumento o caractere. no caso do argumento no ser uma letra, a funo retorna o mesmo caractere que argumento. tolower() (to+lower) o mesmo comportamento que toupper(), porm com o resultado em minscula.
#include <iostream> #include <cctype> using namespace std; int main(void) { char ch; do { cout << "Pressionar S ou s para sair, \nqualquer outra tecla para continuar: "; cin.get(ch); ch = toupper(ch); if (ch != '\n') cin.ignore(); if (ch != 'S') cout << "Deseja continuar?\n"; else cout << "Saindo..."; } while (ch != 'S'); #ifdef WIN32 system ("pause"); #endif return 0; }

Funes que verificam o caractere. Estas funes recebem apenas um argumento, o caractere e retornam um valor booleano.

Manipulando strings

82

Funo isalpha

Descrio Retorna verdadeiro se o argumento uma letra do alfabeto; falso em caso contrrio.

isalnum Retorna verdadeiro se o argumento uma letra do alfabeto ou um dgito; falso em caso contrrio. isdigit Retorna verdadeiro se o argumento um dgito; falso em caso contrrio.

islower Retorna verdadeiro se o argumento uma letra minscula, falso em caso contrrio. isprint ispunct Retorna verdadeiro se o argumento um caractere imprimvel (inclundo espaos); falso em caso contrrio. Retorna verdadeiro se o argumento um sinal de pontuao (caracteres imprimveis que no sejam letras, dgitos ou espao); falso em caso contrrio.

isupper Retorna verdadeiro se o argumento uma letra maiscula; falso em caso contrrio. isspace Retorna verdadeiro se o argumento um espao, tabulao ou nova linha; falso em caso contrrio.

Strings em C++
As cadeias de caracteres da linguagem C podem formatar um novo tipo de dados, porm criar tipos de dados mais sofisticados no possvel nesta linguagem, as strings em C++ so objetos da classe string, o que isso traz de novo para o tratamento de textos em programas? A primeira coisa a notar quando criamos strings em C++ a maneira de cri-las, a classe disponibiliza uma srie de construtores: 1 2 3 4 5 6 string string string string string string ( ( ( ( ( ( ); const string& st ); const string& st, size_t position, size_t n = npositions ); const char * ps, size_t n ); const char * ps ); size_t n, char ch );

Isto torna possvel, basicamente, criar string de seis maneiras diferentes: 1. 2. 3. 4. 5. 6. Podemos definir um objeto string vazio, para futuramente usarmos de acordo com a necessidade; Podemos criar um objeto string com uma cpia de outro; Podemos criar um objeto string com uma cpia de uma poro de outra string; Podemos criar um objeto string com uma cpia de uma parte de uma "char string"; Podemos criar um objeto string com uma cpia de uma "char string"; Podemos criar um objeto string preenchida com uma quantidade definida de um determinado caractere;

Quando manipulamos strings, podemos faz-lo com operadores, como por exemplo "+", "+=", "<<", etc... Isto torna o cdigo um pouco mais intuitivo, vejamos os operadores: 1 2 3 4 5 6 operator= operator[] operator+= operator+ operator<< operator>>

Que representam as operaes: 1. 2. 3. 4. Atribuir o valor de uma string para outra; Acessar caracteres individualmente; Adicionar uma string no final de outra; Concatenar strings;

Manipulando strings 5. Enviar uma string a um output stream; 6. Receber uma string do input stream. Apenas com estas poucas informaes j possvel operar strings com bastante flexibilidade e de uma maneira muito intuitiva, vejamos alguns exemplos: string a = "Alice e Beto gostam de ", b("chocolate."), c = string("doce de leite."), d = "pipoca.", e(c); cout cout cout cout << << << << a a a a + + + + b c d e << << << << endl; endl; endl; endl;

83

Estas operaes resultam em: Alice Alice Alice Alice e e e e Beto Beto Beto Beto gostam gostam gostam gostam de de de de chocolate. doce de leite. pipoca. doce de leite.

Exemplos de como manipular strings em C++


erase A funo membro erase elimina parte de uma string. Os parmetros passados para a funo so a posio inicial e o nmero de caracteres a ser excludo. Veja um exemplo de uso abaixo: #include<iostream> using std::cout; using std::endl; using std::cin; #include<string> using std::string; using std::getline; int main(){ string myText; cout << "Digite um texto qualquer" << endl; getline( cin, myText ); myText.erase(7, 3); cout << myText << endl; return 0; }

Manipulando strings

84

Comparando formas de operar strings em C e C++


Em C, temos diversas funes que so usadas para manipular strings, para mais detalhes veja o livro Programar em C, aqui faremos uma comparao dos modos de operar strings em C e C++, algumas particularidades da linguagem C++ permitem uma operao mais intuitiva das strings e algumas novas formas de trat-las. Vejamos como manipular estes dados to comuns em qualquer programa.

Funes uteis para o uso de strings


strlen() (str=string + len=length)- aceita um argumento que pode ser um array (uma cadeia) de caracteres, um ponteiro (que aponta para um array de caracteres) ou uma string literal. retorna um nmero inteiro que representa o nmero de caracteres, no incluindo o caractere "null": int len; len = strlen("Jeff") // a extenso 4 char* stinkydog = "Dante"; len = strlen(stinkydog); // a extenso 5 char name[80] = "Devvie"; len = strlen(name); // a extenso 6 No c++ temos duas funes similares na classe string que so o lenght() e size(). Estas funes no tem argumentos pois reportam as informaes sobre o objeto a quem pertencem, ambas retornam um inteiro que representa o tamanho das strings: string s = "Jeff Kent"; cout << s.length(); // mostra: 9 cout << s.size(); // tambm mostra: 9

Copiando strings
Se tentssemos copiar strings desta maneira char* target = "Jeff Kent"; char src[80] = "Micaela"; target = src; O que acontecia que era a cpia do endereo de src para o ponteiro e no os caracteres que esto dentro da matriz. No entanto existe a funo strcpy (estilo C) ela aceita dois argumentos, O primeiro para onde vai ser copiada e passado o ponteiro desse array (no pode ser uma string literal). O segundo a frase a ser copiada e pode ser um array, um ponteiro ou um string literal char* target = "Jeff Kent"; char src[80] = "Micaela"; strcpy(target, src); Note que esta operao muito arriscada visto que, quando criamos target, a quantidade de caracteres que foi reservada para a string era de 9 caracteres mais o caractere nulo no final, se fizermos uma cpia de uma string com mais de 9 caracteres para este endereo, representado por target, ele fatalmente causar uma violao de endereo. Porm em C++ podemos atribuir o valor de uma varivel para outra da classe string da forma: string target = "Jeff Kent"; string src = "Micaela"; target = src;

Manipulando strings Agora, reflitamos no que significa estas operaes: Em primeiro lugar "string" no um tipo primitivo de dado, uma classe, portanto um tipo de dado mais "inteligente", uma das caractersticas dos objetos string que eles so redimensionveis, ou seja, quando atribumos a uma string um dado maior que seu espao interno de armazenamento ela aumenta o seu espao interno para comportar o novo dado. Outra caracterstica que a operao "=" para a string uma operao de atribuio de contedo, de forma que a string copia a outra quando usamos este operador e no apenas o ponteiro que referncia o endereo da string.

85

Unir strings
strcat() (string+concatenate) une duas frases. Recebe 2 argumentos, a frase primria o ponteiro para esse array. char target[80] = "Jeff"; char* source= " Kent"; strcat(target, source); cout << target; // Mostra "Jeff Kent" Deve-se observar que strcat , potencialmente, uma das rotinas mais perigosas do C, por um motivo bem simples: a string de destino deve ser pre-dimensionada, e deve ter espao suficiente para receber a string de origem. Um pequeno programa como: char target[13] = "Regras do C!"; char* source = " Mas pode dar resultados imprevisiveis"; strcat(target, source); Escrever bytes em regies da memria que no foram previamente alocadas para a string. Em c++, este problema resolvido pelo uso de objetos string. Ao estilo de c++ podemos fazer. string target = "Regras do C++!\n"; string source = " Geralmente no do resultados imprevisiveis.\n"; target += source; cout << target; // Mostra: Regras do C++! // Geralmente no do resultados imprevisiveis. Isto porque a classe string prev o uso do operador "+=" de concatenao e nele est embutido um cdigo de verificao de espao e realocao do mesmo para string, caso seja necessrio.

comparar frases
se fizessemos char str1[80] = "Devvie Kent"; char str2[80] = "Devvie Kent"; if (str1 == str2) cout << "The two C-strings are equal"; else cout << "The two C-strings are not equal"; o que acontecia que estariamos a comparar os endereos e no os valores temos a funo strcmp (string+compare) (tem 2 arguentos. retornar 0 se forem iguais)

Manipulando strings char str1[80] = "Devvie Kent"; char str2[80] = "Devvie Kent"; if (!strcmp(str1, str2)) cout << "The two C-strings are equal"; else cout << "The two C-strings are not equal"; esta comparao pode ser resultar em negativo e positivo e isso tem a ver com o jogo de caracteres na tabela ascII. aqui vai um resumo Resultados de comparaes entre strings
Primeira string (str1) Jeff aZZZ chess Segunda string (str2) jeff Zaaa check strcmp(str1, str2) negativo positivo positivo j tem valor ASCII maior que J a tem valor ASCII maior que Z Os primeiros trs caracteres so os mesmos, mas a quarta letra da primeira string-C, s, tem maior valor ASCII que a quarta letra da segunda string-C, c. Os quatro primeiros caracteres so os mesmos, mas o quinto caractere da segunda string-C, r, tem valor ASCII maior que o caractere nulo na quinta posio da primeira string-C. Razo

86

Jeff

Jeffrey

negativo

Em C++ podemos comparar duas strings atravs da funo membro da classe string: compare(), existem os seguintes formatos (assinaturas) para a funo: 1 int compare ( 2 int compare ( 3 int compare ( 4 int compare ( 5 int compare ( pos2, size_t n2 6 int compare ( const; const string& str2 ) const; const char* szc ) const; size_t pos1, size_t n1, const size_t pos1, size_t n1, const size_t pos1, size_t n1, const ) const; size_t pos1, size_t n1, const

string& str2 ) const; char* szc) const; string& str2, size_t char* szc, size_t n2)

A funo permite os seguintes modos de operao, respectivamente: 1. Comparar uma "string" de entrada (str2) com o contedo do objeto a qual ela pertence; 2. Comparar uma "C-string" apontada por um ponteiro com o contedo do objeto a qual ela pertence; 3. Comparar uma seo comeando em (pos1) do objeto, a qual contm (n1) caracteres, com a "string" de entrada (str2); 4. Comparar uma "C-string" apontada por um ponteiro (szc), com uma seo comeando em (pos1), a qual contm (n1) caracteres do contedo do objeto a qual ela pertence; 5. Comparar uma seo do objeto, iniciada em (pos1) com (n1) caracteres, com uma seo de (str2), iniciada em (pos2) com (n2) caracteres; 6. Comparar uma "C-string" apontada por um ponteiro (szc) de extenso (n2), com uma seo comeando em (pos1), a qual contm (n1) caracteres do contedo do objeto a qual ela pertence. O resultado similar ao da funo strcmp() em "C", retornando uma referncia de valor de acordo com o cdigo ASCII. Se estiver comparando duas strings uma outra opo, ainda mais natural, utilizar os operadores de comparao < e ==.

Manipulando strings using namespace std; string str1 = "check"; string str2 = "chess"; if (str1 == str2) cout << "As palavras so iguais." << endl; else if (str1 < str2) cout << "A palavra " << str1 << " vem antes de " << str2 << endl; else cout << "A palavra " << str1 << " vem depois de " << str2 << endl;

87

Convertendo C-string e nmero


No ficheiro (arquivo) cabealho da biblioteca cstdlib (c+std+lib) temos vrias funes de converso de nmeros em tipo numrico. atoi (acrnimo para "ASCII to integer") recebe um argumento c-string) e retorna o inteiro que a c-string representa. No verifica se o argumento pode ser convertido: int num = atoi("7654"); Programa exemplo: #include <iostream> #include <cstdlib> // necessrio para atoi #include <cstring> using namespace std; int main(void) { char input[80]; int num; cout << "Enter an integer: "; cin >> input; for (int x = 0; x < strlen(input); x++) { if (x == 0) { if (!isdigit(input[x]) && input[x] != '-') return 1; } else { if (!isdigit(input[x])) return 2; } } num = atoi(input); cout << num;

Manipulando strings

88

#ifdef WIN32 system ("pause"); #endif return 0; } Neste exemplo temos a vantagem de o usurio inserir um dgito para o array de caracteres em vez de um inteiro, para evitar um "run-time error" ou "garbage data" que aconteceria se a entrada fosse no numrica. Depois o array verificado para ver se representa um nmero. Se o numero for negativo tem o caractere "". Em C++ usamos objetos da classe stringstream (biblioteca sstream.h) para armazenar temporariamente os caracteres, depois usamos o operador ">>" para converter os caracteres em nmero, bastando para isto criar a varivel no formato que desejamos receber o nmero. Mais uma vez temos o uso do poliformismo para resoluo de um problema comum de programao, a operao do ">>" diferente para cada tipo de dado, selecionada automaticamente pelo compilador de acordo com o tipo de dado da varivel destino. string name = "123"; stringstream sst; int i; sst << name << endl; sst >> i; Os passos acima armazenam o valor 123 na varivel "i", todo processo de converso feito pelo operador ">>".

Classes
Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

Classes
Existem duas categorias de tipos de dados usuais em C++, so classificados como tipos bsicos e tipos definidos pelo programador. Assim como na linguagem C, podemos definir dados compostos por associaes dos tipos bsicos, estes tipos so chamados de estruturas (structs). C++ traz uma nova representao de dados, muito semelhante na forma s estruturas, porm diferentes na forma conceitual: a palavra chave class, que usada para criar uma classe de objetos mais rica que as structs. Ao declararmos um identificador, tal qual fazemos ao declarar uma varivel e no lugar do tipo especifiquemos uma classe criaremos um objeto. Antes de prosseguirmos, vejamos um pouco sobre o conceito por trs do uso de objetos. Um objeto entendido como uma entidade de dados dentro da memria que, basicamente, deve ser responsvel por seu contedo, ou seja, um objeto deve ser capaz de gerenciar seu contedo autonomamente, ou prover meios de outras entidades de cdigo faz-lo de forma segura.

Classes

89

Origem (atributos)
Observemos, por exemplo, o cdigo abaixo: struct MyData { int n; char data[10]; float nReal; }; Esta declarao, bem conhecida de quem j est familiarizado com a linguagem C, cria um tipo de dado composto heterogneo, que neste exemplo chamamos de MyData, o que acontece aqui que os dados esto agrupados dentro desta estrutura, isto promove a possibilidade de manipul-los em conjunto. Um dos problemas com esta estrutura a presena de uma matriz de caracteres chamada "data", observe que a mesma tem um tamanho definido de 10 caracteres, imagine que em algum momento da execuo do programa tentamos colocar um caractere na posio 11, ou qualquer posio fora da matriz, neste caso estamos colocando o referido dado em endereos invlidos para a operao que pretendemos realizar, ou seja, no h controle nenhum que assegure que o cdigo no far um acesso fora da rea que pertena a matriz. Um acesso de memria a qualquer elemento da matriz acima da posio 9, far com que invadamos dados na rea onde a varivel nReal est definida.

Funes membro (Mtodos)


Agora suponha que tenhamos como definir um modo para entrar e outro para ler dados da matriz: struct MyData { int n; char data[10]; float nReal; bool write_data(int pos, char c) { if (pos >= 0 && pos < 10) { data[pos]=c; return true; } return false; } char read_data(int pos) { if (pos >= 0 && pos < 10) { return data[pos]; } return '\0'; } }; Agora temos assegurados mtodos de incluso e acesso a dados da matriz de caracteres, porm ainda existe um pequeno problema: Quem quiser o antigo mtodo de acesso direto conseguir facilmente, pois os elementos da estrutura esto acessveis publicamente por padro.

Classes

90

Conceituao
O problema da visibilidade pblica dos dados em uma estrutura pode ser resolvido com um dos conceitos de objetos, o encapsulamento. Encapsular os dados, significa reservar o acesso a funes que estejam dentro de um grupo restrito, especializado para tais operaes de manipulao destes dados. Uma das vantagens deste procedimento que o cdigo adquire um formato mais organizado, onde os processos tornam-se claramente distintos, caso tenhamos que analisar o cdigo, cada procedimento estar restrito a partes definidas para cada operao.

Declarando classes
As estruturas so bem parecidas com as classes, com uma pequena diferena, peguemos o caso da passagem de estruturas como argumentos de funes: #include <iostream> #include <string> using namespace std; class Person { string name; int height; }; void setValues(Person&); void getValues(const Person&); int main () { Person p1; setValues(p1); cout << "Informando dados sobre a pessoa:\n"; cout << "================================\n"; getValues(p1); return 0; } void setValues(Person& pers) { cout << "Informe o nome da pessoa: "; getline(cin, pers.name); cout << "Informe a altura em milmetros: "; cin >> pers.height; cin.ignore(); } void getValues(const Person& pers) { cout << "Nome da pessoa: " << pers.name << endl;

Classes cout << "A altura da pessoa em milmetros : " << pers.height << endl; } Mudamos o identificador de struct para class Mas se tentarmos compilar o programa isto vai causar erros de compilao, porque agora temos variveis membro que so privadas por padro, estas no so vistas por funes fora da classe. Dentro de uma classe podemos definir diversos modos de visibilidade de variveis e funes. As modalidades podem ser: private (s podem ser acessados por membros da mesma classe) public (pode ser acessadas fora do objeto, onde este estiver definido) protected (deixemos esta para quando falarmos em classes derivadas, pois depende deste conceito). Ora, como as funes getValues e setValues no so membros da classe Person, tal como o construtor Person, no conseguem acessar as variveis "name" e "height". Visualizamos melhor em forma de tabela:

91

Class Person private string name Int height

p1

A soluo criar funes publicas, para ler de e escrever para as variveis privadas: #include <iostream> #include <string> using namespace std; class Person { private: string name; int height; public: string getName() const; void setName(string); int getHeight() const; void setHeight(int); }; string Person::getName() const { return name; } void Person::setName(string s) { if (s.length() == 0) name = "No name assigned";

Classes else name = s; } int Person::getHeight() const { return height; } void Person::setHeight(int h) { if (h < 0) height = 0; else height = h; } void setValues(Person&); void getValues(const Person&); int main () { Person p1; setValues(p1); cout << "Outputting person data\n"; cout << "======================\n"; getValues(p1); return 0; } void setValues(Person& pers) { string str; int h; cout << "Enter person's name: "; getline(cin,str); pers.setName(str); cout << "Enter height in milimeters: "; cin >> h; cin.ignore(); pers.setHeight(h); } void getValues(const Person& pers) { cout << "Person's name: " << pers.getName() << endl; cout << "Person's height in milimeters is: " << pers.getHeight() << endl; }

92

Classes Mas perguntam: Por que que nos demos ao trabalho de recorrer a membros privados em vez de fazer todos pblicos? Quando tnhamos uma estrutura no lugar de uma classe, no havia nada que impedisse a colocao de valores invlidos, por isso poderamos ter valores vazios para a string e valores negativos para a varivel "height". Agora que "Person" uma classe, as funes membro podem realizar a validao dos dados antes da atribuio de valores nas variveis. Poderamos fazer com que a funo setName verificasse se a entrada na string seria vazia e caso fosse, colocaria um valor padro como: sem nome. similarmente poderamos ter "setHeight" para verificar se seriam colocados valores de entrada negativos e caso fossem, colocaria zero, ou no tomaria nenhuma ao. Todas estas caractersticas demonstram o conceito de encapsulamento. A sua finalidade de tornar o cdigo mais modularizado, restringindo o escopo de anlise a partes bem delimitadas dos programas. Devido a este conceito podemos contar com cdigos mais fceis de analisar e fazer manuteno.

93

Instanciando objetos
Instanciao de objetos o processo de criar a estrutura lgica dos mesmos na memria. Isto ocorre quando declaramos os objetos, pois neste momento todo o processo de construo dos mesmos efetivado. Assim, toda vez que declaramos um objeto estamos instanciando-o, ou seja, estamos criando uma instncia da classe. Podemos declarar os objetos logo aps definir a classe conforme podemos ver no 1 caso logo abaixo. Neste caso teremos a varivel rect criada como um objeto conforme estabelecido pelo modelo definido pela palavra chave class. Este tipo de declarao mais usual para objetos criados globalmente, pois a incluso desta declarao no cabealho pode fazer com que vrios objetos sejam criados com o mesmo nome quando o cabealho invocado de vrios arquivos. Portanto, mais prudente usar esta opo quando a declarao est no arquivo fonte e no no cabealho. 1 caso: class CRectangle { int x, y; public: void set_values (int,int); int area (void); } rect; No 2 caso, apresentado logo abaixo, podemos declarar objetos apenas quando precisarmos. Esta opo de declarar o objeto depois a mais usada, pois na maioria das vezes temos o modelo dos objetos, a classe, declarada em um arquivo de cabealho enquanto que os objetos sero criados no resto do cdigo fonte. Desta forma mais usual criar as classes em cabealhos e depois declarar os objetos na parte do programa que for mais conveniente. 2 caso: class CRectangle { int x, y; public: void set_values (int,int); int area (void); }; int main() { CRectangle rect;

Classes } Em ambos os casos temos

94

CRectangle Private int x int y

public

void set_values (int,int); int area (void);

rect

Podemos, ento, entender os objetos como blocos de dados que tm propriedades (variveis) e que podem fazer algo (mtodos). Ento, criamos todas as funcionalidades que precisamos que a classe fornea aos programas, fazendo os testes necessrios para assegurar sua consistncia e estabilidade. Sempre que precisemos utilizar os objetos s temos que instanci-los (declar-los), e no precisamos nos preocupar como eles funcionam internamente, uma vez que os desenhamos adequadamente. Para entendermos melhor este conceito podemos fazer uma analogia. Consideremos um objeto resistncia: sabemos que temos de us-lo e que ela deve ter certas caractersticas, ento teremos o seu valor em Ohms, sua potncia mxima, tolerncia, entre outras, e teremos uma funo que nos dar a corrente que passa por ela quando lhe aplicamos uma tenso eltrica. No precisamos saber de que que ela feita, ou como estas caractersticas internas a faz funcionar, basta-nos receber os resultados. Vejamos o exemplo: Agora vamos mostrar que podemos ter funes membro apenas como prottipos e defini-las fora da classe. Para isso usamos o operador de definio de escopo :: que permite definir o local do cdigo onde um identificador existe, no formato: ESCOPO::funo ou ESCOPO::dado. De maneira geral, quando declaramos identificadores dentro da classe podemos defini-los no escopo global referenciando estes pelo operador de escopo. // classes example #include <iostream> using namespace std; class CRectangle { int x, y; public: void set_values (int,int); int area () {return (x*y);} }; void CRectangle::set_values (int a, int b) { x = a; y = b; }

Classes //repare no :: que pemite-nos definir a funo membro da classe CRectangle fora da classe int main () { CRectangle rect; //definimos objeto de classe rect.set_values (3,4); //objeto-membro cout << "area: " << rect.area(); return 0; } // classes example #include <iostream> using namespace std; class CRectangle { int x, y; public: void set_values (int a,int b) { x = a; y = b; } int area () {return (x*y);} }; int main () { CRectangle rect; //definimos objeto de classe rect.set_values (3,4); //objeto-membro cout << "area: " << rect.area(); return 0; } area: 12 O exemplo anterior explora a caracterstica de toda figura geomtrica fechada, que possui uma rea interna. Observe que este modo de definir a classe coloca o clculo da rea dentro da definio da mesma. Este modo faz com que o cdigo seja apenas um modelo, a funo de clculo da rea no ser criada se no for usada durante o escrita do resto do programa. Vejamos outro exemplo: class Dog { public: void setAge(int age);

95

Classes int getAge(); void setWeight(int weight); int getWeight(); void speak(); private: int age; int weight; }; void Dog::setAge(int age) { this->age = age; } int Dog::getAge() { return age; } void Dog::setWeight(int weight) { this->weight = weight; } int Dog::getWeight() { return weight; } void Dog::speak() { cout << "BARK!!" << endl; } Acima podemos ver um modo de declarar as funes apenas como prottipos, que ficam dentro da declarao da classe. Nesse contexto as funes so definidas fora da classe, usando-se o operador "::" para ligar a funo classe. Neste caso teremos as funes definidas e construdas no cdigo das mesmas, enquanto que o modelo da classe poder permanecer em um arquivo cabealho, o que possibilita inclu-lo em qualquer arquivo de cdigos fontes do programa.

96

Definio de classes
Usa-se a palavra "class" para criar uma classe, seguindo-se depois o nome que se queira dar-lhe e finalmente a definio da mesma entre chaves. A definio contm: os dados ( propriedades ); os mtodos (as funes membro) Vamos acompanhar com um exemplo: Vamos fazer o desenho de uma classe chamada Image, que ser usada para guardar e manipular uma imagem. Primeiro perguntamos o que necessrio para guardar uma imagem, depois que tipo de manipulaes necessitamos. A imagem possui 400 pixels de largura e 300 pixels altura. Cada pixel tem as propriedades de cor e imagem. A cor composta por: vermelho, azul e verde, numa escala de 0 a . Portanto vamos necessitar de membros para guardar

Classes estas informaes Agora planejemos os mtodos. Vamos, primeiramente, assumir que temos a restrio de <= 400 pixeis, e estes valores sero feitos pelo construtor na criao do objeto. Ns no precisamos dos mtodos para estipular a altura e largura, mas vamos precisar para obter e ler os valores. Esta estratgia tambm nos ajudar a manter os valores de um determinado pixel e a sua localizao. A primeira verso ento seria: class Image { public: int getWidth(); int getHeight(); void setX(int x); int getX(); void setY(int y); int getY(); void setRed(double red); double getRed(); void setBlue(double blue); double getBlue(); void setGreen(double green); double getGreen(); private: int _width; int _height; int _x; int _y; double _red[400][400]; double _blue[400][400]; double _green[400][400]; boolean isWithinSize(int s); double clipIntensity(double brightness); };

97

Especificadores de acesso
Temos as palavras reservadas private e public so os chamados especificadores de acesso. private Especifica uma faixa de variveis ou funes que podem ser acessadas exclusivamente por membros da classe, de forma que nenhum outro cdigo fora da mesma possa acess-las; public Especifica uma faixa de variveis ou funes que podem ser acessadas por qualquer cdigo no programa, sendo que para as funes internas da classe no necessrio especificar o objeto enquanto que para as outras partes do programa necessrio especificar o objeto a qual estas pertencem. Esta caracterstica de limitar o acesso e manipulao dos membros de uma classe chama-se Encapsulamento. A boa prtica no desenho de classes deve sempre forar o encapsulamento. raramente necessrio ou desejvel ter acesso livre e pblico aos dados internos de uma classe. O encapsulamento visa, primariamente duas metas: 1. Eliminar a necessidade de conhecimento da estrutura interna por quem deseja us-la. Por exemplo, se os objetos precisam manter um conjunto de 4 bytes, isto pode ser conseguido usando-se duas variveis short int, uma int,

Classes um vetor com 4 characteres, ou a variao de qualquer um dos anteriores sem sinal, mas estes detalhes no precisam estar expostos. 2. Se a representao interna dos dados for modificada, desde que os tipos de retorno e de parmetros das funes pblicas mantenham-se inalteradas, no necessitemos de alterar cdigo que utilizem objetos da classe. Ou seja, o encapsulamento simplifica a programao escondendo as particulariadades da classe e elimina o retrabalho do cdigo por alteraes da mesma. Geralmente as funes (mtodos) privadas, so auxiliares a outras funes da classe. Se nenhum especificador de acesso for usado, todos os membros e metodos so declarados como privados por padro. H dois mtodos para definir as funes membro: Eles podem ser definidos dentro da classe, o que apropriado para funes pequenas; E funes grandes podem ser definidas fora da classe. Neste caso tero de ser identificadas como pertencentes classe e para isso utilizamos o operador de resoluo de escopo ::.

98

Construtores
Conceito
Os construtores "constructors" so funes membro (mtodos) especiais de uma classe. Permitem a inicializao das variveis membro de um objeto. Ou melhor, permitem a construo e a inicializao de objetos das classes. Se no os declararmos o compilador faz isso por ns. Os construtores tm sempre o mesmo nome que a classe. Os objetos so construdos atravs destas funes especiais chamadas de construtores. At aqui no os declaramos, eram criados automaticamente. Estas funes tem certas caractersticas que as fazem distintas das normais, que permitem que as mesmas construam a estrutura lgica inicial do objeto. Desta forma estas funes so caractersticas da orientao a objetos e servem para criao dos mesmos. Construtores no podem ser chamados explicitamente como fazemos no caso de funes membro regulares. Eles so apenas executados quando um novo objeto da classe criado. Portanto, existe apenas um evento capaz de executar um construtor, a instanciao do objeto. As principais caractersticas dos construtores so: No tm qualquer valor de retorno; No podem ser executados por chamada explcita no cdigo; So executados logo depois que os tipos bsicos do objeto foram criados; Inicializam os dados com os valores que o objeto precisa para comear a funcionar corretamente.

Declarao
Podemos criar construtores facilmente, atravs das caractersticas que os distinguem das funes membro convencionais. Ou seja, definimos uma funo membro que possua o mesmo nome da classe, no tenha tipo de retorno e a declaramos como pblica para que possa ser acessada por quem queira instanciar objetos. Vejamos como definir um construtor: class Caneta { string cor; int volume; /////////////// public:

Classes Caneta( string c, int v ); }; Caneta::Caneta( string c, int v ) { cor = c; volume = v; } Construtores podem iniciar os membros da classe de uma forma simplificada. Este formato usado sempre que o construtor tem dados bsicos que podem ser iniciados antes do resto da construo da estrutura do objeto. Podemos iniciar os dados do objeto declarando-o desta forma: class Caneta { string cor; int volume; /////////////// public: Caneta( string c, int v ) : cor(c), volume(v) { } }; Para faz-lo, como vemos no cdigo, basta listar as variveis membro em uma sequncia depois da declarao do nome do construtor e de um sinal de dois pontos ":". Iniciamos uma lista de membros, com o valor a ser atribudo entre parnteses depois de cada um, separando-os por vrgulas.

99

Destrutores
Conceito
Alm do construtor a linguagem C++, assim como outras linguagens orientadas a objeto, possuem outro tipo de funo especialmente criada e gerenciada pela linguagem, os destrutores. Estas so destinadas a desmontar a estrutura do objeto quando o mesmo est sendo encerrado. O destrutor ter o mesmo nome da classe, mas precedido pelo sinal til ~ e tambm no retorna valor. O destrutor tem as seguintes caractersticas: O destrutor chamado quando o objeto est sendo finalizado; usado para liberar qualquer memria que tenha sido alocada;

Declarao
Faamos a classe Dog com o construtor e o destrutor. class Dog { public: Dog(); //Constructor ~Dog(); //Destructor void setAge(int age); int getAge(); void setWeight(int weight);

Classes int getWeight(); void speak(); private: int age; int weight; }; Dog::Dog() { age = 0; weight = 0; cout << "Dog Constructor Called" << endl; } Dog::~Dog() { cout << "Dog Destructor Called" << endl; } Repare que: O construtor tem o mesmo nome que a classe; O destrutor tem o mesmo nome que a classe com o prefixo de tilde ~; O construtor foi usado para inicializar as variveis membro, mas noutros exemplos poderia alocar memria, tomar controle de recursos como dispositivos de sistema e executar inicializaes de cdigo; O destrutor no exemplo no faz nenhuma ao real, para alm de fazer o eco informando que foi chamado.

100

"copy constructors"
Um "copy constructor" um construtor especial que toma como argumento a referncia de um objeto da mesma classe e cria um novo objeto que a copia do objeto em referncia. Por padro, o compilador providencia um "copy constructor" que faz a cpia membro por membro do objeto original, construindo um objeto idntico. Isto chamado de "shallow copy" ou "member wise". Em algumas situaes a cpia de um objeto no satisfatria, para ver isso vamos ver a classe employee, abaixo: #include <iostream> #include <string.h> using namespace std; class Employee { public: Employee(char *name, int id); ~Employee(); char *getName(){return _name;} private://Other Accessor methods int _id; char *_name;

Classes }; Employee::Employee(char *name, int id) { _id = id; _name = new char[strlen(name) + 1]; array object strcpy(_name, name); } Employee::~Employee() { delete _name; } int main() { Employee programmer("John",22); cout << programmer.getName() << endl; return 0; } A funo strlen retorna o tamanho da string passada pelo constructor. Repare que o nome do employee agora guardado num carcter array dinmico. o string lenght +1 para permitir o null terminator usado no estilo c. A funo strcpy automaticamente adiciona o null terminator a string destino. Note tambm que o destrutor liberta a memoria usada para guardar o employee name, para evitar memory leak. Agora imagine que o john promovido: int main() { Employee programmer("John",22); cout << programmer.getName() << endl; //Lots of code .... Employee manager(&programmer); //Creates a new Employee "manager", //which is an exact copy of the //Employee "programmer". return 0; } Este programa contm um bug srio e morre com uma exceo quando executado. O problema que o construtor que est sendo usado para criar um objeto manager" ,mas ele copia o endereo no ponteiro _name em "manager". Nos temos 2 pointers ambos contendo o mesmo endereo. Imagine que agora um novo empregado contratado. quando o nome for atualizado, no apenas iremos alterar o nome do empregado mas tambm do gerente. Finalmente, quando os objetos deixarem de ser usados e o destrutor da classe fizer a liberao de espao na memria tentar

101

//Allocates an character

Classes liberar duas vezes para o mesmo endereo, provocando um erro no sistema de alocao dinmica de memria, o que forar o sistema operacional a eliminar o programa da memria. Para resolver esse problema podemos definir um construtor de cpia ("copy constructor") na classe, substituindo a implementao padro do compilador. Este recurso automaticamente identificado e faz com que o compilador no crie a sua verso do construtor. Assim, definir um construtor de cpia prprio a maneira mais eficiente quando nossos objetos detm caractersticas que os fazem diferentes do padro. Para criar o construtor basta defin-lo na classe: class Employee { public: Employee( const Employee & e); Employee(char *name, int id); ~Employee(); char *getName(){return _name;} private://Other Accessor methods int _id; char *_name; }; Employee::Employee( const Employee & e ) { _id = e._id; _name = new char[strlen(e._name) + 1]; character array object strcpy(_name, e._name); }

102

//Allocates an

Agora temos um construtor que pode fazer a cpia da forma correta. Neste novo construtor alocamos uma cadeia de caracteres para copiar o contedo da original no objeto a ser copiado e copiamos o contedo para o novo objeto. Assim, teremos objetos distintos, cada um com seu prprio contedo.

Encapsulamento

103

Encapsulamento
Conceito
Encapsulamento, em linguagens orientadas a objeto, a capacidade de ocultao de detalhes de implementao por parte de entidades de manipulao de dados. Esta caracterstica visa prover um meio de manter cada classe responsvel por operaes a elas atribudas sem interferncias externas. A vantagem dessa caracterstica de manter os indivduos de cada classe com funes bem delimitadas e criar meios de criar mdulos onde cada classe faa bem aquilo de que est encarregada, tendo total controle sobre tais operaes.

Atributos de restrio
Classes podem proteger sua estrutura de acessos de outras entidades de dados que no pertencem a seu corpo. Para isto, em C++ temos atributos de acesso para blocos de dados ou funes membros de classes. Em algumas linguagens os atributos so definidos para cada membro individualmente. Os atributos de restrio de acesso em C++ so trs: private, public e protected. Cada atributo oferece um nvel de ocultao para membros de classes. Eles so usados para assegurar que apenas grupos identificados de cdigo tenham acesso a partes presselecionadas da classe. Os nveis de proteo esto ligados ao parentesco do cdigo que pretende acesso com a classe em que os mesmos esto definidos. Mais especificamente, classes que no so filhas da que pretendem acessar s podero ter acesso a membros pblicos, classes filhas tero acesso a membros protegidos (protected) ou pblicos (public) e finalmente, nenhum cdigo que no pertena a prpria classe poder acessar membros privados (private).

Classes derivadas (pequena introduo)


Precisamos dos conceitos bsicos de herana para entender alguns conceitos de encapsulamento. Para no criarmos dependncias circulares entre os tpicos, ou seja, para no dependermos de conceitos de herana que tambm precisa de tpicos de encapsulamento, faremos uma pequena introduo dos conceitos de classes derivadas antes de prosseguirmos com o nosso estudo de encapsulamento. Uma classe pode ser estendida a partir de outra, ou seja, podemos reaproveitar um cdigo j existente em uma determinada classe que j temos e criar uma nova classe com tudo que j existia na primeira, mais o que definirmos para a nova. Vejamos um exemplo bsico: class veculo { string cor; string combustivel; ... ... }; class carro : public veiculo { int nrodas; ... ... int mover( int nkilometros );

Encapsulamento

104

}; A segunda classe declarada possui a extenso ": public veiculo" a mais, esta parte refere-se a uma declarao de parentesco. De fato, ao declarar a classe desta forma estamos informando ao compilador que a classe veiculo me da classe carro. Semanticamente, isto significa que a classe carro possui toda a estrutura da classe veiculo alm de seus prprios membros.

Definindo acessos
Considerando o exemplo anterior, podemos observar que os atributos "cor", "combustivel", "nrodas" poderiam ser alterados em qualquer ponto do programa se tivssemos usado a palavra struct, porm usando a palavra class algo de diferente ocorre, pois no podemos ter acesso a estes atributos, a menos que estejamos acessando-os atravs de funes definidas dentro das classes. Em classes, o atributo private definido por padro, ou seja, os membros que no tenham definidos os seus atributos de acesso explicitamente, sero definidos como privados. Este comportamento revela a necessidade de resguardar os membros de uma classe atravs de atributos de restries. Em C++, ao definir membros em uma classe antes da definio de qualquer atributo de restrio estamos definindo-os como privados (private). Ainda levando em considerao o exemplo anterior, podemos definir atributos de restries para grupos de membros e modificar o comportamento padro da classe. Se definirmos public, os dados estaro acessveis a qualquer parte do programa, o que equivalente a coloca-los em uma estrutura com a palavra struct ao invs de dentro de uma classe. Se definirmos protected temos uma situao peculiar, apenas funes membro da classe ou de suas "filhas" podero acessar dados da classe me. Vejamos o exemplo anterior com algumas alteraes: class veiculo { string cor; protected: string combustivel; ... ... public: bool altCor( string c ) { if ( c == "vermelho" ) { cor = c; return true; } if ( c == "azul" ) { cor = c; return true; } if ( c == "prata" ) { cor = c; return true;

Encapsulamento } return false; } }; class carro : public veiculo { int nrodas; ... ... int mover( int nkilometros ); }; Neste exemplo definimos que o atributo cor no pode ser modificado, a no ser pela funo altCor(), onde restringimos as cores a um conjunto que desejamos. Observe que ao tentar atribuir qualquer cor diferente de "vermelho", "azul" e "prata", receberemos um retorno "false". Assim, temos a possibilidade de controlar o comportamento do objeto criado atravs da restrio imposta. O atributo "combustvel" ser manipulado livremente pela classe "veculo" e pela classe "carro", visto que o atributo protected d visibilidade s classes derivadas de "veiculo". O mesmo mecanismo de controle visto no pargrafo anterior poder ser implementado para acessos fora do escopo das duas classes, ou seja, para funes no escopo global ou em outras classes.

105

Escopos globais
At aqui vimos os atributos de restrio sendo usados em classes para encapsular partes internas a elas, porm, existe outro mecanismo de encapsulamento muito til em C++, os namespaces. Estes "espaos de nomes" so meios de delimitar reas onde smbolos so usados, o que permite evitar que erros ocorram por coincidncia de nomes. A sintaxe para criao de um namespace bem simples. Vejamos um exemplo de cdigo, para observarmos os detalhes: namespace MeuEspaco { void print() { cout << "Funo de imprimir no meu espaco" << endl; } } namespace EspacoAlheio { void print() { cout << "Funo de imprimir no Espaco alheio" << endl; } }

Herana

106

Herana
Conceito
Herana um dos pontos chave de programao orientada a objetos (POO). Ela fornece meios de promover a extensibilidade do cdigo, a reutilizao e uma maior coerncia lgica no modelo de implementao. Estas caractersticas nos possibilitam diversas vantagens, principalmente quando o mantemos bibliotecas para uso futuro de determinados recursos que usamos com muita frequncia. Uma classe de objetos "veiculo", por exemplo, contm todas as caractersticas inerentes aos veculos, como: combustvel, autonomia, velocidade mxima, etc. Agora podemos dizer que "carro" uma classe que tm as caractersticas bsicas da classe "veculo" mais as suas caractersticas particulares. Analisando esse fato, podemos concluir que poderamos apenas definir em "carro" suas caractersticas e usar "veculo" de alguma forma que pudssemos lidar com as caractersticas bsicas. Este meio chama-se herana. Agora podemos definir outros tipos de veculos como: moto, caminho, trator, helicptero, etc, sem ter que reescrever a parte que est na classe "veculo". Para isso define-se a classe "veculo" com suas caractersticas e depois cria-se classes especficas para cada veculo em particular, declarando-se o parentesco neste instante. Outro exemplo: Imagine que j exista uma classe que defina o comportamento de um dado objeto da vida real, por exemplo, animal. Uma vez que eu sei que o leo um animal, o que se deve fazer aproveitar a classe animal e fazer com que a classe leo derive (herde) da classe animal as caractersticas e comportamentos que a mesma deve apresentar, que so prprios dos indivduos classificados como animais. Ou seja, herana acontece quando duas classes so prximas, tm caractersticas mtuas mas no so iguais e existe uma especificao de uma delas. Portanto, em vez de escrever todo o cdigo novamente possvel poupar algum tempo e dizer que uma classe herda da outra e depois basta escrever o cdigo para a especificao dos pontos necessrios da classe derivada (classe que herdou).

Sintaxe
Para declarar uma classe derivada de outra j existente, procedemos de forma a declarar o parentesco e o grau de visibilidade (acesso) que a classe derivada ter dos membros de sua classe base. Para isso seguimos o seguinte cdigo sinttico: class classe_derivada : [<acesso>] classe_base { //corpo da classe derivada } Repare que temos o operador ":" ( dois pontos ) como elo entre as duas classes. Este operador promove o "parentesco" entre as duas classes quando usado na declarao de uma classe derivada. O termo [<acesso>] opcional, mas se estiver presente deve ser public, private ou protected. Ele define o grau de visibilidade dos membros da classe base quando a classe derivada precisar acess-los. Exemplo de implementao: // Demonstra herana. #include <iostream> using namespace std; class veiculo_rodoviario // Define uma classe base veculos. { int rodas; int passageiros;

Herana public: void set_rodas(int num) { rodas = num; } int get_rodas() { return rodas; } void set_pass(int num) { passageiros = num; } int get_pass() { return passageiros; } }; class caminhao : public veiculo_rodoviario // Define um caminhao. { int carga; public: void set_carga(int size) { carga = size; } int get_carga() { return carga; } void mostrar(); }; enum tipo {car, van, vagao}; class automovel : public veiculo_rodoviario // Define um automovel. { enum tipo car_tipo; public: void set_tipo(tipo t) { car_tipo = t; } enum tipo get_tipo() { return car_tipo; } void mostrar(); }; void caminhao::mostrar() { cout << "rodas: " << get_rodas() << "\n"; cout << "passageiros: " << get_pass() << "\n"; cout << "carga (capacidade em litros): " << carga << "\n"; } void automovel::mostrar() { cout << "rodas: " << get_rodas() << "\n"; cout << "passageiros: " << get_pass() << "\n"; cout << "tipo: "; switch(get_tipo()) { case van: cout << "van\n"; break; case car: cout << "carro\n"; break; case vagao: cout << "vagao\n"; } } int main() { caminhao t1, t2; automovel c;

107

Herana t1.set_rodas(18); t1.set_pass(2); t1.set_carga(3200); t2.set_rodas(6); t2.set_pass(3); t2.set_carga(1200); t1.mostrar(); cout << "\n"; t2.mostrar(); cout << "\n"; c.set_rodas(4); c.set_pass(6); c.set_tipo(van); c.mostrar(); #ifdef WIN32 system ("pause"); #endif return 0; } Na implementao acima temos a classe base veiculo_rodoviario e duas classes derivadas : caminhao e automovel. Podemos notar que as caractersticas comuns a todos os tipos de veculos, rodas e passageiros, esto na classe base, enquanto as caractersticas exclusivas de cada tipo de veculo esto nas classes derivadas. Desta forma podemos definir procedimentos especializados para cada classe, fazendo com que todas as eventuais modificaes feitas ao longo da implementao na classe base sejam estendidas a todos os objetos criados a partir das classes derivadas no programa. Repare ainda um pormenor: tanto a classe "caminhao" quanto a automovel tm como funo membro o mtodo mostrar(), mas uma no interfere com a outra. Isto ilustra um outro aspecto da orientao a objeto, o polimorfismo. Este ser exposto em mais detalhe nos captulos subsequentes.

108

Controle de acesso classe base


Quando uma classe herda outra, os membros da classe base so incorporados como membros da classe derivada. Devido separao das classes e do controle de acesso s variveis em cada classe, devemos pensar como as restries de acesso so gerenciadas em classes diferentes, principalmente o acesso a membros da classe base a partir das classes derivadas. O acesso dos membros da classe base classe derivada determinado pelo especificador de acesso: public, private e protected. Por "defaut" (padro) temos o private, ou seja, como temos a opo de no explicitar o especificador de acesso, se este no estiver presente o compilador usar "private" durante a interpretao do cdigo. Assim ficamos com as possveis combinaes

Herana

109

Classe base herdada como public: Membros pblicos (public) da classe base: como se copissemos os membros da classe base e os colocssemos como "public" na classe derivada. No final, eles permanecem como pblicos. Membros privados (private) da classe base: Os membros esto presentes na classe, porm ocultos como privados. Desta forma as informaes esto presentes, mas s podem ser acessadas atravs de funes publicas ou protegidas da classe base. Membros protegidos (protected) da classe base: Se tivermos membros protegidos (protected) na classe derivada, eles se comportam como se tivessem sido copiados para a classe derivada como protegidos (protected). Classe base herdada como private: Membros pblicos (public) da classe base: Os membros se comportam como se tivessem sido copiados como privados (private) na classe derivada. Membros privados (private) da classe base: Os membros esto presentes na classe, porm ocultos como privados. Desta forma as informaes esto presentes, mas no podero ser acessadas, a no ser por funes da classe base que se utilizem delas. Membros protegidos (protected) da classe base: Os membros se comportam como se tivessem sido copiados como privados (private) na classe derivada. Classe base herdada como Protected: Membros pblicos (public) da clase base: Se comportam como se tivssemos copiado-os como protegidos (protected) na classe derivada Membros privados (private) da classe base: Os membros esto presentes na classe, porm ocultos como privados. Desta forma as informaes esto presentes, mas no podero ser acessadas, a no ser por funes da classe base que se utilizem delas. Membros protegidos (protected) da classe base: Se comportam como se estivssemos copiado-os como protegidos (protected) na classe derivada. Em suma, estas regras podem ser sintetizadas em uma regra muito simples: Prevalece o atributo mais restritivo. Para isto basta-nos listar os atributos por ordem de restries decrescente: 1. private 2. protected 3. public Assim, temos todas as combinaes definidas quando colocamos um atributo combinado com o outro, bastando para isto escolher sempre o mais restritivo na combinao. Por exemplo: Quando temos uma varivel pblica na base e a herana privada, a combinao resulta em uma varivel privada na classe derivada. Aqui est um exemplo muito simples:

Herana #include <iostream> using namespace std; class base { int i, j; public: void set(int a, int b) { i = a; j = b; } void show() { cout << i << " " << j << "\n"; } }; class derived : public base { int k; public: derived(int x) { k = x; } void showk() { cout << k << "\n"; } }; int main() { derived ob(3); ob.set(1, 2); // acesso a membro da base ob.show(); // acesso a membro da base ob.showk(); // uso de membro da classe derivada #ifdef WIN32 system ("pause"); #endif return 0; } Conseguimos acessar as funes set() e show() porque so heradadas como publicas. Agora modifiquemos o atributo de acesso na declarao da herana da classe base: #include <iostream> using namespace std; class base { int i, j; public: void set(int a, int b) { i = a; j = b; } void show() { cout << i << " " << j << "\n"; } }; class derived : private base

110

Herana { int k; public: derived(int x) { k = x; } void showk() { cout << k << "\n"; } }; int main() { derived ob(3); ob.set(1, 2); // Erro, no possvel acessar set() ob.show(); // Erro, no possvel acessar show() ob.showk(); // uso de membro da classe derivada #ifdef WIN32 system ("pause"); #endif return 0; } Agora j no podemos acessar as funes porque esto privadas.

111

Heranas mltiplas
Podemos ter a situao em que uma classe derivada possa herdar membros de vrias classes base. Esta caracterstica uma distino entre C++ e outras linguagens orientadas a objeto. Este recurso d mais poder de modelagem ao programador, mas vale a pena lembrar que mais poder exige mais cautela no uso. // Um exemplo de mltiplas classes base. #include <iostream> using namespace std; class base1 { protected: int x; public: void showx() { cout << x << "\n"; } }; class base2 { protected: int y; public: void showy() { cout << y << "\n"; } }; class derived: public base1, public base2 // Inherit multiple base

Herana classes. { public: void set(int i, int j) { x = i; y = j; } }; int main() { derived ob; ob.set(10, 20); // Disponvel pela classe "derived" ob.showx(); // Pela classe base1 ob.showy(); // Pela classe base2 #ifndef WIN32 system ("pause"); #endif return 0; } Repare que utilizamos o operador vrgula para dizer ao compilador que a classe derivada herda mais de uma classe. Com efeito, temos uma lista de classes separadas por vrgulas depois do operador ":" (dois pontos). Quando queremos que a classe derivada herde uma classe como pblica e outra como privada ou protegida basta preceder a classe com o seu especificador de acesso. Da mesma forma, a omisso do especificador leva o compilador a usar o padro que privado (private).

112

Construtores e destrutores
Temos uma srie de classes que mantm relaes de parentesco conforme mostramos nas sees anteriores. Em termos genricos, classes que herdam caractersticas de uma base precisam de regras claras quando forem criadas e destrudas. Precisamos definir a sequncia em que os construtores e destrutores sero chamados, uma vez que cada classe tem pelo menos um construtor e um destrutor. Agora temos a questo: Quando que os construtores so chamados quando eles so herdados? Quando um objeto da classe derivada instanciado, o construtor da classe base chamado primeiro seguido do construtor das classes derivadas, em sequncia da base at a ltima classe derivada. Quando o objeto da classe derivada destrudo, o seu destrutor chamado primeiro seguido dos destrutores das outras classes derivadas logo abaixo, em sequncia at a base. Vamos testar e ver como isto funciona. No caso em que termos herana sequencial A-B-C, teremos: #include <iostream> using namespace std; class base { public: base() { cout << "Construindo base" << endl; } ~base() { cout << "Destruindo base" << endl; } };

Herana

113

class derivada1 : public base { public: derivada1() { cout << "Construindo derivada1" << endl; } ~derivada1() { cout << "Destruindo derivada1" << endl; } }; class derivada2: public derivada1 { public: derivada2() { cout << "Construindo derivada2\n"; } ~derivada2() { cout << "Destruindo derivada2\n"; } }; int main() { derivada2 ob; // constri e destri o objeto ob #ifdef WIN32 system ("pause"); #endif return 0; } Caso de mltipla herana A - B e C #include <iostream> using namespace std; class base1 { public: base1() { cout << "Construindo base1\n"; } ~base1() { cout << "Destruindo base1\n"; } }; class base2 { public: base2() { cout << "Construindo base2\n"; } ~base2() { cout << "Destruindo base2\n"; } }; class derivada: public base2,public base1 { public: derivada() { cout << "Construindo derivada\n"; }

Herana ~derivada() { cout << "Destruindo derivada\n"; } }; int main() { derivada ob;// construindo e destruindo o objeto. #ifdef WIN32 system ("pause"); #endif return 0; } Neste caso a sequncia de inicializao segue ordem estabelecida na lista de herana. Mais explicitamente, temos a construo das bases: "base2" e "base1", nesta ordem respectivamente e depois a derivada. O que, automaticamente, nos revela a sequncia de destruio na ordem inversa, ou seja: destroi-se a "derivada", depois "base1" e, finalmente, a estrutura da "base2".

114

Passando parmetros para construtores da classe base


Agora imaginemos que temos um conjunto de bases para uma classe que queiramos derivar, ento podemos ter um construtor em cada base que precise de parmetros para que possa ser invocado pela nossa classe. Como poderemos passar os parmetros, uma vez que os mesmos s podem ser passados durante a inicializao da classe? Para que possamos passar os parmetros para as classes bases durante a inicializao do objeto da classe derivada temos o recurso de passagem de parmetros pelo construtor. Basicamente, ele funciona como se passssemos valores para variveis membro. Chamamos cada construtor na lista de passagem de valores, a sintax para declarar o corpo do construtor a seguinte: class Classe_derivada : public Base1, public Base2, ..., public BaseN { // Membros... public: Classe_derivada(lista_de_argumentos); // Outras funes... };

Classe_derivada::Classe_derivada(lista_de_argumentos) : Base1(lista_de_argumentos), Base2(lista_de_argumentos), ...BaseN(lista_de_argumentos); { //Corpo do construtor da classe derivada } Este exemplo um pouco mais complexo, ateno!
#include <iostream>

using namespace std;

class base {

Herana
protected: int i; public: base(int x) { i = x; cout << "Construindo base\n"; } ~base() { cout << "Destruindo base\n"; } };

115

class derivada: public base { int j; public: derivada(int x, int y): base(y) { j = x; cout << "Construindo derivada\n"; }// derivada usa x; y passada em lista para a base. ~derivada() { cout << "Destruindo derivada\n"; } void mostrar() { cout << i << " " << j << "\n"; } };

int main() { derivada ob(3, 4); ob.mostrar(); // mostra 4 3 #ifdef WIN32 system ("pause"); #endif return 0; }

No exemplo, a o construtor da classe derivada declarado com 2 argumentos (x e y). no entanto a funo derivada() usa apenas um para inicializar a varivel interna da classe, o segundo argumento usado para passar o valor de inicializao para a classe base. Vejamos mais um exemplo: #include <iostream> using namespace std; class base1 { protected: int i; public: base1(int x) { i = x; cout << "Construindo base1\n"; } ~base1() { cout << "Destruindo base1\n"; } }; class base2 { protected: int k;

Herana public: base2(int x) { k = x; cout << "Construindo base2\n"; } ~base2() { cout << "Destruindo base2\n"; } }; class derivada: public base1, public base2 { int j; public: derivada(int x, int y, int z): base1(y), base2(z) { j = x; cout << "Construindo derivada\n"; } ~derivada() { cout << "Destruindo derivada\n"; } void mostrar() { cout << i << " " << j << " " << k << "\n"; } }; int main() { derivada ob(3, 4, 5); ob.mostrar(); // mostra 4 3 5 #ifdef WIN32 system ("pause"); #endif return 0; }

116

Superposio de funes
Muitas vezes temos classes derivadas que executam uma determinada ao de forma distinta da mesma ao definida na classe base. Por exemplo, se temos uma classe "animal" e declaramos uma funo chamada "mover" e depois declaramos duas derivadas: "ave" e "peixe" com a mesma funo "mover" teremos uma incoerncia devido ao fato de que peixes se movem de forma totalmente diferente de aves. Uma vez que peixes devem "nadar" e "aves" podem "voar" ou "andar" nosso modelo de objetos est incorreto. Por questes de coerncia semntica, porm, precisamos manter o mesmo nome para as funes das classes base e derivada em algumas construes. Isto essencial devido a necessidade de criarmos objetos generalistas, por exemplo se tivermos classes "ave" e "peixe" abstradas em uma base "animal", como vimos acima. Havendo estas condies, como poderemos criar comportamentos diferentes usando o mesmo nome para as funes? A resposta est em uma das caractersticas que ser muito til quando quisermos usar de polimorfismo, que iremos abordar em captulo especfico mais adiante: a ocultao e superposio de funes da classe base a partir de uma classe derivada (conhecida como "overriding" em manuais de compiladores). Com este recurso podemos declarar em uma classe derivada uma funo com nome e parmetros idnticos a uma existente em uma classe base, porm com contedo diferente. Vejamos o exemplo de cdigo e teremos uma noo mais concreta do que foi explanado: #include <iostream> using namespace std; class animal

Herana { public: void comer(); void mover(); void dormir() { cout << "Dormindo..." << endl; } }; ... ... class ave : public animal { public: void comer(){ cout << "Bicando..." << endl; } void mover(){ cout << "Voando..." << endl; } }; ... ... class peixe : public animal { public: void comer(){ cout << "Mordendo..." << endl; } void mover(){ cout << "Nadando..." << endl; } }; int main() { ave passarinho; peixe sardinha; passarinho.mover(); sardinha.mover(); #ifdef WIN32 system("pause"); #endif return 0; } Ao executar o programa gerado por este cdigo percebemos que a mesma funo: mover(), ter comportamento diferente quando invocada por objetos de classes diferentes. O programa mostrar a mensagem "Nadando..." para a funo invocada pelo objeto sardinha e "Voando..." para a invocada pelo objeto passarinho. Aqui, o mecanismo bem simples de se entender, quando cada objeto tem uma verso diferente para a mesma funo fcil para o compilador relacionar o objeto classe que ele pertence e invocar a funo apropriada.

117

Herana

118

Acessando funes superpostas da classe base


O mecanismo para obter acesso s classes base a partir da classe derivada intuitivo. Para isto usamos o operador de resoluo de escopo, composto por um par de dois pontos "::", usando a seguinte sintaxe: <CLASSE>::<FUNO>(lista_de_parmetros); Ou seja, basta invocar a funo informando qual a verso especfica que se deseja utilizar. Se tivermos uma classe "A" e outra "B" com uma funo "Print()", por exemplo, e quisermos usar a funo "Print()" da classe "B" fazemos: B::Print(); Talvez seja melhor visualizar um exemplo no cdigo mais completo: class B { public: void Print() { cout << "Chamando Print() da classe B." << endl; } }; class A : public B { public: void Print() { cout << "Chamando Print() da classe A." << endl; B::Print(); } }; int main() { A ca; ca.Print(); return 0; }

Polimorfismo

119

Polimorfismo
Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

Conceito
Polimorfismo em linguagens orientadas a objeto, a capacidade de objetos se comportarem de forma diferenciada em face de suas caractersticas ou do ambiente ao qual estejam submetidos, mesmo quando executando ao que detenha, semanticamente, a mesma designao. O polimorfismo em C++ se apresenta sob diversas formas diferentes, desde as mais simples, como funes com mesmo nome e lista de parmetros diferentes, at as mais complexas como funes virtuais, cujas formas de execuo so dependentes da classe a qual o objeto pertence e so identificadas em tempo de execuo.

Funes virtuais
#include <iostream> using std::cout; using std::endl; class Base { public: // declarao da funo virtual virtual void Quem_VIRTUAL() { cout << "Base\n"; } // funo comum void Quem_NAO_VIRTUAL() { cout << "Base\n"; } }; class Derivada : public Base { public: // funo virtual sobrescrita virtual void Quem_VIRTUAL() { cout << "Derivada\n"; } // funo comum sobrescrita void Quem_NAO_VIRTUAL() { cout << "Derivada\n";

Polimorfismo } }; int main () { Base *ptr_base; Derivada derivada; ptr_base = &derivada; ptr_base->Quem_VIRTUAL(); "Derivada") ptr_base->Quem_NAO_VIRTUAL(); (mostra: "Base") cout << endl; return 0; } // converso implcita permissvel // chamada polimrfica (mostra: // chamada comum, no-polimrfica

120

Classe base virtual


Consideremos o seguinte programa: // Este programa contm um erro e no ser compilado. #include <iostream> using namespace std; class base { public: int i; }; class derived1 : public base // derived1 inherits base. { public: int j; }; class derived2 : public base // derived2 inherits base. { public: int k; }; class derived3 : public derived1, public derived2 /* "derived3" herda caractersticas de "derived1" e "derived2". Isto significa que h duas cpias da base em "derived3"! */ {

Polimorfismo public: int sum; }; int main() { derived3 ob; ob.i = 10; // Isto se torna ambguo; A qual "i" estamos nos referindo??? ob.j = 20; ob.k = 30; ob.sum = ob.i + ob.j + ob.k;// "i" ambguo aqui, tambm cout << ob.i << " ";// tambm ambguo, Qual "i"? cout << ob.j << " " << ob.k << " "; cout << ob.sum; #ifdef WIN32 system ("pause"); #endif return 0; } As classes derived1 e derived2 so herdadas como classes base. A classe derived3 herda tanto de derived1 quanto de derived2. Como resultado temos 2 cpias da classe base presentes no objeto da derived3, por exemplo presente na linha ob.i=10; isto resulta numa ambiguidade e o programa no vai compilar. H duas maneiras para remediar a situao: 1. Aplicar o operador de resoluo de escopo manualmente: //Este programa usa resoluo de escopo explicita para selecionar "i". #include <iostream> using namespace std; class base { public: int i; }; class derived1 : public base // derived1 inherits base. { public: int j; }; class derived2 : public base // derived2 inherits base. { public: int k; };

121

Polimorfismo class derived3 : public derived1, public derived2 /* "derived3" herda as bases "derived1" e "derived2". Isto significa que h duas cpias de bases em "derived3"! */ { public: int sum; }; int main() { derived3 ob; ob.derived1::i = 10; // escopo resolvido, usa o "i" em "derived1". ob.j = 20; ob.k = 30; ob.sum = ob.derived1::i + ob.j + ob.k; // escopo resolvido. cout << ob.derived1::i << " "; // tambm resolvido aqui. cout << ob.j << " " << ob.k << " "; cout << ob.sum; #ifdef WIN32 system ("pause"); #endif return 0; } 2. A segunda maneira atravs de classes bases virtuais: Quando temos 2 ou mais objetos que so derivados da mesma base class, podemos prevenir mltiplas cpias da base class declarando a base class como virtual quando ela herdada. Exemplificando: // Este program usa classes bases virtuais. #include <iostream> using namespace std; class base { public: int i; }; class derived1 : virtual public base // derived1 inherits base as virtual. { public: int j; }; class derived2 : virtual public base // derived2 inherits base as virtual. { public:

122

Polimorfismo int k; }; class derived3 : public derived1, public derived2 /* derived3 inherits both derived1 and derived2. This time, there is only one copy of base class. */ { public: int sum; }; int main() { derived3 ob; ob.i = 10; // now unambiguous ob.j = 20; ob.k = 30; ob.sum = ob.i + ob.j + ob.k;// unambiguous cout << ob.i << " ";// unambiguous cout << ob.j << " " << ob.k << " "; cout << ob.sum; system ("pause"); return 0; } Repare que agora temos a palavra virtual antes da classe.

123

Friend

124

Friend
Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

O que
Friend um atributo especial de acesso a classes. Com ele declaramos que uma funo fora de uma classe amiga da mesma. Declarando que uma funo (externa classe) "friend" dentro de uma classe, permite que a funo (a amiga) possa ler e manipular membros (variveis e funes membro) "private" - privados e "protected" - protegidos (e claro "public" - publicas, mas isso j era permitido antes de serem "friends"). Considerando que o acesso a membros pode ser restrito para determinadas partes do cdigo, podemos adotar uma postura mais flexvel para funes que conhecemos como confiveis e evitar os inconvenientes da restrio a membros por cdigos que no provoquem problemas maiores a nossa estrutura da aplicao.

Declarar funes "friend"


O processo para fazer com que funes fora do escopo da classe tenham acesso a membros sem nenhuma restrio muito simples. Para isto apenas temos de colocar o prottipo da funo externa dentro da classe precedido da palavra "friend". Desta forma o compilador passa a ignorar os atributos de restrio de acesso da classe quando a funo acessa membros da mesma. Vamos ao exemplo: // friend functions #include <iostream> using namespace std; class CRectangle { int width, height; public: void set_values (int, int); int area () {return (width * height);} friend CRectangle duplicate (CRectangle); }; void CRectangle::set_values (int a, int b) { width = a; height = b; } CRectangle duplicate (CRectangle rectparam) { CRectangle rectres; rectres.width = rectparam.width*2; rectres.height = rectparam.height*2; return (rectres); }

Friend int main () { CRectangle rect, rectb; rect.set_values (2,3); rectb = duplicate (rect); cout << rectb.area(); system (pause); return 0; } O uso de funes amigas deve ser evitado sempre que possvel, pois diminui a identidade da orientao a objetos. Isto ocorre porque o uso desse mecanismo representa uma quebra no encapsulamento. Quando passamos a permitir que funes tenham acesso a membros restritos dos objetos fazemos com que agentes externos interfiram na autonomia dos mesmos. Isto pode dificultar a anlise de programas muito extensos. No caso da criao de procedimentos que tem a finalidade de modificar o contedo do objeto explicitamente, como nos casos de operadores e modificadores de comportamento, podemos usar as funes amigas "friends" para esta finalidade tomando os devidos cuidados para torn-las muito bem restritas as funes que devem executar. muito importante observar se estas funes alteram dados dentro dos objetos que no podem ser modificados. Se as devidas precaues forem tomadas no haver problemas no uso de funes "friend".

125

Friend classes
Da mesma forma que podemos declarar funes como amigas de uma determinada classe, podemos declarar outra classe como sua amiga. Este artifcio faz com que os membros da classe onde foi feita a declarao sejam acessveis declarada. Assim, a segunda classe passa a ter possibilidade de manipulao livre dos membros da outra. Apesar da funcionalidade ser um pouco semelhante que temos no uso das funes, quando declaramos uma classe como "friend" dentro de outra, teremos todas as funes da primeira com poderes de acesso aos membros da segunda. Esta caracterstica requer cuidado redobrado quando operaes da classe "friend" interferem no contedo da outra. // friend class #include <iostream> using namespace std; class CSquare; class CRectangle { int width, height; public: int area () {return (width * height);} void convert (CSquare a); //consigo acessar porque friend }; class CSquare { private: int side; public: void set_side (int a) {side=a;}

Friend friend class CRectangle; //declaro friend class

126

}; void CRectangle::convert (CSquare a) { width = a.side; height = a.side; } int main () { CSquare sqr; CRectangle rect; sqr.set_side(4); rect.convert(sqr); cout << rect.area(); system (pause); return 0; } Nota: No h a propriedade de reciprocidade (ou reverso). O facto de uma funo ou classe ser friend de uma classe no implica o contrrio, ou seja, A ter B como friend no implica que B a tenha em mesma conta. Outra propriedade que no h transitividade. Se numa class A for declarado que a class B friend. E depois que na classe B estiver declarado que a classe C friend de B,Isto no implica que A seja friend de C.

Classes internas
Conceituao
As classes podem ser construdas uma dentro da outra para uma melhor organizao do cdigo. Esta possibilidade nos leva a implicaes a serem consideradas durante a fase de implementao do cdigo. Devemos verificar as particularidades de acesso a dados, o que nos leva a diversas particularidades devido ao escopo das mesmas. No exemplo a seguir, temos a implementao bsica de uma classe interna a outra: class data { int n; char str[256]; public: class idata { int x; int y; int z; }; int getn(); char *getstr(); void setstr( const char *instr);

Classes internas void setn(int inn); }; Uma vez que criamos o prottipo de objeto dentro de outra classe podemos us-lo atravs do operador de resoluo de escopo. Deveremos nos referir ao operador para acessar o corpo da primeira classe e depois o invocamos novamente para alcanar a outra. Desta forma, poderamos us-la como exemplificado abaixo: data::idata ni; importante notar que objetos diferentes tero dados diferentes na regio da classe interna, isso impede que usemos dados da classe mais externa dentro das classes internas. Devido a esta caracterstica as funes dentro da classe interna no podem acessar dados da classe mais externa, a menos que sejam estticos, o que no exige definio do objeto a qual eles pertencem. Portanto, o uso de classes internas permite um isolamento de parte dos dados e prover um tratamento diferenciado para os mesmos.

127

Sobrecarga de operadores
Modificando operadores
A linguagem C++ possui os mesmos operadores presentes na linguagem C. Estes tm funes padronizadas e comportamentos semelhantes a seus parentes diretos em C. Esta caracterstica a traz compatibilidade que um requisito fundamental e adiciona uma nova funcionalidade chamada sobrecarga de operadores. Quando operamos tipos nativos da linguagem, fazemos com funes especficas predefinidas e padronizadas. Como poderemos operar os nossos objetos que definimos com nossas classes? Simples: criamos as funcionalidades e as atribuimos a operadores j conhecidos, de forma a manter a idia bsica da operao embutida na simbologia. Ao definir novas funes para os operadores padro, na verdade no substituimos a sua funo, apenas adicionamos mais uma funo ao mesmo operador. Esta operao chamada de sobrecarga de operador. O nome parece um pouco fora do comum, mas apenas reflete o comportamento da linguagem quando esta lida com a definio de vrios tratamentos para o mesmo identificador, que, neste caso, o smbolo do operador. Portanto, sobrecarga de operador a definio de novas tarefas para o mesmo operador.

Definindo novas operaes


Digamos que temos uma classe chamada ponto, que define dois inteiros para um plano hipoteticamente definido. Este par de inteiros poder representar uma coordenada neste plano formado por pontos espaados um do outro. Sob estas condies, cada objeto desta classe ser uma coordenada neste plano: class ponto { int x,y; public: ponto(int a, int b) { x = a; y = b; } }; Se quisermos operar estes objetos no teremos como faz-lo, pois no h meios de operar os objetos do tipo ponto. Nenhuma operao possivel, pois a linguagem no define como oper-los. Cabe ao programador dizer ao compilador como ele deve efetuar a operao do novo tipo criado.

Sobrecarga de operadores ponto p1(1,5),p2(3,4), Soma; Soma = p1 + p2; Ao tentar compilar este trecho de cdigo o compilador retornar um erro por no conhecer a maneira de como operar este tipo de dado. Como criamos o tipo de dado, precisamos definir como fazer a soma do mesmo. Podemos fazer a seguinte definio: class ponto { int x,y; public: ponto(int a, int b) { x = a; y = b; } ponto operator+(ponto p); }; ponto ponto::operator+(ponto p) { int a,b; a = x + p.x; b = y + p.y; return ponto(a,b); } A sintaxe desta definio, muitas vezes causa confuso, mas poder ser facilmente entendida depois que tenhamos assimilado as idias bsicas por traz dela. Ela opera, aparentemente, apenas um dado de entrada, porm o operador deve somar dois. Como isto possvel? Observando mais atentamente o cdigo poderemos entender: Verificamos que, no cdigo, nos referimos a x e y sem definir a qual objeto pertence. Acontece que a operao est ocorrendo dentro de um dos objetos, aquele imediatamente antes do operador. Esta a primeira coisa a ter em mente: O operador "pertence" a um dos objetos que est sendo operado, sendo sempre aquele que o antecede. Com isso, s precisamos declarar o segundo dado a operar. Podemos visualizar isto melhor, da seguinte forma: P3 = P1 + P2; Que pode ser entendido como a invocao da funo: P3 = P1.operator+( P2); Agora podemos entender como acontece a invocao da funo que define o operador. Observe que P1 contm o operador que recebe P2, fazendo o clculo e devolvendo uma cpia do objeto resultante para P3. A sintaxe esconde o mecanismo para tornar o cdigo mais simples de ser entendido quando tiver que ser lido.

128

Alocao dinmica de memria

129

Alocao dinmica de memria


Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

Alocao dinmica de memria


O compilador reserva espao na memria para todos os dados declarados explicitamente, mas se usarmos ponteiros precisamos reservar o espao necessrio e colocar o endereo inicial nos mesmos. Para isto, podemos usar o endereo de uma varivel definida previamente ou reservar o espao necessrio no momento que precisemos. Este espao que precisamos reservar em tempo de execuo chamada de memria alocada dinamicamente. Refere-se possibilidade de termos o nosso programa a correr e o utilizador ter de inserir dados e como tal no sabemos exatamente a quantidade de dados que o utilizador vai colocar, portanto temos de arranjar uma memria que nos permita lidar com esta indeterminao quanto quantidade de dados inseridos. Este o caso em que no sabemos no momento da programao a quantidade de dados que devero ser inseridos mas o programa j est a correr. tentar responder a perguntas: quantas pessoas existem na tua turma? Quantas letras vamos escrever, etc. Em vez de estarmos a prever um limite superior para abarcar todas as situaes, temos esta possibilidade do dinmico. Alm de que colocar no momento da programao cria reserva de memria por isso, estaramos a reservar memria para um limite que possivelmente no iramos ter necessidade. O exemplo tpico disto os processadores de texto. em que no sabemos a quantidade de letras que o utilizador vai escrever. Vamos voltar a uma ponta solta num dos captulos anteriores, onde queramos fazer com que o utilizador dissesse quantos elementos do array que se deveria utilizar. J dissemos antes que o declarador do n de elementos do array tem de ser ou uma constante ou um literal, mas no pode ser uma varivel. Isso d erro. Aqui vai o exemplo desse erro: #include <iostream> using namespace std; int main () { int numTests; cout << "digite o numero de testes : "; cin >> numTests; int testScore[numTests]; return 0; } A razo da exigncia de ter uma constante (ou literal) que vamos alocar memria para o array na altura da compilao, e o compilador necessita de saber exatamente a quantidade de memria que deve reservar porm se a varivel o size declarator, o compilador no sabe quanta memria deve reservar para alocar a varivel, pois o seu valor pode mudar.

Alocao dinmica de memria

130

Operador new
Reformulando o exemplo anterior agora com dados dinmicos. #include <iostream> using namespace std; int main () { int numTests; cout << "Enter the number of test scores:"; cin >> numTests; int * iPtr = new int[numTests]; //colocamos um ponteiro no inicio da memria dinmica for (int i = 0; i < numTests; i++) { cout << "Enter test score #" << i + 1 << " : "; cin >> iPtr[i]; } for (int i = 0; i < numTests; i++) cout << "Test score #" << i + 1 << " is "<< iPtr[i] << endl; delete [] iPtr; return 0; } Ou seja conseguimos criar um array onde o utilizador a definir o tamanho do array e que depois coloca o valor para cada um dos elementos. O operador new retorna o endereo onde comea o bloco de memria. e como retorna um endereo vamos coloc-lo num pointer. Necessitamos do uso do pointer que dever ser do mesmo tipo que o tipo de varivel que alocado dinamicamente. int * iPtr = new int[numTests]; Temos termo NEW. Que um operador cuja funo alocar dinamicamente memria Temos o tipo da varivel alocada dinamicamente Repare que NO temos o nome do array Uma vez que o array fica sem nome para nos referirmos a cada elemento do array teremos de usar o pointer.

Podemos inicializar de duas maneiras: int *IDpt = new int; *IDpt = 5; ou int *IDpt = new int(5); //Allocates an int object and initializes it to value 5. char *letter = new char('J');

Alocao dinmica de memria

131

Operador Delete - Memory Leak


O tempo de vida de uma varivel criada dinamicamente o tempo de execuo do programa. Se um ponteiro aponta para uma varivel dinmica e fica out of scope, j no conseguiremos acessar essa memria criada dinamicamente. Fica indisponvel. A isso se chama Memory Leak Explicando: se alocamos memria dinamicamente dentro de uma funo usando um ponteiro local, quando a funo termina, o ponteiro ser destrudo, mas a memria mantm-se. Assim j no teramos maneira de chamar essa memria porque ela no tem nome! Apenas tnhamos o endereo que estava no ponteiro. Portanto, se realmente no necessitamos mais dos dados que esto nessa memria dinmica, em vez de eles estarem a ocupar espao vamos apag-los! Necessitamos de libertar essa memria atravs do operador delete este operador entrega ao sistema operacional a memria reservada dinamicamente. A sintaxe delete [] iPtr; Este delete operator no apaga o ponteiro mas sim a memria onde o ponteiro aponta. dynamic memory allocation funciona porque a memria no reservada no momento da compilao, mas antes na execuo. Em vez de ser no STACK (compilao) a memria reservada no HEAP (execuo). O heap uma parte da memria que usada como memria temporria. Pergunta: onde que fica situado o Heap? Vamos explicar melhor todo este processo: pois isto tem de entrar na cabea! void myfunction() { int *pt; int av; pt = new int(1024); .... .... //No delete } int main() { while (some condition exists) // Pseudo-code { myfunction(); } exit 0; } quando a funo myfunction chamada a varivel av criada no stack e quando a funo acaba a varivel retirada do stack. O mesmo acontece com o ponteiro pt, ele uma varivel local. ou seja quando a funo acaba o ponteiro tambm termina e retirado do stack. Porm o objeto alocado dinamicamente ainda existe. E agora no conseguimos apagar esse objeto por que ele no tem nome e a nica maneira que tnhamos para saber onde ele estava era atravs do ponteiro que terminou quando termina a funo pois ele local. Ento medida que o programa continua a operar mais e mais memria ser perdida do Heap (free store). se o programa continuar o tempo suficiente, deixaremos de ter memria disponvel e o programa deixar de operar.

Alocao dinmica de memria

132

Retornando um ponteiro para uma varivel local


#include <iostream> using namespace std; char * setName(); int main (void) { char* str = setName(); //ponteiros para a funo cout << str; //imprimo o valor do ponteiros? return 0; } char* setName (void) { char name[80]; cout << "Enter your name: "; cin.getline (name, 80); return name; } O que se passou aqui que o ponteiro que sai da funo setName aponta para o array local cuja vida acaba quando a funo termina de executar. A soluo estender o tempo de vida. Uma soluo era tornar esse array global, mas existem alternativas melhores.

Retornando um Ponteiro a uma Varivel Local Esttica


Uma dessas alternativas #include <iostream> using namespace std; char * setName(); int main (void) { char* str = setName(); cout << str; return 0; } char* setName (void) { static char name[80]; //crio como static cout << "Enter your name: "; cin.getline (name, 80); return name; } A diferena que usamos a palavra static. O ponteiro do setName aponta para o array local, e como foi utilizado o static, ele perdura at fim da funo, terminando apenas quando o programa acaba.

Alocao dinmica de memria

133

Returning a Pointer to a Dynamically Created Variable


Outra alternative, talvez melhor #include <iostream> using namespace std; char * setName(); int main (void) { char* str= setName(); cout << str; delete [] str; //fao o delete para evitar o memory leak return 0; } char* setName (void) { char* name = new char[80]; //crio ponteiro chamado de name e dou o valor do endereo da memoria dinmica cout << "Enter your name: "; cin.getline (name, 80); return name; } Isto funciona porque o ponteiro retornado da funo setname aponta para o array cujo tempo de vida persiste. O address do ponteiro local atribudo no main a outro ponteiro no main str. Depois este ponteiro usado at ao fim da execuo do programa. Este um exemplo onde diferentes ponteiros apontam para o mesmo endereo. Mas ter ateno que se fizermos o delete atravs de um ponteiro, ter cuidado com o segundo ponteiro que aponta para a memoria que acabou de ser deslocada.

Alocar dinamicamente Arrays


Ora o que fizemos antes com variveis, vamos ter de fazer com arrays. int *pt = new int[1024]; //allocates an array of 1024 ints double *myBills = new double[10000]; /* This doesn't mean I owe 10000.0, but rather allocates an array of 10000 doubles to hold the amounts of the thousands of bills I receive monthly. */ Notar a diferena: int *pt = new int[1024]; int *pt = new int(1024); //allocates an array of 1024 ints //allocates a single int with value 1024

a melhor maneira para alocar um array dinamicamente usar o loop int *buff = new int[1024]; for (i = 0; i < 1024; i++) { *buff = 52; //Assigns 52 to each element; buff++; }

Alocao dinmica de memria ou se quisermos desta maneira int *buff = new int[1024]; for (i = 0; i < 1024; i++) { buff[i] = 52; //Assigns 52 to each element; } para utilizar o delete em arrays delete[] pt; delete[] myBills;

134

Dangling Pointers
int *myPointer; myPointer = new int(10); cout << "The value of myPointer is " << *myPointer << endl; delete myPointer; *myPointer = 5; cout << "The value of myPointer is " << *myPointer << endl; neste exemplo libertmos a memria dinmica, mas o ponteiro continua isto um bug tremendo, e muito difcil de detectar. o programa continua a correr e a seco de memria pode ser usada por outro objeto dinmico. acontece que essa memoria estar corrompida se continuar a usar o myPointer. a melhor maneira depois do delete fazer apontar para zero, faz-lo um ponteiro nulo. se tentarem usar o ponteiro iremos ter a run time exception e o bug pode ser identificado Assim, corrigindo o cdigo anterior ficaramos com: int *myPointer; myPointer = new int(10); cout << "The value of myPointer is " << *myPointer << endl; delete myPointer; myPointer = 0; *myPointer = 5; //This statement will cause an run-time exception, now. cout << "The value of myPointer is " << *myPointer << endl;

Verificar a existncia de memria para dinmica


Na alocao dinmica temos de nos certificar de que a alocao no heap foi feita com sucesso e podemos ver isso de duas maneiras: Uma so as excees (este o mtodo defaut) bobby = new int [5]; bad_alloc exception // if it fails an exception is thrown

vamos ver este caso quase no ultimo capitulo- isto uma captulo avanado notthrow, aqui no caso de no se conseguir a memria retorna um ponteiro nulo, e o programa continua. bobby = new (nothrow) int [5]; supostamente este mtodo pode ser tedioso para grandes projetos

Alocao dinmica de memria Vamos ver um exemplo com o caso de nothrow // rememb-o-matic #include <iostream> using namespace std; int main () { int i,n,* p; cout << "How many numbers would you like to type? "; cin >> i; p= new (nothrow) int[i]; //crimos I variaveis na execuo if (p == 0) cout << "Error: memory could not be allocated"; else { for (n=0; n<i; n++) { cout << "Enter number: "; cin >> p[n]; } cout << "You have entered: "; for (n=0; n<i; n++) cout << p[n] << ", "; delete[] p; } return 0; }

135

Excees

136

Excees
Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

Uma exception um erro que ocorre em tempo de execuo. Podemos lidar com estes erros e criar rotinas para muitos deles, o que nos permite automatizar muitos erros que antes teriam de ser emendados mo.

Namespace
Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

O propsito dos namespace localizar os identifiers (os nomes) por forma a evitar que haja apenas um, para evitar colises. Por exemplo eu poderia criar uma funo com um determinado nome e depois vir a saber que esse mesmo nome existia na biblioteca. E isto pode ocorrer bem freqentemente quando temos vrios programadores contribuindo para o mesmo projeto e ainda mais quando se recorre a bibliotecas para usar cdigo criado por outros. O que o namespace permite continuar a termos o mesmo nome mas ir fazer a diferenciao pela deteco do contexto de aplicao para cada nome.

Templates
Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

Os templates permitem a criao de cdigo reusado, usando templates possvel criar funes e classes genricas. Assim o tipo de dados usadas pelas funes so parmetros. Podemos criar um template para soma, e depois enviamos que tipo de dados queremos somar, podemos at utilizar a sobrecarga de operadores para tal fim.

Funes genricas
template <class Ttype> ret-type func-name(parameter list) { // body of function } vamos dar o exemplo // Function template example. #include <iostream> using namespace std; template <class X> void swapargs(X &a, X &b)// This is a function template. { X temp; temp = a; a = b;

Templates b = temp; } int main() { int i=10, j=20; double x=10.1, y=23.3; char a='x', b='z'; cout << "Original i, j: " << i << ' ' << j << '\n'; cout << "Original x, y: " << x << ' ' << y << '\n'; cout << "Original a, b: " << a << ' ' << b << '\n'; swapargs(i, j); // swap integers swapargs(x, y); // swap floats swapargs(a, b); // swap chars cout << "Swapped i, j: " << i << ' ' << j << '\n'; cout << "Swapped x, y: " << x << ' ' << y << '\n'; cout << "Swapped a, b: " << a << ' ' << b << '\n'; system ("pause"); return 0; } Aqui criamos uma template para uma funo que troca os valores, e essa funo pode ser usada quer tendo ints, doubles ou chars. ns utilizamos o X como data type. neste caso temos swapargs() como uma funo genrica. O compilador automaticamente cria 3 verses para a funo swapargs(). portanto os templates no so bem funes que funcionam para as vrios tipos, mas antes os templates permitem poupar escrita ao programador para no ter de especificar cada tipo. template function ou generic function ( uma definio de uma funo precedida pela statement template especializao == quando o compilador cria a verso especifica da funo. tambm chamada de generated function. o ato de gerar a funo referido como instantiating. h quem prefira ter a declarao do template da seguinte forma template <class X> void swapargs(X &a, X &b)// This is a function template. { X temp; temp = a; a = b; b = temp; } O que se torna bem parecido com o modelo utilizado anteriormente. Uma funo com dois tipos genricos: #include <iostream> using namespace std; template <class type1, class type2> void myfunc(type1 x, type2 y) { cout << x << ' ' << y << '\n';

137

Templates } int main() { myfunc(10, "hi"); myfunc(0.23, 10L); system ("pause"); return 0; } Repare que temos dois tipos de dados diferentes na mesma funo.

138

Sobrecarregando explicitamente uma funo genrica


apesar de uma funo genrica poder ser overload automaticamente se necessrio, ns podemos explicitar. a isso chamamos deexplicit specialization

Containers
list set unordered_set map unordered_map

Compilao
Esta pgina precisa ser reciclada (discuta). Ao melhor-la, voc estar ajudando o Wikilivros.

Compilao o processo de "traduo" do programa escrito em uma linguagem de programao para um formato no qual o computador entenda. A compilao gera um ficheiro - arquivo em portugus brasileiro - binrio (executvel) a partir do cdigo fonte.

A traduo do cdigo para o computador


Em C e C++ so 3 os programas usados para fazer a traduo do cdigo fonte (que so as linhas de cdigo que o programador escreve) num ficheiro executvel, que o computador pode executar: 1. Preprocessor - pr-processador 2. Compiler - compilador 3. Linker

Compilao

139

Pr-processador
Este um programa que busca no cdigo fonte no cdigo que escrevemos por diretivas que foram dirigidas a ele, ou seja linhas iniciadas com #, assim o pr-processador sabe que aquela instruo dirigida para ele. No exemplo tnhamos: #include <iostream> Ento o pr-processador inclui ficheiros localizados no ficheiro iostream. Ento tnhamos o cdigo fonte que depois transformado num outro cdigo fonte de acordo com as diretivas pr-processadas. Essencialmente, o pr-processador um processador de macros para uma linguagem de alto nvel.[1]

Compilador
Compilador um programa que pega cdigo fonte preprocessado e o traduz em instrues de linguagem de mquina, linguagem que o computador entende. Estas so guardadas num arquivo a parte, chamado de "object file" e tem a extenso .o ou .obj dependendo do compilador. Existem diferentes compiladores para diferentes linguagens de programao. Essa traduo feita se o cdigo estiver na linguagem que o compilador compilar. Existem regras de escrita e de gramtica. No caso de existir um erro de sintaxe, ento dar um erro de compilao.

Linker
Apesar do nosso "object file" ter as instrues em linguagem mquina, o computador ainda no poder correr como um programa. A razo que necessrio outro cdigo da biblioteca, que o cdigo do run-time library, que para as operaes comuns tipo a traduo o input do teclado ou a capacidade para interagir com hardware externo tipo o monitor para apresentar uma mensagem. Estas bibliotecas run-time costumam j estar instaladas com o sistema operacional, caso isso no acontea teremos de fazer o download delas. Ento o resultado da combinao do "object file" com as partes necessrias da biblioteca run-time fazem finalmente a criao de um ficheiro executvel com a extenso .exe

Processo de compilao
Em primeiro lugar, vamos escrever um cdigo que est na linguagem C++ e vamos gravar esse cdigo todo num ficheiro, que uma quantidade de memria no computador. Esse ficheiro fica com a terminao .CPP ou .CP ou C.. Chama-se a este conjunto de linhas que escrevemos de, cdigo fonte ou source code (pode ter a terminao .c, .cpp, e .cc - estas extenses dependem do compilador que se utiliza). Esse "source code" de alguma forma crptica e para algum que no saiba de c++ no entanto aquilo que neste momento chamamos de humam readable form. Para tornar o nosso source code num programa usamos um compilador que ir produzir um "object file". Este ficheiro tem normalmente a extenso. OBJ porm ainda no temos um programa executvel. Para isso vamos utilizar o linker. Uma das vantagens do c++ que usufrui de uma estrutura multi-file. A linguagem permite compilao separada, onde partes do programa total podem estar numa ou mais source files e estes podem ser compilados independentemente de cada um. A ideia que o processo de compilao produz files que depois podem ser linked together usando um editor de link ou loads que o sistema provem. Os programas feitos em c++ so tipicamente ficheiros .OBJ ligados uns aos outros com uma ou mais libraries. Estas so uma coleo de linkable files que ns crimos ou que foram fornecidas (vm com o compilador ou compramos). Depois de se fazer este linking que obtemos o arquivo executvel. No Windows, ele tem terminao .exe. Assim, o sistema operacional reconhece o programa como independente.

Compilao Os compiladores atuais incluem tambm pr-compiladores, (ou pr-processadores) (antes eram software independente, extra), estes pr-compiladores vo fazer alteraes ao cdigo fonte, que basicamente consistem em eliminar pedaos de cdigo que escrevemos, e/ou substituir pedaos de cdigo que escrevemos por outro (copy-paste), enfim, alterar o cdigo fonte por outro cdigo fonte. Depois que se compila.

140

Referncias
[1] http:/ / www. dca. fee. unicamp. br/ cursos/ EA876/ apostila/ HTML/ node150. html

O pr-processador C

Lista de Palavras Reservadas do C++


Estas so as palavras reservadas do c++:
alignas (since C++11) and_eq bitand break char class alignof (since C++11) asm bitor case char16_t (since C++11) compl and auto bool catch char32_t (since C++11) const continue delete dynamic_cast explicit false friend inline mutable noexcept (since C++11) nullptr (since C++11) or_eq public return sizeof

constexpr (since C++11) const_cast decltype (since C++11) do else export float goto int namespace not operator private register short static struct this true typeid unsigned void while default double enum extern for if long new not_eq or protected reinterpret_cast signed

static_assert (since C++11) static_cast switch template

thread_local (since C++11) throw try typename using volatile xor typedef union virtual wchar_t xor_eq

Lista de Palavras Reservadas do C++

141

Maiores detalhes podem ser encontrados em: http://en.cppreference.com/w/cpp/keyword

Lista de Sequncias de Escape


Estes so caracteres que so difceis de serem expressos de outra forma em um cdigo fonte. Todos eles so precedidos de uma barra invertida. A Tabela 1 apresenta a lista de sequncias de escape.
Controle/Caracter Nulo (null) Campainha (bell) Retrocesso (backspace) Tabulao horizontal Nova linha (new line) Tabulao vertical Sequncia de escape Valor ASCII \0 \a \b \t \n \v 00 07 08 09 10 11 12 13 34 39 63 92

Alimentao de folha (form feed) \f Retorno de carro (carriage return) \r Aspas (") Apstrofo (') Interrogao (?) Barra invertida (\) \" \' \? \\

Tabela 1 - Lista de Sequncias de Escape em C++

Tabela ASCII

142

Tabela ASCII
Programa que gera a tabela ASCII do C++ (programa escrito em c++). Nenhum dos 2 programas mostra a tabela inteira. O programa mostra alguns caracteres que o programa 2 no mostra. De modo geral, faltam alguns caracteres.
Esta pgina um esboo de informtica. Ampliando-a voc ajudar a melhorar o Wikilivros.

Programa 1
#include <stdio.h> #include <iostream> using namespace std;

int main() { //CARACTER " " (ENTER) = DECIMAL 10 HEXADECIMAL A;

int s = -127; cout<<" CARAC DEC HEX\n\n"; for ( char i = -127; i<127; i++ ) { cout<<" "<<i<<" "<<s<<" "; printf("%X",s); cout<<"\n"; s++; } cout<<"\n CARAC DEC HEX\n\n"; cout<<" \x122 ENTER \x122 10 A\n\n"; system ("PAUSE"); return 0; }

Programa 2
#include <stdio.h> #include <iostream> int main() { int x; printf(" DEC\tHEX\tA DEC\tHEX\t"); printf(" DEC\tHEX\n"); for(x=-173;x<360;x++) {

Tabela ASCII printf("%c printf("%c printf("%c printf("%c %3i\t%2X\t",x,x,x); %3i\t%2X\t",x+32,x+32,x+32); %3i\t%2X\t",x+64,x+64,x+64); %3i\t%2X\n",x+96,x+96,x+96);

143

} system ("PAUSE"); return 0; }

C++11
Origem: Wikipdia, a enciclopdia livre. C++11, anteriormente conhecido por C++0x o novo padro para a linguagem de programao C++. Ele substitui o antigo padro do C++, o ISO/IEC 14882, que foi publicado em 1998 e atualizado em 2003. Estes predecessores foram informalmente chamados C++98 e C++03. O novo padro incluir muitas adies ao ncleo da linguagem (sua implementao principal), e estender a biblioteca padro do C++, incluindo a maior parte da biblioteca do chamado C++ Technical Report 1 um documento que prope mudanas ao C++ com exceo das funes matemticas especficas. Esse nome uma referncia ao ano no qual o padro ser lanado. O comit pretendia introduzir o novo padro em 2009,1 a partir do que o ento chamado "C++0x" passaria a se chamar "C++09", o que significa que o documento deveria estar pronto para a ratificao dos membros do comit at o final de 2008. Para cumprir o prazo, o comit decidiu focar seus esforos nas solues introduzidas at 2006 e ignorar novas propostas.2 porm ele ficar pronto apenas em 2010. Linguagens de programao como o C++ utilizam um processo evolucionrio para desenvolverem suas definies. Tal processo inevitavelmente culmina em problemas de compatibilidade com cdigo pr-existente, o que ocasionalmente aconteceu durante o processo de desenvolvimento do C++. Entretanto, de acordo com o anncio feito por Bjarne Stroustrup inventor da linguagem C++ e membro do comit o novo padro ser quase completamente compatvel com o padro atual.3 Novas classes: std::array std::tuple std::foward_list std::unordered_set std::unordered_multiset std::unordered_map std::unordered_multimap Regular expressions library: http://en.cppreference.com/w/cpp/regex Atomic operations library: http://en.cppreference.com/w/cpp/atomic Thread support library: http://en.cppreference.com/w/cpp/thread

Fontes e Editores da Pgina

144

Fontes e Editores da Pgina


Objetivo Fonte: http://pt.wikibooks.org/w/index.php?oldid=212683 Contribuidores: Contribuidor, Helder.wiki, Marcos Antnio Nunes de Moura, SallesNeto BR, Wbrito Por que C++? Fonte: http://pt.wikibooks.org/w/index.php?oldid=244119 Contribuidores: Abacaxi, Helder.wiki, Jorge Morais, Marcos Antnio Nunes de Moura, SallesNeto BR, Wbrito, 2 edies annimas Diferenas entre C e C++ Fonte: http://pt.wikibooks.org/w/index.php?oldid=265805 Contribuidores: Abacaxi, Fabio Basso, Helder.wiki, Marcos Antnio Nunes de Moura, Master, Torneira, 1 edies annimas Introduo Fonte: http://pt.wikibooks.org/w/index.php?oldid=267436 Contribuidores: Abacaxi, Helder.wiki, Mappim, Marcos Antnio Nunes de Moura, Rautopia, 4 edies annimas Al, Mundo! Fonte: http://pt.wikibooks.org/w/index.php?oldid=267384 Contribuidores: Abacaxi, Albmont, Carlosmacapuna, Daveiro, Edudobay, Focli, Helder.wiki, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Petrusz1, Rautopia, Renatofq, Sygmn, Wbrito, 20 edies annimas Variveis e constantes Fonte: http://pt.wikibooks.org/w/index.php?oldid=238714 Contribuidores: Jorge Morais, Marcos Antnio Nunes de Moura, Rautopia Ponteiros Fonte: http://pt.wikibooks.org/w/index.php?oldid=247694 Contribuidores: Abacaxi, Albmont, Jonathan Queiroz, Jorge Morais, Marcos Antnio Nunes de Moura, 3 edies annimas Vetores Fonte: http://pt.wikibooks.org/w/index.php?oldid=267854 Contribuidores: Abacaxi, Daveiro, Edudobay, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Master, Raylton P. Sousa, Wbrito, 6 edies annimas Estruturas Fonte: http://pt.wikibooks.org/w/index.php?oldid=256735 Contribuidores: Abacaxi, Albmont, Marcos Antnio Nunes de Moura, 5 edies annimas Operadores Fonte: http://pt.wikibooks.org/w/index.php?oldid=244121 Contribuidores: Abacaxi, Marcos Antnio Nunes de Moura Deciso e controle de fluxo Fonte: http://pt.wikibooks.org/w/index.php?oldid=266793 Contribuidores: Abacaxi, Marcos Antnio Nunes de Moura, 11 edies annimas Estruturas de repetio Fonte: http://pt.wikibooks.org/w/index.php?oldid=266523 Contribuidores: Abacaxi, Diegobza, Helder.wiki, LlamaAl, Lucas Daltro, Marcos Antnio Nunes de Moura, 1 edies annimas Funes Fonte: http://pt.wikibooks.org/w/index.php?oldid=249232 Contribuidores: Abacaxi, Jonas AGX, 2 edies annimas Referncias de dados Fonte: http://pt.wikibooks.org/w/index.php?oldid=239660 Contribuidores: Albmont, Marcos Antnio Nunes de Moura, Reder, 5 edies annimas Entrada e sada de dados Fonte: http://pt.wikibooks.org/w/index.php?oldid=266602 Contribuidores: Abacaxi, Albmont, Daveiro, Edudobay, Jeferson90, Jonathan Queiroz, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Torneira, Wbrito, 16 edies annimas Entrada e sada de dados 2 Fonte: http://pt.wikibooks.org/w/index.php?oldid=256748 Contribuidores: Abacaxi, Daveiro, Diego.g.a, Edudobay, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Raylton P. Sousa, Wbrito, 19 edies annimas Manipulando strings Fonte: http://pt.wikibooks.org/w/index.php?oldid=264914 Contribuidores: Abacaxi, Albmont, Daveiro, Fabiobasso, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Wbrito, 20 edies annimas Classes Fonte: http://pt.wikibooks.org/w/index.php?oldid=266994 Contribuidores: Abacaxi, Albmont, Daveiro, Hudsonkem, Jeferson90, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Wbrito, 18 edies annimas Encapsulamento Fonte: http://pt.wikibooks.org/w/index.php?oldid=214125 Contribuidores: MGFE Jnior, Marcos Antnio Nunes de Moura, 2 edies annimas Herana Fonte: http://pt.wikibooks.org/w/index.php?oldid=214299 Contribuidores: Albmont, Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Wbrito, 14 edies annimas Polimorfismo Fonte: http://pt.wikibooks.org/w/index.php?oldid=265821 Contribuidores: Abacaxi, Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Torneira, Wbrito, 5 edies annimas Friend Fonte: http://pt.wikibooks.org/w/index.php?oldid=255619 Contribuidores: Abacaxi, Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Wbrito, 8 edies annimas Classes internas Fonte: http://pt.wikibooks.org/w/index.php?oldid=212708 Contribuidores: Marcos Antnio Nunes de Moura Sobrecarga de operadores Fonte: http://pt.wikibooks.org/w/index.php?oldid=231778 Contribuidores: Marcos Antnio Nunes de Moura, Raylton P. Sousa, 5 edies annimas Alocao dinmica de memria Fonte: http://pt.wikibooks.org/w/index.php?oldid=266992 Contribuidores: Abacaxi, Daveiro, Helder.wiki, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Petrusz1, Wbrito, 14 edies annimas Excees Fonte: http://pt.wikibooks.org/w/index.php?oldid=203880 Contribuidores: Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, SallesNeto BR, Wbrito, 5 edies annimas Namespace Fonte: http://pt.wikibooks.org/w/index.php?oldid=203888 Contribuidores: Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Wbrito, 4 edies annimas Templates Fonte: http://pt.wikibooks.org/w/index.php?oldid=267395 Contribuidores: Abacaxi, Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Wbrito, 8 edies annimas Containers Fonte: http://pt.wikibooks.org/w/index.php?oldid=267423 Contribuidores: Abacaxi, 1 edies annimas Compilao Fonte: http://pt.wikibooks.org/w/index.php?oldid=266790 Contribuidores: Abacaxi, Daveiro, Edudobay, Jonas AGX, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Master, Renatofq, SallesNeto BR, Wbrito, 5 edies annimas Lista de Palavras Reservadas do C++ Fonte: http://pt.wikibooks.org/w/index.php?oldid=266289 Contribuidores: Abacaxi, Lucas Daltro, 1 edies annimas Lista de Sequncias de Escape Fonte: http://pt.wikibooks.org/w/index.php?oldid=253634 Contribuidores: Abacaxi, Yoroi Tabela ASCII Fonte: http://pt.wikibooks.org/w/index.php?oldid=265804 Contribuidores: Abacaxi, Helder.wiki, Torneira, 2 edies annimas C++11 Fonte: http://pt.wikibooks.org/w/index.php?oldid=267422 Contribuidores: Abacaxi, 1 edies annimas

Fontes, Licenas e Editores da Imagem

145

Fontes, Licenas e Editores da Imagem


Image:Nuvola apps konsole.png Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Nuvola_apps_konsole.png Licena: GNU Lesser General Public License Contribuidores: Alno, Alphax Image:Recycle001.svg Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Recycle001.svg Licena: desconhecido Contribuidores: Users Cbuckley, Jpowell on en.wikipedia

Licena

146

Licena
Creative Commons Attribution-Share Alike 3.0 //creativecommons.org/licenses/by-sa/3.0/