programacao cpp

140
Programação C++ 22 de Setembro de 2008

Upload: tiago

Post on 23-Jan-2017

33 views

Category:

Education


9 download

TRANSCRIPT

Page 1: Programacao cpp

Programação C++

22 de Setembro de 2008

Page 2: Programacao cpp

Conteúdo

I Sobre essa apostila 4

II Informações Básicas 6

III GNU Free Documentation License 11

IV Programação C++ 20

1 O que é o C++ 21

2 Plano de ensino 222.1 Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.2 Público Alvo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.3 Pré-requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.4 Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.5 Metodologia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.6 Cronograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.7 Programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.8 Avaliação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242.9 Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3 Introdução e Breve História 263.1 Introdução ao C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.1.1 Breve História do C e do C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . 263.1.2 Algumas novidades... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.2 Características do C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.3 Alguns conceitos básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.4 Ambientes de Desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.5 Incompatibilidades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

4 Iniciando 304.1 Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304.2 Conceitos Básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314.3 Símbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324.4 Os Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334.5 Precedência de Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

1

Page 3: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

4.6 Outros Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

5 Constantes 375.1 Tipos de Dados Fundamentais de C++ . . . . . . . . . . . . . . . . . . . . . . . . . . 375.2 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395.3 Literais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

6 I/O com Arquivos 406.1 Entrada/Saída de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406.2 Stringstream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

7 Estruturas de Iteração e Desvios Condicionais 447.1 Estruturas de Iteração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

7.1.1 Estruturas de Iteração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457.1.2 Desvios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

7.2 Escopo de Variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527.3 Funções sem tipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537.4 Valores Padrões nos Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557.5 Especificador Inline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567.6 Recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 577.7 Declarações de Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

8 Vetores e Seqüência de Caracteres 608.1 Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608.2 Arrays multidimensionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 628.3 Passando Vetores Como Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . 638.4 Seqüencia de Caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

9 Ponteiros e Memória Dinâmica 679.1 Ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

9.1.1 Ponteiros Aritméticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719.1.2 Ponteiros para Ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729.1.3 Ponteiros sem tipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729.1.4 Ponteiro Nulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739.1.5 Ponteiros para Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

9.2 Memória Dinâmica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

10 Estruturas de Dados 7810.1 Tipos de Dados Definidos (typedef) . . . . . . . . . . . . . . . . . . . . . . . . . . . 8410.2 Uniões (Unions) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8410.3 Uniões Anônimas (Anonymous unions) . . . . . . . . . . . . . . . . . . . . . . . . . 8510.4 Enumerações (enum) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

11 Programação Orientada a Objeto - POO 8811.1 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8811.2 Construtores e Destrutores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9011.3 Construtores Sobrecarregados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9211.4 Construtor Padrão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9411.5 Classes definidas com struct e union . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

2

Page 4: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

11.6 Sobrecarregando Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9611.7 Friendship e Herança . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

11.7.1 Funções Friend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10011.8 Herança Múltipla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10611.9 Polimorfismo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

12 Templates, Namespaces 11512.1 Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11512.2 Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

13 Exceptions e Diretivas 12713.1 Diretivas Pré-Processamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

14 Entrada/Saída com Arquivos 137

3

Page 5: Programacao cpp

Parte I

Sobre essa apostila

4

Page 6: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Conteúdo

O conteúdo dessa apostila é fruto da compilação de diversos materiais livres publicados na in-ternet, disponíveis em diversos sites ou originalmente produzido no CDTC em http://www.cdtc.org.br.

O formato original deste material bem como sua atualização está disponível dentro da licençaGNU Free Documentation License, cujo teor integral encontra-se aqui reproduzido na seção demesmo nome, tendo inclusive uma versão traduzida (não oficial).

A revisão e alteração vem sendo realizada pelo CDTC ([email protected]), desde outubrode 2006. Criticas e sugestões construtivas são bem-vindas a qualquer tempo.

Autores

A autoria deste conteúdo, atividades e avaliações é de responsabilidade de Júlio Cesar Júnior([email protected]) .

O texto original faz parte do projeto Centro de Difusão de Tecnolgia e Conhecimento, que vemsendo realizado pelo ITI em conjunto com outros parceiros institucionais, atuando em conjuntocom as universidades federais brasileiras que tem produzido e utilizado Software Livre, apoiandoinclusive a comunidade Free Software junto a outras entidades no país.

Informações adicionais podem ser obtidas atréves do email [email protected], ou dahome page da entidade, através da URL http://www.cdtc.org.br .

Garantias

O material contido nesta apostila é isento de garantias e o seu uso é de inteira responsabi-lidade do usuário/leitor. Os autores, bem como o ITI e seus parceiros, não se responsabilizamdireta ou indiretamente por qualquer prejuízo oriundo da utilização do material aqui contido.

Licença

Copyright ©2006,Júlio Cesar Júnior ([email protected]) .

Permission is granted to copy, distribute and/or modify this document under the termsof the GNU Free Documentation License, Version 1.1 or any later version published bythe Free Software Foundation; with the Invariant Chapter being SOBRE ESSA APOS-TILA. A copy of the license is included in the section entitled GNU Free DocumentationLicense.

5

Page 7: Programacao cpp

Parte II

Informações Básicas

6

Page 8: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Sobre o CDTC

Objetivo Geral

O Projeto CDTC visa a promoção e o desenvolvimento de ações que incentivem a dissemina-ção de soluções que utilizem padrões abertos e não proprietários de tecnologia, em proveito dodesenvolvimento social, cultural, político, tecnológico e econômico da sociedade brasileira.

Objetivo Específico

Auxiliar o Governo Federal na implantação do plano nacional de software não-proprietário ede código fonte aberto, identificando e mobilizando grupos de formadores de opinião dentre osservidores públicos e agentes políticos da União Federal, estimulando e incentivando o mercadonacional a adotar novos modelos de negócio da tecnologia da informação e de novos negóciosde comunicação com base em software não-proprietário e de código fonte aberto, oferecendotreinamento específico para técnicos, profissionais de suporte e funcionários públicos usuários,criando grupos de funcionários públicos que irão treinar outros funcionários públicos e atuar comoincentivadores e defensores de produtos de software não proprietários e código fonte aberto, ofe-recendo conteúdo técnico on-line para serviços de suporte, ferramentas para desenvolvimento deprodutos de software não proprietários e de seu código fonte livre, articulando redes de terceiros(dentro e fora do governo) fornecedoras de educação, pesquisa, desenvolvimento e teste de pro-dutos de software livre.

Guia do aluno

Neste guia, você terá reunidas uma série de informações importantes para que você comeceseu curso. São elas:

• Licenças para cópia de material disponível

• Os 10 mandamentos do aluno de Educação a Distância

• Como participar dos fóruns e da wikipédia

• Primeiros passos

É muito importante que você entre em contato com TODAS estas informações, seguindo oroteiro acima.

Licença

Copyright ©2006, Júlio Cesar Júnior ([email protected]) .

7

Page 9: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

É dada permissão para copiar, distribuir e/ou modificar este documento sob os termosda Licença de Documentação Livre GNU, Versão 1.1 ou qualquer versão posteriorpublicada pela Free Software Foundation; com o Capítulo Invariante SOBRE ESSAAPOSTILA. Uma cópia da licença está inclusa na seção entitulada "Licença de Docu-mentação Livre GNU".

Os 10 mandamentos do aluno de educação online

• 1. Acesso a Internet: ter endereço eletrônico, um provedor e um equipamento adequado épré-requisito para a participação nos cursos a distância.

• 2. Habilidade e disposição para operar programas: ter conhecimentos básicos de Informá-tica é necessário para poder executar as tarefas.

• 3. Vontade para aprender colaborativamente: interagir, ser participativo no ensino a distân-cia conta muitos pontos, pois irá colaborar para o processo ensino-aprendizagem pessoal,dos colegas e dos professores.

• 4. Comportamentos compatíveis com a etiqueta: mostrar-se interessado em conhecer seuscolegas de turma respeitando-os e fazendo ser respeitado pelo mesmo.

• 5. Organização pessoal: planejar e organizar tudo é fundamental para facilitar a sua revisãoe a sua recuperação de materiais.

• 6. Vontade para realizar as atividades no tempo correto: anotar todas as suas obrigações erealizá-las em tempo real.

• 7. Curiosidade e abertura para inovações: aceitar novas idéias e inovar sempre.

• 8. Flexibilidade e adaptação: requisitos necessário a mudança tecnológica, aprendizagense descobertas.

• 9. Objetividade em sua comunicação: comunicar-se de forma clara, breve e transparente éponto-chave na comunicação pela Internet.

• 10. Responsabilidade: ser responsável por seu próprio aprendizado. O ambiente virtual nãocontrola a sua dedicação, mas reflete os resultados do seu esforço e da sua colaboração.

Como participar dos fóruns e Wikipédia

Você tem um problema e precisa de ajuda?

Podemos te ajudar de 2 formas:

A primeira é o uso dos fóruns de notícias e de dúvidas gerais que se distinguem pelo uso:

O fórum de notícias tem por objetivo disponibilizar um meio de acesso rápido a informaçõesque sejam pertinentes ao curso (avisos, notícias). As mensagens postadas nele são enviadas a

8

Page 10: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

todos participantes. Assim, se o monitor ou algum outro participante tiver uma informação queinteresse ao grupo, favor postá-la aqui.Porém, se o que você deseja é resolver alguma dúvida ou discutir algum tópico específico docurso, é recomendado que você faça uso do Fórum de dúvidas gerais que lhe dá recursos maisefetivos para esta prática.

. O fórum de dúvidas gerais tem por objetivo disponibilizar um meio fácil, rápido e interativopara solucionar suas dúvidas e trocar experiências. As mensagens postadas nele são enviadasa todos participantes do curso. Assim, fica muito mais fácil obter respostas, já que todos podemajudar.Se você receber uma mensagem com algum tópico que saiba responder, não se preocupe com aformalização ou a gramática. Responda! E não se esqueça de que antes de abrir um novo tópicoé recomendável ver se a sua pergunta já foi feita por outro participante.

A segunda forma se dá pelas Wikis:

Uma wiki é uma página web que pode ser editada colaborativamente, ou seja, qualquer par-ticipante pode inserir, editar, apagar textos. As versões antigas vão sendo arquivadas e podemser recuperadas a qualquer momento que um dos participantes o desejar. Assim, ela oferece umótimo suporte a processos de aprendizagem colaborativa. A maior wiki na web é o site "Wikipé-dia", uma experiência grandiosa de construção de uma enciclopédia de forma colaborativa, porpessoas de todas as partes do mundo. Acesse-a em português pelos links:

• Página principal da Wiki - http://pt.wikipedia.org/wiki/

Agradecemos antecipadamente a sua colaboração com a aprendizagem do grupo!

Primeiros Passos

Para uma melhor aprendizagem é recomendável que você siga os seguintes passos:

• Ler o Plano de Ensino e entender a que seu curso se dispõe a ensinar;

• Ler a Ambientação do Moodle para aprender a navegar neste ambiente e se utilizar dasferramentas básicas do mesmo;

• Entrar nas lições seguindo a seqüência descrita no Plano de Ensino;

• Qualquer dúvida, reporte ao Fórum de Dúvidas Gerais.

Perfil do Tutor

Segue-se uma descrição do tutor ideal, baseada no feedback de alunos e de tutores.

O tutor ideal é um modelo de excelência: é consistente, justo e profissional nos respectivosvalores e atitudes, incentiva mas é honesto, imparcial, amável, positivo, respeitador, aceita asidéias dos estudantes, é paciente, pessoal, tolerante, apreciativo, compreensivo e pronto a ajudar.

9

Page 11: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

A classificação por um tutor desta natureza proporciona o melhor feedback possível, é crucial, e,para a maior parte dos alunos, constitui o ponto central do processo de aprendizagem.’ Este tutorou instrutor:

• fornece explicações claras acerca do que ele espera, e do estilo de classificação que iráutilizar;

• gosta que lhe façam perguntas adicionais;

• identifica as nossas falhas, mas corrige-as amavelmente’, diz um estudante, ’e explica por-que motivo a classificação foi ou não foi atribuída’;

• tece comentários completos e construtivos, mas de forma agradável (em contraste com umreparo de um estudante: ’os comentários deixam-nos com uma sensação de crítica, deameaça e de nervosismo’)

• dá uma ajuda complementar para encorajar um estudante em dificuldade;

• esclarece pontos que não foram entendidos, ou corretamente aprendidos anteriormente;

• ajuda o estudante a alcançar os seus objetivos;

• é flexível quando necessário;

• mostra um interesse genuíno em motivar os alunos (mesmo os principiantes e, por isso,talvez numa fase menos interessante para o tutor);

• escreve todas as correções de forma legível e com um nível de pormenorização adequado;

• acima de tudo, devolve os trabalhos rapidamente;

10

Page 12: Programacao cpp

Parte III

GNU Free Documentation License

11

Page 13: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

(Traduzido pelo João S. O. Bueno através do CIPSGA em 2001)Esta é uma tradução não oficial da Licençaa de Documentação Livre GNU em Português

Brasileiro. Ela não é publicada pela Free Software Foundation, e não se aplica legalmente a dis-tribuição de textos que usem a GFDL - apenas o texto original em Inglês da GNU FDL faz isso.Entretanto, nós esperamos que esta tradução ajude falantes de português a entenderem melhora GFDL.

This is an unofficial translation of the GNU General Documentation License into Brazilian Por-tuguese. It was not published by the Free Software Foundation, and does not legally state thedistribution terms for software that uses the GFDL–only the original English text of the GFDL doesthat. However, we hope that this translation will help Portuguese speakers understand the GFDLbetter.

Licença de Documentação Livre GNU Versão 1.1, Março de 2000

Copyright (C) 2000 Free Software Foundation, Inc.59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

É permitido a qualquer um copiar e distribuir cópias exatas deste documento de licença, masnão é permitido alterá-lo.

INTRODUÇÃO

O propósito desta Licença é deixar um manual, livro-texto ou outro documento escrito "livre"nosentido de liberdade: assegurar a qualquer um a efetiva liberdade de copiá-lo ou redistribui-lo,com ou sem modificações, comercialmente ou não. Secundariamente, esta Licença mantémpara o autor e editor uma forma de ter crédito por seu trabalho, sem ser considerado responsávelpelas modificações feitas por terceiros.

Esta Licença é um tipo de "copyleft"("direitos revertidos"), o que significa que derivações dodocumento precisam ser livres no mesmo sentido. Ela complementa a GNU Licença Pública Ge-ral (GNU GPL), que é um copyleft para software livre.

Nós fizemos esta Licença para que seja usada em manuais de software livre, por que softwarelivre precisa de documentação livre: um programa livre deve ser acompanhado de manuais queprovenham as mesmas liberdades que o software possui. Mas esta Licença não está restrita amanuais de software; ela pode ser usada para qualquer trabalho em texto, independentementedo assunto ou se ele é publicado como um livro impresso. Nós recomendamos esta Licença prin-cipalmente para trabalhos cujo propósito seja de introdução ou referência.

APLICABILIDADE E DEFINIÇÕES

Esta Licença se aplica a qualquer manual ou outro texto que contenha uma nota colocada pelodetentor dos direitos autorais dizendo que ele pode ser distribuído sob os termos desta Licença.

12

Page 14: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

O "Documento"abaixo se refere a qualquer manual ou texto. Qualquer pessoa do público é umlicenciado e é referida como "você".

Uma "Versão Modificada"do Documento se refere a qualquer trabalho contendo o documentoou uma parte dele, quer copiada exatamente, quer com modificações e/ou traduzida em outralíngua.

Uma "Seção Secundária"é um apêndice ou uma seção inicial do Documento que trata ex-clusivamente da relação dos editores ou dos autores do Documento com o assunto geral doDocumento (ou assuntos relacionados) e não contém nada que poderia ser incluído diretamentenesse assunto geral (Por exemplo, se o Documento é em parte um livro texto de matemática, aSeção Secundária pode não explicar nada de matemática).

Essa relação poderia ser uma questão de ligação histórica com o assunto, ou matérias relaci-onadas, ou de posições legais, comerciais, filosóficas, éticas ou políticas relacionadas ao mesmo.

As "Seções Invariantes"são certas Seções Secundárias cujos títulos são designados, comosendo de Seções Invariantes, na nota que diz que o Documento é publicado sob esta Licença.

Os "Textos de Capa"são certos trechos curtos de texto que são listados, como Textos de CapaFrontal ou Textos da Quarta Capa, na nota que diz que o texto é publicado sob esta Licença.

Uma cópia "Transparente"do Documento significa uma cópia que pode ser lida automatica-mente, representada num formato cuja especificação esteja disponível ao público geral, cujosconteúdos possam ser vistos e editados diretamente e sem mecanismos especiais com editoresde texto genéricos ou (para imagens compostas de pixels) programas de pintura genéricos ou(para desenhos) por algum editor de desenhos grandemente difundido, e que seja passível deservir como entrada a formatadores de texto ou para tradução automática para uma variedadede formatos que sirvam de entrada para formatadores de texto. Uma cópia feita em um formatode arquivo outrossim Transparente cuja constituição tenha sido projetada para atrapalhar ou de-sencorajar modificações subsequentes pelos leitores não é Transparente. Uma cópia que não é"Transparente"é chamada de "Opaca".

Exemplos de formatos que podem ser usados para cópias Transparentes incluem ASCII sim-ples sem marcações, formato de entrada do Texinfo, formato de entrada do LaTex, SGML ou XMLusando uma DTD disponibilizada publicamente, e HTML simples, compatível com os padrões, eprojetado para ser modificado por pessoas. Formatos opacos incluem PostScript, PDF, formatosproprietários que podem ser lidos e editados apenas com processadores de texto proprietários,SGML ou XML para os quais a DTD e/ou ferramentas de processamento e edição não estejamdisponíveis para o público, e HTML gerado automaticamente por alguns editores de texto comfinalidade apenas de saída.

A "Página do Título"significa, para um livro impresso, a página do título propriamente dita,mais quaisquer páginas subsequentes quantas forem necessárias para conter, de forma legível,o material que esta Licença requer que apareça na página do título. Para trabalhos que nãotenham uma página do título, "Página do Título"significa o texto próximo da aparição mais proe-minente do título do trabalho, precedendo o início do corpo do texto.

13

Page 15: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

FAZENDO CÓPIAS EXATAS

Você pode copiar e distribuir o Documento em qualquer meio, de forma comercial ou nãocomercial, desde que esta Licença, as notas de copyright, e a nota de licença dizendo que estaLicença se aplica ao documento estejam reproduzidas em todas as cópias, e que você não acres-cente nenhuma outra condição, quaisquer que sejam, às desta Licença.

Você não pode usar medidas técnicas para obstruir ou controlar a leitura ou confecção decópias subsequentes das cópias que você fizer ou distribuir. Entretanto, você pode aceitar com-pensação em troca de cópias. Se você distribuir uma quantidade grande o suficiente de cópias,você também precisa respeitar as condições da seção 3.

Você também pode emprestar cópias, sob as mesmas condições colocadas acima, e tambémpode exibir cópias publicamente.

FAZENDO CÓPIAS EM QUANTIDADE

Se você publicar cópias do Documento em número maior que 100, e a nota de licença doDocumento obrigar Textos de Capa, você precisará incluir as cópias em capas que tragam, clarae legivelmente, todos esses Textos de Capa: Textos de Capa da Frente na capa da frente, eTextos da Quarta Capa na capa de trás. Ambas as capas também precisam identificar clara elegivelmente você como o editor dessas cópias. A capa da frente precisa apresentar o titulo com-pleto com todas as palavras do título igualmente proeminentes e visíveis. Você pode adicionaroutros materiais às capas. Fazer cópias com modificações limitadas às capas, tanto quanto estaspreservem o título do documento e satisfaçam a essas condições, pode ser tratado como cópiaexata em outros aspectos.

Se os textos requeridos em qualquer das capas for muito volumoso para caber de formalegível, você deve colocar os primeiros (tantos quantos couberem de forma razoável) na capaverdadeira, e continuar os outros nas páginas adjacentes.

Se você publicar ou distribuir cópias Opacas do Documento em número maior que 100, vocêprecisa ou incluir uma cópia Transparente que possa ser lida automaticamente com cada cópiaOpaca, ou informar, em ou com, cada cópia Opaca a localização de uma cópia Transparentecompleta do Documento acessível publicamente em uma rede de computadores, a qual o públicousuário de redes tenha acesso a download gratuito e anônimo utilizando padrões públicos deprotocolos de rede. Se você utilizar o segundo método, você precisará tomar cuidados razoavel-mente prudentes, quando iniciar a distribuição de cópias Opacas em quantidade, para assegurarque esta cópia Transparente vai permanecer acessível desta forma na localização especificadapor pelo menos um ano depois da última vez em que você distribuir uma cópia Opaca (direta-mente ou através de seus agentes ou distribuidores) daquela edição para o público.

É pedido, mas não é obrigatório, que você contate os autores do Documento bem antes deredistribuir qualquer grande número de cópias, para lhes dar uma oportunidade de prover vocêcom uma versão atualizada do Documento.

14

Page 16: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

MODIFICAÇÕES

Você pode copiar e distribuir uma Versão Modificada do Documento sob as condições das se-ções 2 e 3 acima, desde que você publique a Versão Modificada estritamente sob esta Licença,com a Versão Modificada tomando o papel do Documento, de forma a licenciar a distribuiçãoe modificação da Versão Modificada para quem quer que possua uma cópia da mesma. Alémdisso, você precisa fazer o seguinte na versão modificada:

A. Usar na Página de Título (e nas capas, se houver alguma) um título distinto daquele do Do-cumento, e daqueles de versões anteriores (que deveriam, se houvesse algum, estarem listadosna seção "Histórico do Documento"). Você pode usar o mesmo título de uma versão anterior seo editor original daquela versão lhe der permissão;

B. Listar na Página de Título, como autores, uma ou mais das pessoas ou entidades responsá-veis pela autoria das modificações na Versão Modificada, conjuntamente com pelo menos cincodos autores principais do Documento (todos os seus autores principais, se ele tiver menos quecinco);

C. Colocar na Página de Título o nome do editor da Versão Modificada, como o editor;

D. Preservar todas as notas de copyright do Documento;

E. Adicionar uma nota de copyright apropriada para suas próprias modificações adjacente àsoutras notas de copyright;

F. Incluir, imediatamente depois das notas de copyright, uma nota de licença dando ao públicoo direito de usar a Versão Modificada sob os termos desta Licença, na forma mostrada no tópicoabaixo;

G. Preservar nessa nota de licença as listas completas das Seções Invariantes e os Textos deCapa requeridos dados na nota de licença do Documento;

H. Incluir uma cópia inalterada desta Licença;

I. Preservar a seção entitulada "Histórico", e seu título, e adicionar à mesma um item dizendopelo menos o título, ano, novos autores e editor da Versão Modificada como dados na Página deTítulo. Se não houver uma sessão denominada "Histórico"no Documento, criar uma dizendo otítulo, ano, autores, e editor do Documento como dados em sua Página de Título, então adicionarum item descrevendo a Versão Modificada, tal como descrito na sentença anterior;

J. Preservar o endereço de rede, se algum, dado no Documento para acesso público a umacópia Transparente do Documento, e da mesma forma, as localizações de rede dadas no Docu-mento para as versões anteriores em que ele foi baseado. Elas podem ser colocadas na seção"Histórico". Você pode omitir uma localização na rede para um trabalho que tenha sido publicadopelo menos quatro anos antes do Documento, ou se o editor original da versão a que ela se refirader sua permissão;

K. Em qualquer seção entitulada "Agradecimentos"ou "Dedicatórias", preservar o título da

15

Page 17: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

seção e preservar a seção em toda substância e fim de cada um dos agradecimentos de contri-buidores e/ou dedicatórias dados;

L. Preservar todas as Seções Invariantes do Documento, inalteradas em seus textos ou emseus títulos. Números de seção ou equivalentes não são considerados parte dos títulos da seção;

M. Apagar qualquer seção entitulada "Endossos". Tal sessão não pode ser incluída na VersãoModificada;

N. Não reentitular qualquer seção existente com o título "Endossos"ou com qualquer outrotítulo dado a uma Seção Invariante.

Se a Versão Modificada incluir novas seções iniciais ou apêndices que se qualifiquem comoSeções Secundárias e não contenham nenhum material copiado do Documento, você pode optarpor designar alguma ou todas aquelas seções como invariantes. Para fazer isso, adicione seustítulos à lista de Seções Invariantes na nota de licença da Versão Modificada. Esses títulos preci-sam ser diferentes de qualquer outro título de seção.

Você pode adicionar uma seção entitulada "Endossos", desde que ela não contenha qual-quer coisa além de endossos da sua Versão Modificada por várias pessoas ou entidades - porexemplo, declarações de revisores ou de que o texto foi aprovado por uma organização como adefinição oficial de um padrão.

Você pode adicionar uma passagem de até cinco palavras como um Texto de Capa da Frente, e uma passagem de até 25 palavras como um Texto de Quarta Capa, ao final da lista de Textosde Capa na Versão Modificada. Somente uma passagem de Texto da Capa da Frente e uma deTexto da Quarta Capa podem ser adicionados por (ou por acordos feitos por) qualquer entidade.Se o Documento já incluir um texto de capa para a mesma capa, adicionado previamente porvocê ou por acordo feito com alguma entidade para a qual você esteja agindo, você não podeadicionar um outro; mas você pode trocar o antigo, com permissão explícita do editor anterior queadicionou a passagem antiga.

O(s) autor(es) e editor(es) do Documento não dão permissão por esta Licença para que seusnomes sejam usados para publicidade ou para assegurar ou implicar endossamento de qualquerVersão Modificada.

COMBINANDO DOCUMENTOS

Você pode combinar o Documento com outros documentos publicados sob esta Licença, sobos termos definidos na seção 4 acima para versões modificadas, desde que você inclua na com-binação todas as Seções Invariantes de todos os documentos originais, sem modificações, e listetodas elas como Seções Invariantes de seu trabalho combinado em sua nota de licença.

O trabalho combinado precisa conter apenas uma cópia desta Licença, e Seções InvariantesIdênticas com multiplas ocorrências podem ser substituídas por apenas uma cópia. Se houvermúltiplas Seções Invariantes com o mesmo nome mas com conteúdos distintos, faça o título de

16

Page 18: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

cada seção único adicionando ao final do mesmo, em parênteses, o nome do autor ou editororigianl daquela seção, se for conhecido, ou um número que seja único. Faça o mesmo ajustenos títulos de seção na lista de Seções Invariantes nota de licença do trabalho combinado.

Na combinação, você precisa combinar quaisquer seções entituladas "Histórico"dos diver-sos documentos originais, formando uma seção entitulada "Histórico"; da mesma forma combinequaisquer seções entituladas "Agradecimentos", ou "Dedicatórias". Você precisa apagar todas asseções entituladas como "Endosso".

COLETÂNEAS DE DOCUMENTOS

Você pode fazer uma coletânea consitindo do Documento e outros documentos publicadossob esta Licença, e substituir as cópias individuais desta Licença nos vários documentos comuma única cópia incluida na coletânea, desde que você siga as regras desta Licença para cópiaexata de cada um dos Documentos em todos os outros aspectos.

Você pode extrair um único documento de tal coletânea, e distribuí-lo individualmente sobesta Licença, desde que você insira uma cópia desta Licença no documento extraído, e siga estaLicença em todos os outros aspectos relacionados à cópia exata daquele documento.

AGREGAÇÃO COM TRABALHOS INDEPENDENTES

Uma compilação do Documento ou derivados dele com outros trabalhos ou documentos se-parados e independentes, em um volume ou mídia de distribuição, não conta como uma Ver-são Modificada do Documento, desde que nenhum copyright de compilação seja reclamado pelacompilação. Tal compilação é chamada um "agregado", e esta Licença não se aplica aos outrostrabalhos auto-contidos compilados junto com o Documento, só por conta de terem sido assimcompilados, e eles não são trabalhos derivados do Documento.

Se o requerido para o Texto de Capa na seção 3 for aplicável a essas cópias do Documento,então, se o Documento constituir menos de um quarto de todo o agregado, os Textos de Capado Documento podem ser colocados em capas adjacentes ao Documento dentro do agregado.Senão eles precisarão aparecer nas capas de todo o agregado.

TRADUÇÃO

Tradução é considerada como um tipo de modificação, então você pode distribuir traduçõesdo Documento sob os termos da seção 4. A substituição de Seções Invariantes por traduçõesrequer uma permissão especial dos detentores do copyright das mesmas, mas você pode incluirtraduções de algumas ou de todas as Seções Invariantes em adição às versões orignais dessasSeções Invariantes. Você pode incluir uma tradução desta Licença desde que você também in-clua a versão original em Inglês desta Licença. No caso de discordância entre a tradução e a

17

Page 19: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

versão original em Inglês desta Licença, a versão original em Inglês prevalecerá.

TÉRMINO

Você não pode copiar, modificar, sublicenciar, ou distribuir o Documento exceto como expres-samente especificado sob esta Licença. Qualquer outra tentativa de copiar, modificar, sublicen-ciar, ou distribuir o Documento é nula, e resultará automaticamente no término de seus direitossob esta Licença. Entretanto, terceiros que tenham recebido cópias, ou direitos de você sob estaLicença não terão suas licenças terminadas, tanto quanto esses terceiros permaneçam em totalacordo com esta Licença.

REVISÕES FUTURAS DESTA LICENÇA

A Free Software Foundation pode publicar novas versões revisadas da Licença de Documen-tação Livre GNU de tempos em tempos. Tais novas versões serão similares em espirito à versãopresente, mas podem diferir em detalhes ao abordarem novos porblemas e preocupações. Vejahttp://www.gnu.org/copyleft/.

A cada versão da Licença é dado um número de versão distinto. Se o Documento especificarque uma versão particular desta Licença "ou qualquer versão posterior"se aplica ao mesmo, vocêtem a opção de seguir os termos e condições daquela versão específica, ou de qualquer versãoposterior que tenha sido publicada (não como rascunho) pela Free Software Foundation. Se oDocumento não especificar um número de Versão desta Licença, você pode escolher qualquerversão já publicada (não como rascunho) pela Free Software Foundation.

ADENDO: Como usar esta Licença para seus documentos

Para usar esta Licença num documento que você escreveu, inclua uma cópia desta Licençano documento e ponha as seguintes notas de copyright e licenças logo após a página de título:

Copyright (c) ANO SEU NOME.É dada permissão para copiar, distribuir e/ou modificar este documento sob os termos da Licençade Documentação Livre GNU, Versão 1.1 ou qualquer versão posterior publicada pela Free Soft-ware Foundation; com as Seções Invariantes sendo LISTE SEUS TÍTULOS, com os Textos daCapa da Frente sendo LISTE, e com os Textos da Quarta-Capa sendo LISTE. Uma cópia da li-cença está inclusa na seção entitulada "Licença de Documentação Livre GNU".

Se você não tiver nenhuma Seção Invariante, escreva "sem Seções Invariantes"ao invés dedizer quais são invariantes. Se você não tiver Textos de Capa da Frente, escreva "sem Textos deCapa da Frente"ao invés de "com os Textos de Capa da Frente sendo LISTE"; o mesmo para osTextos da Quarta Capa.

Se o seu documento contiver exemplos não triviais de código de programas, nós recomenda-mos a publicação desses exemplos em paralelo sob a sua escolha de licença de software livre,

18

Page 20: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

tal como a GNU General Public License, para permitir o seu uso em software livre.

19

Page 21: Programacao cpp

Parte IV

Programação C++

20

Page 22: Programacao cpp

Capítulo 1

O que é o C++

O C++ é uma linguagem de programação de alto nível com facilidades para o uso em baixonível (herdados do C), multiparadigma e de uso geral. Desde os anos 1990 é uma das linguagenscomerciais mais populares, sendo bastante usada também na academia por seu grande desem-penho e base de utilizadores.

21

Page 23: Programacao cpp

Capítulo 2

Plano de ensino

2.1 Objetivo

Qualificar técnicos e programadores na linguagem de programação c++.

2.2 Público Alvo

Técnicos e Programadores que desejam trabalhar com C++.

2.3 Pré-requisitos

Os usuários deverão ser, necessariamente, indicados por empresas públicas e ter conheci-mento básico acerca da lógica de programação.

2.4 Descrição

O curso de Introdução à Programação C++ será realizado na modalidade EAD e utilizaráa plataforma Moodle como ferramenta de aprendizagem. Ele é composto de um módulo deaprendizado que será dado na primeira semana e um módulo de avaliação que será dado nasegunda semana. O material didático estará disponível on-line de acordo com as datas pré-estabelecidas no calendário.

2.5 Metodologia

O curso está dividido da seguinte maneira:

2.6 Cronograma

• Introdução e Breve História;

• Iniciando;

22

Page 24: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

• Operadores, Identificadores e Símbolos;

• Constantes;

• Entrada e Saída de Dados;

• Estruturas de Iteração e Desvios Condicionais;

• Funções;

• Vetores e Seqüência de Caracteres;

• Ponteiros e Memória Dinâmica;

• Estruturas de Dados;

• Programação Orientada a Objeto;

• Programação Orientada a Objeto - continuação;

• Finalizando POO;

• Templates, Namespaces;

• Exceptions, Type Casting, Diretivas;

• I/O com arquivos;

• Avaliação de aprendizagem;

• Avaliação do curso;

As lições contém o conteúdo principal. Elas poderão ser acessadas quantas vezes forem ne-cessárias, desde que esteja dentro da semana programada. Ao final de uma lição, você receberáuma nota de acordo com o seu desempenho. Responda com atenção às perguntas de cada lição,pois elas serão consideradas na sua nota final. Caso sua nota numa determinada lição for menordo que 6.0, sugerimos que você faça novamente esta lição.

Ao final do curso será disponibilizada a avaliação referente ao curso. Tanto as notas das liçõesquanto a da avaliação serão consideradas para a nota final. Todos os módulos ficarão visíveispara que possam ser consultados durante a avaliação final.

Aconselhamos a leitura da "Ambientação do Moodle"para que você conheça a plataforma deEnsino a Distância, evitando dificuldades advindas do "desconhecimento"sobre a mesma.

Os instrutores estarão a sua disposição ao longo de todo curso. Qualquer dúvida deverá serenviada no fórum. Diariamente os monitores darão respostas e esclarecimentos.

2.7 Programa

O curso de Nagios oferecerá o seguinte conteúdo:

• Introdução e Breve História;

23

Page 25: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

• Iniciando;

• Operadores, Identificadores e Símbolos;

• Constantes;

• Entrada e Saída de Dados;

• Estruturas de Iteração e Desvios Condicionais;

• Funções;

• Vetores e Seqüência de Caracteres;

• Ponteiros e Memória Dinâmica;

• Estruturas de Dados;

• Programação Orientada a Objeto;

• Programação Orientada a Objeto - continuação;

• Finalizando POO;

• Templates, Namespaces;

• Exceptions, Type Casting, Diretivas;

• I/O com arquivos;

2.8 Avaliação

Toda a avaliação será feita on-line.Aspectos a serem considerados na avaliação:

• Iniciativa e autonomia no processo de aprendizagem e de produção de conhecimento;

• Capacidade de pesquisa e abordagem criativa na solução dos problemas apresentados.

Instrumentos de avaliação:

• Participação ativa nas atividades programadas.

• Avaliação ao final do curso.

• O participante fará várias avaliações referente ao conteúdo do curso. Para a aprovação eobtenção do certificado o participante deverá obter nota final maior ou igual a 6.0 de acordocom a fórmula abaixo:

• Nota Final = ((ML x 7) + (AF x 3)) / 10 = Média aritmética das lições

• AF = Avaliações

24

Page 26: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

2.9 Bibliografia

• http://www.dcc.unicamp.br/ cmrubira/aacesta/cpp/cpp15.html

• http://psantos.zi-yu.com/wiki.aspx?topic=PRE.CppTutorial

• http://pt.wikipedia.org/wiki/C

• http://www.cplusplus.com/doc/tutorial/

• http://www.lmpt.ufsc.br/ andre (André Duarte Bueno, UFSC-LPMT-NPC)

25

Page 27: Programacao cpp

Capítulo 3

Introdução e Breve História

3.1 Introdução ao C++

O C++ é uma linguagem de programação de alto nível(1) com facilidades para o uso em baixonível(2) (herdados do C), multiparadigma e de uso geral. Desde os anos 1990 é uma das lin-guagens comerciais mais populares, sendo bastante usada também na academia por seu grandedesempenho e base de utilizadores.

Durante sua fase inicial de desenvolvimento, a linguagem era chamada "novo C"ou ainda "Ccom classes". O termo "C++"é creditado a Rick Mascitti, e foi utilizado pela primeira vez em de-zembro de 1983. Ele é uma referência ao operador de incremento ++, significando um acréscimo(uma evolução) à linguagem C.

3.1.1 Breve História do C e do C++

A linguagem C foi desenvolvida por Denis Richard em 1972 e teve origem na linguagem B,desenvolvida por Ken Thompson, em 1970. C teve sua divulgação e sucesso graças à vendagemdo livro "The C Programmign Language"e ao fato de ser independente de hardware. Vale notarque C e o Sistema Operacional Unix foram desenvolvidos conjuntamente, o que faz que ambien-tes Unix, Linux e MacOS X e a linguagem C tenham uma interação forte.

Figura 3.1: Bjarne Stroustrup

26

Page 28: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Em 1980, Bjarne Stroustrup desenvolveu o C++ no Bell Labs como um adicional à linguagemC. Hoje em dia quase todas as grandes empresas que desenvolvem softwares usam C++. Mas apergunta principal é: "Devemos aprender primeiro o C e depois C++ ou ir direto ao C++? BjarneStroustrup afirmou em 1999: "estou firmemente convencido de que é melhor ir direto ao C++".

3.1.2 Algumas novidades...

A linguagem C++ consegue agrupar uma funcionalidade que envolve formulações como clas-ses, altamente abstratas, que permitem um trabalho de alto nível e formulações de baixo nível.Com isso é uma das melhores LPs (Linguagens de Programação) que existem. As principaisnovidades existentes no C++ em relação ao C são:

Uso de classes, funções, inline, conversão de tipo, verificação de argumentos de uma função,operadores para gerenciamento de memória, referências, constantes, sobrecarga de operador,sobrecarga de funções, polimorfismo, templates (gabaritos), tratamento de exceções e espaçosde nomes (namespace). Também podemos citar o aumento da produtividade, maior reaproveita-mento de código, maior qualidade geral do projeto, facilidade de extensão e manutenção. Maiorcompreensão geral pela equipe de desenvolvimento, já que com C++ um único programador éapto gerenciar uma quantidade maior do código.

Pode-se dizer que C++ foi a única linguagem entre tantas outras que obteve sucesso como umasucessora à linguagem C, inclusive servindo de inspiração para outras linguagens como Java, aIDL de CORBA e C#.

(1) Linguagem de programação de baixo nível, próximas a máquina, como Assembly.(2)Linguagem de programação de alto nível, no nível da especificação de algoritmos, como Pas-cal, Fortran, Java, C, C++.

OBS: ainda temos as Linguagem de programação de muito alto nível, no nível da especifica-ção declarativa, como SQL.

3.2 Características do C++

Algumas regras que o próprio Bjarne Stroustrup utilizou para desenvolver a linguagem são:

• C++ é desenvolvido para ser uma linguagem tipada (forte uso de tipos dinâmicos) estatica-mente e de proposta geral que é tão eficiente e portável quanto o C;

• C++ é desenvolvido para suportar múltiplos paradigmas de linguagem (Orientada a Objetos,Estruturada, Funcional, lógica, etc);

• C++ é desenvolvido para fornecer ao programador escolhas, mesmo que seja possível aoprogramador escolher a opção errada;

27

Page 29: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

• C++ é desenvolvido para ser o quanto mais compatível com C possível, fornecendo transi-ções simples para código C;

• C++ evita fornecer facilidades que são específicas a certas plataformas ou a certos gruposde desenvolvedores;

• C++ não exige overhead (tempo de processamento excessivo) para facilidades que não sãoutilizadas;

• C++ é desenvolvido para ser utilizado mesmo sem um ambiente de desenvolvimento sofis-ticado.

3.3 Alguns conceitos básicos

DebugerAjuda o programador a encontrar os erros de programação, famosos bugs.

ProfilerAjuda a identificar os pontos onde o programa está sendo lento, ou que consomem mais tempo;com isso pode-se melhorar a qualidade do programa e sua velocidade. Apenas rodamos o pro-grama dentro do profiler e analisamos os resultados de tempo de execução de cada método oufunção.

LinkerTransforma um ou mais arquivos *.o (no Unix/Linux) em um arquivo executável. Os arquivos queserão unidos são definidos em um arquivo de projeto ou em um arquivo makefile. No linux, depoisde linkado, um programa tem um arquivp ’a.out’. Os erros de ligação são detectados pelo linker.

CompiladorEncontra erros de sintaxe do programa e realiza a tradução do código em linguagem de máquina.Após o processo, o programa passa a ter um arquivo ’*.o’.

3.4 Ambientes de Desenvolvimento

Antes de começarmos a teoria propriamente dita, abaixo serão listados os principais am-bientes de desenvolvimento C++, sejam eles compiladores ou ambientes de desenvolvimentointegrado (IDE) que rodam em ambiente Linux:

28

Page 30: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

G++ Um componente do GCC, compilador padrão do Projecto GNU.Intel C++ Produz código otimizado para processadores Intel.C++ Builder Ferramenta da Borland que oferece versões antigas gratuitas

sem presença de IDE. Possui integração com Delphi.Comeau C++ Pode ser experimentado pela Internet.Eclipse Disponível para C++ através da extensão CDT.Code::Blocks Ambiente aberto e multi-plataforma, em sua versão para Windows utiliza

o compilador MinGW, apesar de também suportar outros compiladorescomo o Visual C++, Digital Mars, Borland C++ 5.5 e Open Watcom.

Não mostrarei métodos de instalação no curso pois, além de serem extremamente triviais, sãomuitos os compiladores existentes. Para dúvidas, entre em contato com os monitores no fórumde dúvidas.

3.5 Incompatibilidades

Considerar o C++ como um superconjunto, uma linguagem que implementa completamente oC e adiciona novas funcionalidades ao C é um erro. Grande parte do código C pode ser perfei-tamente compilado em C++, mas existem algumas diferenças sintáticas e semânticas entre elasque tornam alguns trechos de código C válidos em código C++ inválido, ou códigos que exibemcomportamentos diferentes em cada linguagem. A mais comum é que C permite conversão implí-cita entre o tipo void* para ponteiros para outros tipos, algo que o C++ não permite. Seria inválidoentão o seguinte código em C++:int *i = mallo (sizeof(int) * 5);

, a não ser que explicitemos a conversão:int *i = (int *) mallo (sizeof(int) * 5);Outro ponto é o fato do C++ adicionar novas palavras reservadas, como new e class, que

podem ser utilizadas como identificadores (por exemplo nomes de variáveis) em C, gerando in-compatibilidade.

29

Page 31: Programacao cpp

Capítulo 4

Iniciando

4.1 Layout

O desenvolvimento de um programa em c++ começa com a definição do arquivo de projeto.Em seguida são criados os arquivos de cabeçalho (*.h) e os arquivos de implementação (*.cpp).

• 1) O arquivo de projeto define quais arquivos fazem parte do programa além de definirem que seqüência devem ser compilados. Contém, então, uma lista com os nomes dodsarquivos de cabeçalho (*.h), de implementação (*.cpp) e a forma como os mesmos serãocompilados. A organização do programa separando o código em vários arquivos facilita amanutenção e possibilita um maior entendimento da estrutura dos programas. Além disso,o processo de compilação fica mais rápido;

• 2) Arquivos de cabeçalho armazenam a definição da classe, e têm a extensão *.h. ;

• 3) Arquivos de implementação armazenam as definições dos métodos das classes, e têm aextensão *.cpp. ;

• 4) É necessário um arquivo com a definição da função main, um aruqivo também *.cpp, queusa as classes definidas pelo programador.

Um exemplo de código (dividido em 3 arquivos) onde estão presentes uma breve documen-tação da aplicação, da classe implementada e uma descrição dos atributos e métodos. Não énecessário o entendimento do funcionamento, apenas atente à divisão dos arquivos e no formatousado://-----------------------------TApli a ao.h///De lara uma lasse minimalista lass TApli a ao{publi :///Método de exe ução da apli açãovoid Run();};//-----------------------------TApli a ao. pp#in lude <iostream>

30

Page 32: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF//Define método da lasse.#in lude "TApli a ao.h"/**O método Run es reve uma msg na tela*/void Tapli ação::Run(){//ini io do método//std:: out es reve na tela// out= outstd:: out << "Bem_vindo_ao_C++!",,std::end1;}4.2 Conceitos Básicos

Alguns conceitos relacionados à sintaxe e semântica da linguagem:

Atribuição : Atribuir um valor a uma determinada posição de memória, abstratamente num objetoou variável. Para atribuições usa-se o símbolo de igual (=).Exemplo:x = 7;b = 3;b = b+1;

Declaração : Declara que existe tal objeto, mas não o cria.Exemplo:int x; lass tal;float fun ao();stru t s;extern onst int a;

Inicialização : As variáveis, no ato de sua declaração podem ser inicializadas com algum valorque terão até o fim do programa ou até que este valor seja alterado.Exemplo:int x = 10; har = 'a';int f = 0;

Escopo : Define aonde um objeto é visível. Pode ser objeto local, de classe , de função, glo-bal, ou de arquivo.

31

Page 33: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#in lude <iostream>using namespa e std;int integer; har ;unsigned int n; // , n são variáveis globaisint main (){unsigned short m;float x, y; //x,y,m são variaveis lo ais...}Especificadores : São palavras reservadas da linguagem, usadas para atribuir determinadas

propriedades ao tipos ou definir o tipo do objeto.Exemplo:int x;intline void f(){...}typedef float ra ional;//são identifi adores int, intline, typedef.

Diretrizes pré-processamento : Informações no início do programa que são passadas aocompilador. Iniciam-se com o símbolo #.

Lvalue : é uma expressão que se refere a um objeto ou função. Pode aparecer à esquerda dosinal de igual (=). Objetos especificados como const não são lvalues.

4.3 Símbolos

Existem alguns símbolos que podemos usar ao programar em C++: Identificadores, opera-dores, palavras-chave, literais e separadores.

Identificadores : Sequência de letras definidas pelo programador. Podem ser nome dos ob-jetos, nome dos atributos, ou nome dos métodos.Exemplo:int x,y,x; //x, y e z são os identifi adores.

Operadores : Operadores são símbolos cujo uso já vem definido na linguagem. São eles:! % ^& * () - + = {} [℄ \ ; ' : " < > ? , . /32

Page 34: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Mais na frente explicarei melhor os operadores.

Palavras-chave : São palavras de uso interno da linguagem, já contêm algum significado es-pecífico para o processo de compilação. Não podem ser usadas, portanto, para dar nome avariáveis.Exemplo: lass, string, else, then, main...

Literais : Tipos previamente definidos na linguagem para serem usados representando obje-tos de uso corrente. Exemplo:int x = 3; //O numero é um literal har = 'k'; //a letra 'a'é um literalfloat y = 8.7; //onúmero 5.3 é um literal har* nome = "julio" //julio é um literal4.4 Os Operadores

AtribuiçãoUsados para atribuir um valor para a variável.

Operadores aritméticosOperadores que correspondem às suas respectivas operações matemáticas. São elas:

+ adição- subtração* multiplicação/ divisão

, ressaltando que o módulo é o resto da divisão de um valor pelo outro.

Combinados

Usados quando queremos modificar o valor da variável executando uma operação no valor atual-mente armazenadonela. São eles:+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=.

Exemplos:x += 3; //x=x+3x -= 3; //x=x-3x = 3; //x=x*3x /= 3; //x=x/3x %= 3; //x=x%333

Page 35: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Incremento e decremento

Usados para incrementar ou decrementar em uma unidade o valor armazenado na variável. São,portanto, equivalentes:x += 1;x++;x = x + 1;

oux -= 1;x--;x = x ? 1;OBS: Note a diferença existente entre os dois exemplos seguintes, onde no primeiro é usado

como prefixo e no segundo é usado como sufixo:

1 2A=++B; A=B++;//A armazena 4, B armazena 4 //A armazena 3, B armazena 4

Relacionais

Usados para avaliar uma comparação entre dois valores. Retornam um booleano true ou false.São eles:

== É igual a...!= Não é igual a...> É maior que...< É menor que...>= É maior ou igual a...<= É menor ou igual a...

Exemplos:(7 == 5) // retorna false(5 > 4) // retorna true(3 != 2) // retorna true(6 >= 6) // retorna true(5 < 5) // retorna false.Lógicos

Usados para expressar negação, conjunção ou disjunção.Exemplos:!(3 == 3) // retorna falso pois 3 == 3 é verdade.!(10 <= 2) // retorna true pois 6 <= 4 retornaria falso.

34

Page 36: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFa=true;b=falsea && b //retorna falsoa=true;b=false;a || b //retorna trueCondicional (?) e vírgula (,)

O condicional ’?’ é usado para avaliar uma expressão, retornando um valor (resultado1) se aexpressão for verdadeira e um outro valor (resultado2) se ela for falsa. Neste formato: ondição ? resultado1 : resultado2

Exemplo:7==5 ? 4 : 3 // retorna 3, já que 7 não é igual a 5.7==5+2 ? 4 : 3 // returns 4, sin e 7 is equal to 5+2.Já a vírgula é usada para separar duas ou mais expressões que são incluídas onde apenas

uma expressão é esperada.a = (b=4, b+6);Primeiramente b recebe o valor 4, em seguida atribuído o valor b+6 para a variável a. No final,

a tem o valor 10 e b tem o valor 4.

BináriosModificam variáveis considerando os padrões binários que representam os valores que eles ar-mazenam.São eles:

operador equivalente em assembly descrição& AND Binário AND.| OR Binário Inclusivo OR.^ XOR Binário exclusivo OR.~ NOT complemento unário (inversão de bit).« SHL Desloca para a esquerda (shift left).» SHR Desloca para a direita (shift right).

4.5 Precedência de Operadores

Ao escrevermos expressões complexas, às vezes fica difícil distinguir qual operador vem pri-meiro na hierarquia. Há uma ordem de prioridade para cada operador que, da maior para amenor, é esta:

35

Page 37: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Nível Operador Agrupamento1 :: esquerda para a direita.2 () [] . -> ++ – esquerda para a direita.

dynamic_cast static_cast reinterpret_castconst_cast typeid

3 ++ – ! sizeof new delete direita para a esquerda.* &+ -

4 (type) direita para a esquerda.5 * ->* esquerda para a direita.6 * / % esquerda para a direita.7 + - esquerda para a direita.8 « » esquerda para a direita.9 < > <= >= esquerda para a direita.10 == != esquerda para a direita.11 & esquerda para a direita.12 ^ esquerda para a direita.13 | esquerda para a direita.14 && esquerda para a direita.15 || esquerda para a direita.16 ?: direita para a esquerda.17 = *= /= %= += -= »= «= &= ^= |= direita para a esquerda.18 , esquerda para a direita.

4.6 Outros Operadores

Existem certos operadores que são usados para converter dados de um dado tipo para outro.A maneira mais simples de fazer isso em C++, herdada do C, é a seguinte:int i;float f = 3.14;i = (int) f;

Este código converte um float (3.14) para um inteiro (3). Outra maneira é:i = int (f);O último operador a vermos é o sizeof(). Ele aceita 1 parâmetro, que pode ser tanto um tipo

ou uma variável e retorna o tamanho em bytes daquele tipo ou objeto.a = sizeof ( har);Com esse comando, atribuímos o valos 1 a a pois char é um tipo constituído de um byte.

36

Page 38: Programacao cpp

Capítulo 5

Constantes

5.1 Tipos de Dados Fundamentais de C++

Ao programar, o valor das variáveis são armazenados na memória do computador, mas estetem que saber que tipo de dados queremos salvar, já que armazenar um número simples não iráocupar a mesma área de memória que armazenar uma letra ou um número maior, por exemplo.

Sabemos que a memória é organizada em bytes. Um byte é a quantia mínima que podemosgerenciar em C++. Um byte pode armazenar uma quantidade relativamente pequena de dados:um caracter simples ou um inteiro pequeno (geralmente um inteiro entre 0 e 255). Além disso, ocomputador pode manipular tipos de dados mais complexos que aparecem do agrupamento devários bytes, como números grandes ou números não-inteiros.

São tipos fundamentais em C++ (incluídos o intervalo de valores que cada um pode representar):

37

Page 39: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Nome DescriçãoTamanhoIntervalo de valores

char usualmente caracteres1 bytec/ sinal: -128 a 127sem sinal: 0 a 255.

short inteiros curtos2 bytec/ sinal: -32768 a 32767sem sinal: 0 a 65535.

int inteiros4 bytec/ sinal: -2147483648 a 2147483647sem sinal: 0 a 4294967295.

long inteiros longos4 bytec/ sinal: -2147483648 a 2147483647sem sinal: 0 a 4294967295.

bool valores booleanos true ou false1 bytetrue ou false.

float números em ponto flutuante.4 byte3.4e +/- 38 (7 dígitos).

double precisão double de números em ponto flutuante.8 byte1.7e +/- 308 (15 diítos).

long double precisão long de números em ponto flutuante.8 byte1.7e +/- 308 (15 dígitos).

wchar_t caracter wide2 ou 4 byte1 caracter wide.

Os valores das colunas tamanho e intervalo dependem do sistema para o qual o programa écompilado. Os valores mostrados são aqueles encontrados na maioria dos sistemas 32-bit. Paraoutros sistemas, entretanto, a especificação genérica é que int tem o tamanho natural sugeridopela arquitetura do sistema (uma "palavra", 4 bytes ou 8 bytes por exemplo) e os outros tiposinteiros (char, short, int, long) devem, cada um, ser no mínimo do tamanho do que o precede,com char sempre sendo 1 byte de tamanho. O mesmo se aplica aos tipos de ponto flutuantes(float, double, long double), onde cada um deve prover no mínimo a mesma precisão do que oprecede.

38

Page 40: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

5.2 Constantes

Constantes são expressões com um valor fixo.

5.3 Literais

Constantes usadas para expressar valores particulares num programa. Podem ser divididasem Números Inteiros, Números em Ponto-Flutuante, Caracteres, Strings, Valores Booleanos.

Inteiros:107653-789São constantes numéricas que identificam valores decimais. Em C++, além dos decimais,

podemos usar literais de números octais (base 8) e hexadecimais (base 16), da seguinte maneira:

• -Se quisermos expressar um número octal, nós o precedemos com um 0 (zero).

• -Se quisermos expressar um número hexadecimal, nós o precedemos com um 0x (zero-xis).

Exemplo:75 //de imal 750113 //de imal 75 em o tal0x4b //de imal 75 em hexade imalPor padrão, literais inteiros têm um tipo pré-definido: int.

Ponto-FlutuanteExpressam números com decimais e/ou expoentes.Exemplo:3.14159 // 3.14159 6.02e23 // 6.02 x 10^23 1.6e-19 // 1.6 x 10^-19 3.0 // 3.0

O tipo padrão para ponto-flutuante é double.

39

Page 41: Programacao cpp

Capítulo 6

I/O com Arquivos

6.1 Entrada/Saída de Dados

A partir desta parte do curso começaremos a interagir com o usuário por meio dos padrõesda biblioteca de entrada/saída. C++ usa uma abstração chamada stream para executar opera-ções de entrada e saída em aparatos como tela ou teclado. Uma Stream é um objeto de onde oprograma pode inserir ou extrair caracteres.

Por padrão, a saída de um programa é a tela e o objeto stream definido para acessá-la é "cout".Cout é usada em conjunto com o operador de inserção: «.Exemplo: out << "Olá Mundo"; // Olá Mundo é impresso na tela; out << x; // imprime na tela o valor de x; out << "x"; // imprime a string/ ara ter x na tela; out << "Olá Mundo, " << "isto é" << "uma frase"; //imprime "Olá Mundo, isto é uma frase". out << "Olá Mundo, este é o " << num << " exemplo da " << numli ao << " lição";

O operador « insere o dado que o segue na stream que o precede. Nos casos anteriores, xe a string "Olá Mundo"são inseridas em ’cout’, por exemplo. Deve-se ressaltar que o ’cout’ nãoinsere uma quebra de linha automática, devendo esta ser explicitada. out << "Isto é uma frase"; out << " sem quebra de linha automáti a.";

O exemplo anterior será mostrado desta maneira:Isto é uma frase sem quebra de linha automáti a.Já neste caso: out << "Isto é uma frase\n"; out << " om quebra de\n"; out << "linha automáti a.";a frase será impressa desta maneira:

40

Page 42: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFIsto é uma frase om quebra delinha automáti a.Para imprimirmos a frase com a quebra de linha também podemos usar o manipulador endl

(endline), da seguinte maneira: out << "Frase om" <<endl; out << "quebra de linha" << endl;que mostrará na tela:Frase omquebra de linhaO padrão de entrada de dados é, usualmente, o teclado. Para manipular a entrada padrão de

dados em C++ usamos o operador de extração » na stream cin. Este operador deve ser seguidopela variável que irá armazenar os dados que serão extraídos da stream. Desta maneira:int numero; in >> numero;

A primeira linha declara uma variável numero do tipo int e a segunda linha espera que ousuário digite algo, alguma entrada de dados do cin (o teclado) para armazenar na variável inteira.É interessante notar que o cin só pode processar a entrada do teclado uma vez que a teclade retorno tiver sido pressionada. Com isso, mesmo se fizermos a requisição de um caractersimples, a extração do cin não vai processar a entrada até que o usuário pressione a tecla deretorno depois que o caracter for introduzido. Exemplo:// exemplo de entrada e saída...#in lude <iostream>using namespa e std;int main (){int i; out << "Insira um valor inteiro: "; in >> x; out << "O valor inserido é " << x; out << " e seu quadrado é " << x*x << ".\n";return 0;}

resultado:Insira um valor inteiro: 10O valor inserido é 10 e seu quadrado é 100.Podemos usar cin para pedir ao usuário que insira mais de um dado: São equivalentes os

dois exemplos:

41

Page 43: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF in >> x >> y;e in >> x; in >> y;OBS: se um valor inteiro é requisitado no código e o usuário insere um nome, por exemplo,

pode resultar em mal funcionamento do programa. Ao usar entrada de dados com as extraçõescin, temos que confiar que o usuário irá inserir os dados corretamente, sem caracteres ou algosimilar quando é preciso. Mais à frente, quando formos ver a classe stringstream, veremos umapossível solução para esses tipos de erros.

Podemos ainda usar o cin para extrair strings da mesma maneira que fizemos com os outrostipos de váriaveis usando o mesmo operador ». in >> frase

Contudo, essa extração com o cin para de ler dados do usuário assim que encontra um espaçoem branco. Sendo desta maneira, só podemos pegar uma palavra do usuário por extração, e nãouma frase inteira. Para pegarmos as frases inteiras podemos usar a função getline, que é maisrecomendável. Teremos, por exemplo, como resultado se o nome inserido pelo usuário for "Fulanode Tal":#in lude <iostream>#in lude <string>using namespa e std;int main (){string nome; out << "Por favor, insira seu nome ompleto: ";getline ( in, nome); out << "Olá, " << nome << ".\n";return 0;}

resultado:Por favor, insira seu nome ompleto:Olá Fulano de Tal.6.2 Stringstream

O cabeçalho padrão stringstream define a classe stringstream que permite que um objeto ba-seado numa string seja tratado como uma stream. Assim, podemos fazer operações de extraçãoou inserção de/para strings, especialmente úteis para converter strings para valores numéricos evice-versa. Se quisermos extrair um inteiro de uma strings podemos fazer:

42

Page 44: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFstring snum ("1997");int numero;stringstream(snum) >> numero;Após isto, a variável numero deve conter o numérico 1997.// stringstreams#in lude <iostream>#in lude <string>#in lude <sstream>using namespa e std;int main (){string re ebe;int anonum=0;int mesnum=0;int dianum=0; out << "Entre om o ano do seu nas imento: ";getline ( in,re ebe);stringstream(re ebe) >> anonum; out << "Entre om o mês do seu nas imento: ";getline ( in,re ebe);stringstream(re ebe) >> mesnum; out << "Entre om o dia do seu nas imento: ";getline ( in,re ebe);stringstream(re ebe) >> dianum; out << "Data de nas imento: " << dianum << mesnum << anonum <<endl;return 0;}que resulta em:Entre om o ano do seu nas imento: 1982Entre om o mês do seu nas imento: 01Entre om o dia do seu nas imento: 15Data de nas imento: 15 01 1982

43

Page 45: Programacao cpp

Capítulo 7

Estruturas de Iteração e DesviosCondicionais

7.1 Estruturas de Iteração

A maioria das linguagens de programação têm certas estruturas que servem para desviar ocontrole das instruções, repetir certos trechos de códigos, tomar cedisões, etc. As principais es-truturas de controle em C++ serão mostradas nesta parte do curso.

If e Else

A palavra-chave IF é usada quando queremos executar certo trecho do código somente se al-guma condição(ões) for(em) satisfeita(s).Exemplo:if (x == 123) out << "O valor de x é 123";

Aqui, o programa imprime a string "O valor de x é 123"somente se o valor de x for igual (=)a 123. Para inserir mais de uma instrução quando a condição é verdadeira, basta usarmos aslinhas de código entre chaves , assim:if (x == 123){ out << "O valor de x é 123"; out << "O valor de x não é 100";}

Se a condição tiver sido falsa e quisermos executar algum trecho de código neste caso, usa-mos o Else:if (x > 123) out << "O valor de x é superior a 123";else (x < 123) out << "O valor de x é inferior a 123";else out << "O valor de x é zero";

44

Page 46: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Aqui, se o valor de x for superior a 123, ele imprime: O valor de x é superior a 123 já seo valor de x for inferior a 123, ele imprime: O valor de x é inferior a 123 ou se for 0, eleimprime: O valor de x é zero.7.1.1 Estruturas de Iteração

Os Loops têm como propósito repetir um trecho de código um certo número de vezes en-quanto/até que a condição seja satisfeita.

While

Uma destas estruturas é o loop while. Ele repete certo trecho enquanto a condição não forsatisfeita.Exemplo:#in lude <iostream>using namespa e std;int main (){int n; out << "Insira um valor de iní io > "; in >> n;while (n>0) { out << n << ", ";--n;} out << "BOOM!\n";return 0;}

O que resulta em:Insira um valor de iní io > 77, 6, 5, 4, 3, 2, 1, BOOM!O programa anterior faz o que está descrito nos seguintes passos:

• 1- Quando é iniciado, pede ao usuário que insira um valor de entrada e ele acaba atribuindoum valor para n.

• 2- Quando o loop inicia, se o valor inserido atende à condição n>0: verdadeira - a sentençaé executada e vai para o passo 3 falsa - ignora a sentença e vai para o passo 5

• 3- Imprime o valor de n na tela e decrementa o valor de n em 1 unidade.

• 4- Fim do bloco e o programa retorna à parte descrita no passo 2.

• 5- Continua o programa logo após o bloco. Imprime BOOM e finaliza o programa.

45

Page 47: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

OBS: ao criarmos a estrutura while, devemos levar em conta que ela deve terminar a algumponto. Para isso, devemos fornecer algum método para forçar a condição a se tornar falsa emalgum lugar. Caso contrário, o while se tornará um "loop infinito".

Do-While

Loop que funciona de maneira praticamente igual ao loop while, com a diferença que, neste,a condição do do-while será avaliada após a execução do bloco, ao invés de antes. Com isto,mesmo que a condição não seja atendida, o programa vai garantir que o código dentro do blocoseja executado ao menos 1 vez. Por exemplo:#in lude <iostream>using namespa e std;int main (){unsigned long n;do { out << "Insira um valor (Insira 0 para sair): "; in >> n; out << "Vo ê inseriu: " << n << "\n";} while (n != 0);return 0;}

que retorna na tela:Insira um valor (Insira 0 para sair): 132Vo ê inseriu: 123Insira um valor (Insira 0 para sair): 321Vo ê inseriu: 321Insira um valor (Insira 0 para sair): 0Vo ê inseriu: 0No programa anterior, se não inserirmos o valor 0, o programa pedirá um novo número para

sempre.

For

A função do loop for é, além de repetir certo trecho de código enquanto a condição permaneceverdadeira, como o while, fornecer uma inicialização e incremento de alguma variável específica(um contador) usada no trecho de código no seu escopo*.

Sua sintaxe éfor (ini ialização; ondição; in remento){}Exemplo:

46

Page 48: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#in lude <iostream>using namespa e std;int main (){for (int n=10; n>0; n--) { out << n << ", ";} out << "BOOM!\n";return 0;}que mostra na tela:10, 9, 8, 7, 6, 5, 4, 3, 2, 1, BOOM!OBS: ponto-e-vírgulas são obrigatórios, apesar do incremento e inicialização serem opcionais.

Com isso, se não forem usados teríamos, por exemplo:for (;n>10;){}já as vírgulas podem ser usadas para especificar mais de uma expressão em um dos campos,

assim:for ( n=0, i=100 ; n!=i ; n++, i-- ){}7.1.2 Desvios

Break

Com o break, podemos deixar um loop mesmo que a condição não seja satisfeita. Útil em lo-ops infinitos, ou para forçar um final antes do fim normal do bloco.Exemplo:#in lude <iostream>using namespa e std;int main (){int x;for (x=10; x>0; x--){ out << x << ", ";if (x==3){ out << "Contagem finalizada!";break;}}return 0;}

47

Page 49: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

que retorna:10, 9, 8, 7, 6, 5, 4, 3, Contagem finalizada!Continue

Com o continue, o programa pula o resto do loop na iteração atual como se o fi do bloco ti-vesse sido atingido e pula ao começo da iteração seguinte.Exemplo:#in lude <iostream>using namespa e std;int main (){for (int x=10; x>0; x--) {if (x==5) ontinue; out << x << ", ";} out << "final!\n";return 0;}

que mostra na tela:10, 9, 8, 7, 6, 4, 3, 2, 1, final!Goto

O goto permite desviarmos para um ponto qualquer no programa. Por este motivo, deve serusado com cautela, já que sua execução causa um desvio incondicional que ignora qualquer tipode limite de escopo. O destino é definido com um label, que é usado como um argumento para ogoto. Este label é feito de um identificador válido seguido de dois-pontos (sorriso.Exemplo:#in lude <iostream>using namespa e std;int main (){int x=10;loop: out << x << ", ";x--;if (x>0) goto loop; out << "final!\n";return 0;}

que mostra na tela:

48

Page 50: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF10, 9, 8, 7, 6, 5, 4, 3, 2, 1, final!Exit

O exit é uma função definida na biblioteca cstdlib cuja função é terminar o programa atual comum código específico. Seu protótipo é:void exit (int exit ode);

O exitcode é usado por alguns sistemas operacionais e pode ser usado por programas que ochamem. por convenção, um exitcode 0 significa que o programa terminou normalmente. Outrosvalores indicam que algum erro ou resultados inesperados aconteceram.

Switch

O switch é uma estrutura que checa várias possibilidades de valores constantes para uma ex-pressão. Acompanhe o formato padrão do switch junto à sua explicação, a seguir:swit h (expressão){ ase onstante_1:{blo o_de_ ódigo_1;}break; ase onstante_2:{blo o_de_ ódigo_2;}break;...default:{blo o_de_ ódigo_padrao;}}

Primeiramente ele avalia a expressão e verifica se o resultado dela é equivalente à cons-tante_1. Se for, executa o bloco_de_código_1 até que encontre um break. Ao encontrá-lo, oprograma desvia ao fim do switch.

Se o valor da expressão não for igual à constante_1, o switch checa a constante_2, seguindo omesmo procedimento anterior. Note que os três-pontos mostram que podem ser usadas quantasconstantes e blocos de códigos sejam necessáris. Se por ventura nenhuma dessas constantesfor igual ao valor da expressão, o switch executará o bloco_de_código_padrao, do default. Poreste motivo, um switch exige sempre que haja um label default.

OBS:

• 1) é importante ressaltar que se o break entre os labels e blocos de código não foremusados, o switch poderá entrar na primeira clausula, por exemplo, e continuar executandoas outras sem interrução do loop. Esta é a importância do break dentro do switch. Apesardisso, como o default deve ser o último label a ser inserido, ele não exige o desvio break.

49

Page 51: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

• 2) O switch só pode ser usado para comparar expressões com constantes. Assim, nãopodemos colocar variáveis como labels.

Ambos os seguintes trechos de código têm o mesmo funcionamento:swit h (x) { ase 1: out << "x é 1";break; ase 2: out << "x é 2";break;default: out << "Valor des onhe ido de x";}Funciona da mesma maneira que:if (x == 1) { out << "x é 1";}else if (x == 2) { out << "x é 2";}else { out << "Valor des onhe ido de x";}Veja um outro exemplo de switch:swit h (x*2){ ase 2:{ out << "O valor da expressão é 2.";}break; ase 4:{ out << "O valor da expressão é 4.";}break; ase 6:{ out << "O valor da expressão é 6.";}break;default:{

50

Page 52: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF out << "O valor da expressão é des onhe ido";}}que, no caso em que x é 3 resulta:O valor da expressão é 6.Funções Uma função é um bloco de instruções que é executado apenas quando é chamado

em algum ponto do programa. Ao usar funções, podemos estruturar os programas de uma ma-neira mais modular, acessando todo o potencial que a programação estruturada em C++ podeoferecer.

O formato padrão de funções é:Tipo\_dado nome\_fun ao (parametro1, parametro2, ...){blo o\_de\_ ódigo\_da\_fun ao}O Tipo é o tipo (int, float, etc...) do dado que será retornado pela função ao lugar que a

chamou. O nome da função é o nome que será usado para caracterizar a função e chamá-laquando for necessário. Os parâmetros podem ser quantos forem necessários. São tipos dedados seguidos pelo identificador, como uma declaração de variável comum (int x, por exemplo),e que agem na função como variáveis locais comuns. Eles permitem passar argumentos para afunção quando é chamada. Exemplo:#in lude <iostream>using namespa e std;int soma(int a, int b){int x;x=a+b;return (x);}int main (){int y;y = soma(200,100); out << "O resultado é " << y;return 0;}

Que mostra na tela:O resultado é 300.Um programa em C++ sempre inicia sua execução no método main. Logo, neste exemplo,

começamos declarando y, e dizendo que seu valor é igual ao valor que a função soma com osparâmetros 200 e 100 retornará. Ao chamar a função soma, o controle é desviado para estafunção, que soma os dois numeros recebidos como parâmetros e retornam o resultado para ondeela foi chamada. o valor de y resultante na função main então se altera para 300 e é impresso natela com o cout.

51

Page 53: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

7.2 Escopo de Variáveis

O escopo de variáveis (ou local do programa onde as variáveis são válidas) declaradas numafunção é a própria função e por isso, elas não podem ser utilizadas fora delas. No exemplo an-terior, o escopo de x é a função soma. Se tentássemos usá-la fora da função, teríamos um erroindicando que a variável não pode ser reconhecida pelo compilador. Da mesma maneira, z nãopoderia ser utilizada na função soma.

Resumidamente, o escopo das variáveis segue o seguinte:

Variávels LocaisSeu escopo é limitado ao mesmo nível de bloco em que são declaradas.

Variáveis GlobaisVariáveis que são visíveis em qualquer ponto do código, dentro e fora de todas as funções. De-vem, para isso, ser declaradas fora das funções diretamente no corpo do programa.Exemplos:#in lude <iostream>using namespa e std;int subtra ao (int a, int b){int res;res=a-b;return (res);}int main (){int x=5, y=3, z;z = subtra ao(7,2); out << "O primeiro resultado é " << z << '\n'; out << "O segundo resultado é " << subtra ao(7,2) << '\n'; out << "O ter eiro resultado é " << subtra ao(x,y) << '\n';z= 4 + subtra ao(x,y); out << "O quarto resultado é " << z << '\n';return 0;}

,o que mostra na tela:O primeiro resultado é 5O segundo resultado é 5O ter eiro resultado é 2O quarto resultado é 652

Page 54: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

7.3 Funções sem tipo

Se verificarmos o formato geral de funções, verificamos que elas se iniciam com um tipo, queé o tipo da função por si mesma, o tipo do valor que ela retorna ao ponto que a chamou. Masdevemos saber que podemos não querer retornar valor algum. Imagine que somente queremosque uma função retorne algo na tela. Não queremos, então, que ela retorne valor algum e usamoso void para demonstrar isto ao compilador.Exemplo de uso do void:#in lude <iostream>using namespa e std;void mensagem(){ out << "Mensagem à toa!";}int main (){mensagem();return 0;}

, que retorna na tela:Mensagem à toa!OBS: 1) O void pode ainda ser utilizado para explicitar que não queremos que a função receba

parâmetros quando é chamada. A função anterior poderia ser declarada assim:void mensagem (void){ out << "Mensagem à toa!";}2) Mesmo que a função não contenha parâmetros, é imprescindível o uso dos parênteses na

sua declaração:void mensagem (){ out << "blablabla";}Parâmetros passados por Valor e por Referência

Argumentos passados por valor significa que, ao serem passados para a função, são "cópias"deseus valores, e não as variáveis propriamente ditas. Na prática, o que acontece é que são pas-sados para a função apenas os VALORES das variáveis. Com isso, não importa se estes valoresforem alterados ao longo da função, as variáveis originais continuarão tendo o mesmo valor foradela.Parte do Exemplo anterior:

53

Page 55: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFint x=3, y=4;int z;z= adi ao(x,y);Aqui, quando a função é chamada, o valor de a e b se tornam 3 e 4 respectivamente, mas

qualquer modificação a a ou b dentro da função não alterará o valor de x e y fora dela, já que nãoforam passadas à função e sim apenas seus valores (ou cópias deles).

Já no caso dos argumentos passados por referência a função não recebe apenas um valor, massim o ENDEREÇO de uma variável global. Portanto, qualquer modificação que for realizada noconteúdo deste parâmetro afetará também a variável global que está associada a ele. Durante aexecução do subprograma, ou função, os parâmetros passados por referência são análogos àsvariáveis globais.Exemplo:#in lude <iostream>using namespa e std;void dobro(int& a, int& b, int& ){a*=2;b*=2; *=2;}int main (){int x=1, y=3, z=7;dobro(x, y, z); out << "x=" << x << ", y=" << y << ", z=" << z;return 0;}

,o que retorna na tela:x=2, y=6, z=14Note que na declaração de cada parâmetro da função é usado o símbolo &. Ele é quem

especifica que os parâmetros serão passados por referência. Perceba também que depois de oprograma ter chamado a função, os parâmetros x, y e z têm seus valores alterados, situação estaque foi criada dentro da função por terem sido passados como por referência.

Existe um exemplo interessante que mostra que, ao passarmos os valores por referência, per-mitimos que a função retorne mais de um valor. neste caso o valor original (passado por valor), ovalor anterior a ele e o valor posterior a ele. Veja:#in lude <iostream>using namespa e std;

54

Page 56: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFvoid ant_post(int x, int& ant, int& post){ant = x-1;post = x+1;}int main (){int x=100, y, z;ant_post(x, y, z); out << "Valor Anterior=" << y << ", Valor Posterior=" << z;return 0;}que, como o valor de x é 100, retorna na tela:Valor Anterior=99, Valor Posterior=101

7.4 Valores Padrões nos Parâmetros

Ao declararmos uma função podemos especificar um valor padrão para cada parâmetro. Estevalor será usado se o argumento correspondente for deixado em branco na hora de chamar afunção. Para isto, simplesmente usamos o operador de atribuição e um valor para os argumentosna declaração da função. Se um valor para aquele parâmetro não for passado quando a funçãoé chamada, o valor padrão é usado. Contudo, se um valor para o parâmetro for especificado nachamada da função, este valor padrão é ignorado e o valor passado à função é usado.Exemplo:#in lude <iostream>using namespa e std;int divisao(int a, int b=2){int x;x=a/b;return (x);}int main (){ out << divisao(12); out << endl; out << divisao(20,4);return 0;}

que resulta em:

55

Page 57: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF65No caso anterior, o valor padrão b=2 só é utilizado no caso de divisao(12), pois não existe um

segundo argumento especificado.

Em C++, podemos usar mesmo nome para mais de uma função desde que tenham um númerode parâmetros diferentes ou tipos diferentes nos parâmetros.Exemplo:#in lude <iostream>using namespa e std;int al ular(int a, int b){return (a*b);}float al ular(float a, float b){return (a/b);}int main (){int x=5,y=2;float n=5.0,m=2.0; out << al ular(x,y); out << "\n"; out << al ular(n,m); out << "\n";return 0;}

que retorna como resultado na tela:102.5Neste caso, declaramos 2 funções com o mesmo nome (calcular) mas com tipos diferentes

(int e float).

7.5 Especificador Inline

Usado para dizer ao compilador que a substituição inline deve ser usada, ao invés do meca-nismo de chamada da função usual. Não muda o comportamento da função, mas é usado parasugerir ao compilador que o código gerado pelo corpo da função seja inserido em cada ponto dechamada da função, ao invés de ser inserido apenas uma vez e ser feita uma chamada normal a

56

Page 58: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

ela, o que geralmente envolve um tempo de execução adicional.

Seu formato:inline tipo nome_da_fun ao ( argumentos ... ){ blo o_de_instru oes }A única diferença é o uso do especificador inline no início da DECLARAÇÃO da função, não

sendo necessário nenhuma mudança na chamada da função. A maioria dos compiladores jáotimiza o código incluíndo funções inline quando é mais conveniente. O especificador só indicaque para determinada função o inline é preferido.

7.6 Recursividade

É a propriedade que as funções têm de chamarem a si mesmas. Suas utilidades são inúme-ras, como calcular fatoriais de números, ordenações, etc.Exemplo

Como o fatorial de um número é calculado usando:n! = n * (n-1) * (n-2) * (n-3) ... * 1em um programa teríamos:#in lude <iostream>using namespa e std;long fatorial (long x){if (x > 1)return (x * fatorial (x-1));elsereturn (1);}int main (){long num; out << "Insira um valor: "; in >> num; out << num << "! = " << fatorial (num);return 0;}que mostra na tela:Insira um valor: 1010! = 3628800

57

Page 59: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Percebemos que no código anterior a função chama a si mesma, mas apenas se o valorpassado como argumento for maior que 1. Caso contrário, a função executa um loop infinitorecursivo em que, assim que atingir o valor 0, continuaria multiplicando por todos os númerosnegativos (o que provavelmente geraria um erro de overflow na execução). Neste exemplo, portermos usado long, os resultados não seriam válidos para valores muito maiores que 10! ou 15!,dependendo do sistema em que forem compilados.

7.7 Declarações de Funções

Até aqui, definimos todas as funções antes da primeira aparição de chamadas a elas nocódigo. Acontece que se fizermos o teste de inverter o main e declararmos as funções apósele, teríamos erros de compilação, já que elas devem já ter sido declaradas para poderem serchamadas no main. No entanto, existe uma maneira de evitar termos que escrever o códigointeiro da função antes de chamá-la. Basta declararmos sua existência, ao invés da definiçãocompleta. Esta declaração tem a forma:tipo nome_da_fun ao (tipo argumento1, tipo argumento2, ...);

que é idêntica à definição de uma função excluíndo o corpo dela. Apesar de deixar o có-digo mais legível os nomes dos parâmetros não são obrigatórios. As seguintes declarações dosprotótipos de uma função são válidas:int fun ao1 (int a, int b);int fun ao1 (int, int);

Exemplo:#in lude <iostream>using namespa e std;void impar(int x);void par(int x);int main (){int i;do { out << "Diga um valor (digite 0 para sair): "; in >> i;impar(i);} while (i!=0);return 0;}void impar(int x){if ((x%2)!=0) out << "Número é ímpar.\n";else par(x);58

Page 60: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF}void par(int x){if ((x%2)==0) out << "Número é par.\n";else impar(x);}o que mostra na tela:Diga um valor (digite 0 para sair):3Número é ímpar.Diga um valor (digite 0 para sair):1000Número é par.Diga um valor (digite 0 para sair):15Número é ímpar.Diga um valor (digite 0 para sair):0Número é par.Percebemos neste exemplo que as funções par e impar só são definidas com seu corpo

inteiro após o método main, mas foram declaradas inicialmente com seus protótipos. Esta práticamostrou-se eficiente para a limpeza do código, já que isso acaba facilitando a localização dasfunções existentes no programa.

59

Page 61: Programacao cpp

Capítulo 8

Vetores e Seqüência de Caracteres

8.1 Vetores

Um vetor ou array é uma série de elementos do mesmo tipo colocados em seqüencia emlocais de memória que podem ser acessados ou referenciados individualmente usando índices.Podemos abstrair os vetores pensando neles como se fossem dessa forma:

Figura 8.1: Exemplo de Vetor

Significa que, por exemplo, podemos armazenar 6 valores do tipo int em um vetor sem ter quedeclarar 6 diferentes variáveis, cada uma com um identificador. Para fazer isso, criamos um vetorcom um identificador único (por exemplo vet) e referenciamos as posições usando índices (porexemplo vet[0], vet[1], vet[2], vet[3],... etc). Também abstraindo isto, teríamos:

Figura 8.2: Outro exemplo de Vetor

Lembrando que os índices nos vetores se iniciam de 0, necessitamos declarar um vetor antesde usá-lo, como fizemos com as variáveis. Fazemos assim:tipo nome_do_vetor [numero_de_elementos℄;

onde tipo é qualquer tipo válido ja conhecido (int, float, etc...), nome_do_vetor deve ser umidentificador válido (como sempre) e numero_de_elementos deve ser uma constante inteira, jáque vetores são valores são blocos de memória não-dinâmica cujo tamanho deve ser determinadoantes da execução. Exemplo:int notas[30℄;

60

Page 62: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

,significa que armazenaremos um vetor com 30 números inteiros.

Inicializando os Vetores

Ao declararmos um vetor localmente, se não especificarmos, seus elementos não serão inici-alizados com valor algum por padrão e seu conteúdo será indeterminado até que algum valorseja atribuído a eles. Localmente e globalmente, ao declararmos um vetor, podemos atribuirvalores iniciais às posições do vetor colocando-os entre chaves e separados por vírgulas (,).Assim:int notas[5℄ = { 10, 5, 7, 3, 6};

que criaria um vetor assim:

Figura 8.3: Criação de vetor

Note que o número de elementos nas chaves deve sempre ser igual ao declarado dentro doscolchetes [ ];

Acessando os valores

Para acessarmos os valores do vetor individualmente, como se fossem variáveis, podemos usaríndices, como já foi falado. Desta maneira:nome_do_vetor[índi e℄

,para armazenarmos um valor do vetor em uma variável separada fazemos por exemplo:int x = notas[3℄;que atribuir o valor inserido na quarta posição do vetor notas para a variável x. Podemos

também fazer o contrário, inserindo algum valor em uma determinada posição do vetor destameneira:notas[2℄ = 7;

São também operações válidas de vetores:notas[0℄ = i;notas[i℄ = 75;x = notas[i+2℄;notas[notas[i℄℄ = notas[2℄ + 2;OBS: é importante notar que os colchetes desempenham 2 funções nos vetores. São usados

na declaração de um novo vetor, especificando seu numero de elementos, e são também usadospara isolar os índices, na hora de acessar as posições do vetor. Exemplo:

61

Page 63: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFint notas[5℄;notas[2℄ = 7;Exemplo de código com vetores:#in lude <iostream>using namespa e std;int notas[℄ = {1, 2, 3, 4, 5};int n, resultado=0;int main (){for ( n=0 ; n<5 ; n++ ){resultado += notas[n℄;} out << resultado;return 0;}, que mostra na tela o valor 15.

8.2 Arrays multidimensionais

São basicamente "vetores de vetores". Vetores multidimensionais podem conter quantos índi-ces quanto forem necessários. Só devemos ter cuidado com o tamanho de memória necessária,já que num vetor deste tipo ela cresce rapidamente com cada dimensão.

Podemos abstrair um array bidimensional assim:

Figura 8.4: Array Multidimensionalmat, por exemplo, representa um vetor bidimensional de 4 por 5 do tipo inteiro. Declaramosdesta maneira:int nome_do_array[numero_de_linhas℄[numero_de_ olunas℄;

Exemplo:int mat[4℄[5℄;62

Page 64: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Lembrando que os índices começam sempre em 0, referenciamos o 2º elemento verticalmentee 3º horizontalmente, por exemplo (marcado em vermelho na figura), desta maneira:mat[1℄[2℄8.3 Passando Vetores Como Parâmetros

Podemos querer, em algum momento, passar vetores como parâmetros de funções. Comonão é possível passar um bloco completo de memória por valor como um parâmetro, passamosapenas os endereços. Na prática, tem quase o mesmo efeito e é mais eficiente e rápido. A únicacoisa que necessitamos é especificar na declaração da função o tipo do vetor, um identificador eos colchetes [ ]. Desta maneira:void fun ao (int vet[℄){blo o de instruções}

A declaração de função anterior aceita um parâmetro do tipo "vetor de inteiros", neste caso ovet. Para passar a esta função um vetor declarado como:int vetor[30℄;

,podemos chamar a funcao desta maneira:fun ao(vet);Exemplo:#in lude <iostream>using namespa e std;void mostravetor(int vet[℄, int length) {for (int n=0; n<length; n++) out << vet[n℄ << " "; out << "\n";}int main (){int vetor1[℄ = {5, 10, 15};int vetor2[℄ = {2, 4, 6, 8, 10};mostravetor(vetor1,3);mostravetor(vetor2,5);return 0;},que mostra na tela:5 10 152 4 6 8 10

63

Page 65: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Também podemos passar vetores multidimensionais como parâmetros de funções. Eles te-riam o seguinte formato:tipo nome_da_fun ao (tipo nome[℄[profundidade℄[profundidade℄){blo o de instruções}

Exemplo:void fun ao (int multi[℄[3℄[4℄)Note que os primeiros colchetes são deixados em branco enquanto os seguintes não. Funci-

ona assim pois o compilador deve ser capaz de determinar numa função qual é a profundidadede cada dimensão adicional.

8.4 Seqüencia de Caracteres

Assim como em várias linguagens, podemos representar em C++ as strings como vetores decaracteres, já que elas são, na verdade, seqüências de caracteres. Desta maneira, a seguinteexpressão: har frase[30℄;

,é um vetor que pode armazenar até 30 elementos do tipo caractere. Podemos, entretanto, ar-mazenar seqüências menores. Por exemplo, frase poderia armazenar "Olá"ou "Como vai você?",ambas com menos de 30 caracteres. Para designar o fim de uma seqüência válida, usa-se ocaracter null:'\0'

Podemos representar graficamente como:

Figura 8.5: Seqüência de caracteres

Inicialização de seqüências de caracteres terminadas com n ull

Como podem ser considerados simples vetores, as seqüências de caracteres seguem as mesmasregras. Se quisermos inicializar um vetor de caracteres com alguma seqüência pré-determinada,por exemplo, fazemos igual a qualquer outro vetor: har frase[℄ = { 'B', 'e', 'm', ' ', 'V', 'i', 'n', 'd', 'o', 's', '\0'};

64

Page 66: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Arrays de caractere, no entanto, ainda contam com outro método para terem seus valoresinicializados: usando strings. Sabemos que:"esta é uma frase"

é uma string cujo tipo é, na verdade, um array de caracteres. Então strings também contêm ocaracter null ao final. Com isso podem ser usados para inicializar um vetor de caracteres, destamaneira: har frase[℄ = "Bem Vindos";

,que tem o mesmo resultado que a declaração mostrada anteriormente.

Até aqui mostramos inicializações de vetores de caracteres no momento em que são declara-dos, mas não ainda após já terem sido declarados. Se frase for um vetor char[], expressões destetipo: frase = "Bem vindos";frase = { 'B', 'e', 'm', ' ', 'V', 'i', 'n', 'd', 'o', 's', '\0'};frase[℄ = "Bem vindos";

não seriam válidas. Ao sabermos mais sobre ponteiros, isso ficará um pouco mais claro, jáque mostraremos que um vetor é, na verdade, um ponteiro constante apontando para certo blocode memória.

Cin e cout suportam seqüências terminadas em null como containers válidos para seqüênciasde caracteres. Podem, com isso, ser diretamente usados para extrair strings de caracteres do cinou para inserí-las no cout.Exemplo:#in lude <iostream>using namespa e std;int main (){ har perg[℄ = "Por favor, insira seu Primeiro nome: "; har resp[℄ = "Bem vindo, "; har nome[90℄; out << perg; in >> nome; out << resp << nome << "!";return 0;}

, o que mostrará:Por favor, insira seu Primeiro nome: JúlioBem vindo, Júlio!"65

Page 67: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Como podemos ver, declaramos três arrays de caracteres. Nos dois primeiros, inicializamoscom strings e o terceiro não foi inicializado. Em todos os casos é necessário definir o tamanho dovetor. Nos dois primeiros está implícito, definido pelo comprimento da string com que eles foraminicializados. O último está explícito que são 90 posições. Por fim, seqüências de caracteresarmazenadas em vetores de caracteres podem ser facilmente convertidas em strings apenasusando o operador de atribuição, desta maneira:string str; har text[℄="fim de li ao";str = text;

66

Page 68: Programacao cpp

Capítulo 9

Ponteiros e Memória Dinâmica

9.1 Ponteiros

A memória do computador pode ser abstraída como uma sucessão de células, representandoas posições de memória, cada uma do tamanho mínimo que as máquinas trabalham: 1 byte.Estas posições são numeradas de uma maneira seqüencial, consecutiva, de maneira que em umbloco de memória cada célula tem sua numeração igual à anterior adicionada de 1.

Assim que declaramos uma variável, a quantidade de memória necessária é atribuída a um lo-cal específico na memória. Normalmente não decidimos exatamente onde será o exato local davariável dentro da memória, já que é uma tarefa automaticamente realizada pelo Sistema Opera-cional na execução. Em alguns casos, entretanto, é interessante sabermos o endereço de ondenossa variável está armazenada durante a execução com a finalidade de operar com posiçõesrelativas a ela.

O endereço que identifica uma variável na memória é o que chamamos de uma referência àquelavariável. Ela pode ser obtida precedendo o identificador de uma variável com o operador de refe-rência, representado pelo símbolo &, que pode ser literalmente traduzido para "o endereço de".Exemplo:var1 = &var2;

Isto significa que estamos atribuindo var1 para o endereço da variável var2. Não estamosfalando sobre o conteúdo da variável em si ao preceder var2 pelo operador &, mas sim sobre suareferência, seu endereço de memória. Mostrarei um exemplo simples para clarificar um poucomais.

Primeiramente vamos assumir que var1 está alocado na memória no endereço 1234 (na rea-lidade não sabemos antes da execução o valor real do endereço que uma variável vai ter namemória, sendo este número somente para exemplificar). Veja o código:var1 = 40;var2 = var1;var3 = &var1;

Os valores contidos nas variáveis são:

67

Page 69: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

• var1 = 40, pois assumimos este valor no início do programa.

• var2 = 40, pois atribuímos ao var2 o valor que estava na variável var1 (variável cujo valorera 40 e endereço de memória era 1234)

• var3 = 1234, pois atribuímos a var3 o endereço de memória em que estava var1.

Veja a figura:

Figura 9.1: Ponteiros

Os Ponteiros

Chamamos de ponteiro a variável que armazena uma referência para outra variável, como var3no último exemplo. Abstraindo novamente, ponteiros são ditos apontando para a variável cujareferência eles armazenam. Ao usar um ponteiro, podemos acessar diretamente o valor armaze-nado na variável para a qual ele aponta. Para fazer isto, simplesmente precedemos o identificadordo ponteiro pelo asterisco (*), que pode ser literalmente traduzido para "valor apontado por".Exemplo:var4 = *var3; //var4 é igual ao valor apontado por var3. Como var3 armazena o endereço 1234 ...//... e o valor ontido no endereço 1234 é 40, var4 re eberia 40.

Devemos claramente diferenciar que a expressão var3 é diferente de *var3, a primeira repre-sentando o valor 1234 e a segunda se referindo ao valor armazenado em 1234, que é 40. Noteque anteriormente fizemos as seguintes atribuições:var1 = 40;var3 = &var1;

Após estas atribuições, as seguintes sentenças retornariam true (verdadeiro) se executadas:var1 == 40&var1 == 1234var3 == 1234*var3 == 4068

Page 70: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Devido à habilidade de referenciar diretamente o valor para o qual aponta, é necessário sem-pre especificar na declaração para qual tipo de dado um ponteiro irá apontar. Isto é um tantoóbvio visto que não é a mesma coisa apontar para um char do que apontar para um int ou float.

A declaração dos ponteiros segue o seguinte:tipo * nome;onde tipo é o tipo de dado do valor para o qual o ponteiro pretende apontar. Este tipo não é o

tipo do ponteiro em si! Exemplo de declarações de ponteiros:int * num; har * ;float * fnum;Cada uma das declarações anteriores pretende apontar para um tipo de dado diferente, mas

na realidade todos são ponteiros e ocuparão o mesmo espaço na memória (o tamanho da me-mória de um ponteiro depende da plataforma onde o código é executado). Todavia, o dado parao qual eles apontam não ocupam o mesmo espaço nem são do mesmo tipo: o primeiro apontapara um int, o segundo para um char e o terceiro para um float. Com isso, apesar de serem todosponteiros, são ditos terem tipos diferentes: int*, char* e float* respectivamente.

OBS: é importante frisar que o asterisco (*) usado ao declararmos aqui um ponteiro só indicaque é um ponteiro, e não deve ser confundido com o operador visto anteriormente usado comoum referenciador, que também é escrito com um asterisco (*).

Exemplo de declaração de ponteiros:#in lude <iostream>using namespa e std;int main (){int val1, val2;int * pont;pont = &val1;*pont = 10;pont = &val2;*pont = 20; out << "val1 é " << val1 << endl; out << "val2 é " << val2 << endl;return 0;}, o que retorna:val1 é 10val2 é 20

69

Page 71: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Note que mesmo que não tenhamos diretamente setado um valor para val1 e val2, os doisterminam com um valor setado indiretamente pelo uso de pont. Isto pois ao atribuirmos um valorpara o local de memória apontado por pont, modificamos o valor de val1 e val2. Note que umponteiro pode aceitar diversos valores diferentes durante o mesmo programa.

Um exemplo um pouco mais elaborado:#in lude <iostream>using namespa e std;int main (){int val1 = 5, val2 = 15;int * p1, * p2;p1 = &val1; // p1 = endereço de val1p2 = &val2; // p2 = endereço de val2*p1 = 10; // valor apontado por p1 = 10*p2 = *p1; // valor apontado por p2 = valor apontado por p1p1 = p2; // p1 = p2 (valor do ponteiro é opiado)*p1 = 20; // valor apontado por p1 = 20 out << "val1 é " << val1 << endl; out << "val2 é " << val2 << endl;return 0;},o que retorna na tela:val1 é 10val2 é 20Note que há expressões com os ponteiros p1 e p2 ambas com e sem o operador de referência

(*). O significado de uma expressão usando esse operador é muito diferente da que não o usa(*): quando ele precede o nome de um ponteiro, a expressão refere-se ao valor sendo apontado,enquanto quando o ponteiro aparece sem este operador, refere-se ao valor do ponteiro em si(endereço para o que o ponteiro está apontando). Outra coisa a se chamar atenção é a linha:int * p1, * p2;

, que declara dois ponteiros usados no exemplo. Mas perceba que há um asterisco (*) paracada ponteiro. Se não usássemos os dois asteriscos, deixando p2 sem o asterisco por exemplo,o tipo dela seria somente int. Desta maneira:int * p1, p2;

Aqui, p1 tem o tipo int* mas p2 somente tem o tipo int, que não serviria de nada no exemplo.

70

Page 72: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

9.1.1 Ponteiros Aritméticos

Operações aritméticas em ponteiros têm uma maneira um pouco diferente de serem condu-zidas do que em tipo inteiros comuns. Somente adição e subtração são permitidas. Mas ambasadição e subtração têm um diferente comportamento com ponteiros de acordo com o tamanhodo tipo de dados para o qual ele aponta. Quando vimos os tipos fundamentais vimos que algunsocupam mais ou menos memória que os outros. Por exemplo, assuma que numa certa máquinachar recebe 1 byte, short recebe 2 bytes, e long recebe 4. Suponha também que definimos 3ponteiros: har *p har;short *pshort;long *plong;

, e que saibamos que eles apontam para os locais de memória 1000, 2000 e 3000 respectiva-mente. Então, se escrevermos:p har++;pshort++;plong++;

oup har = p har + 1;pshort = pshort + 1;plong = plong + 1;, vamos perceber que pchar conterá o valor 1001, pshort conterá 2002, e plong conterá 3004.

A razão é que, ao adicionar uma unidade a um ponteiro, estamos fazendo que ele aponte parao elemento seguinte do mesmo tipo em que ele foi definido, e assim o tamanho em bytes dotipo apontado é adicionado ao ponteiro. Isto é aplicável ao adicionarmos ou subtrairmos algumnúmero de um ponteiro.

Note que ambos incremento (++) e decremento (–) têm precedência maior do que o operador(*), mas ambos t?m um comportamento especial quando usados como sufixos (a expressão éavaliada com o valor que tinha antes de ser incrementada). Com isso, a expressão seguinte podelevar a uma confusão:*p++

Como (++) tem precedêndia maior que (*), esta expressão é equivalente a *(p++). Então, oque ela faz é incrementar o valor de p (fazendo ele apontar para próximo elemento), mas como++ é usado pós-fixado, toda a expressão é avaliada com o valor apontado pela referência original(o endereço para o qual apontava antes de ser incrementado). Note a diferença com:(*p)++

Aqui, a expressão seria avaliada como o valor apontado por p incrementado em uma unidade.O valor de p, o ponteiro em si, não seria modificado, mas sim o que está sendo apontado por esteponteiro. Se escrevermos:

71

Page 73: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF*p++ = *q++;, como (++) tem precedência maior que (*), ambos p e q são incrementados mas, por ambos

usarem os operadores de incremento como pós-fixados, o valor atribuído a *p é *q antes quesejam incrementados. Seria equivalente a*p = *q;++p;++q;

OBS: sempre use parênteses para evitar ambigüidades e melhorar a legibilidade do código.

9.1.2 Ponteiros para Ponteiros

Podemos também usar ponteiros que apontam para ponteiros e, os últimos, por sua vez,apontam para dados ou mesmo para outros ponteiros. Para isto, é necessário adicionar umasterisco (*) para cada nível de referência nas declarações. har a; har * b; har ** ;a = 'z';b = &a; = &b;

Isto, supondo locais de memória aleatoriamente escolhidos para cada variável respectiva-mente de 7230, 8092, 10502, pode ser representado como:

Figura 9.2: Ponteiros 2

O valor de cada variável é escrito em cada célula, e abaixo seus respectivos endereços dememória. A novidade aqui é a variável c, que pode ser usada em 3 diferentes níveis de indireção,cada um correspondendo a um valor diferente. tem tipo har** e um valor de 8092* tem tipo har* e um valor de 7230** tem tipo har e um valor de 'z'9.1.3 Ponteiros sem tipo

O tipo void de um ponteiro é um tipo especial de ponteiro. Em C++, void representa a au-sência de tipo, então ponteiros void são ponteiros que apontam para um valor que não tem tipo

72

Page 74: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

(tendo, com isso, tamanho indeterminado). Isto permite que ponteiros void apontem para dadosde qualquer tipo. Porém, têm uma limitação: o dado apontado por ele não pode ser referenciadodiretamente. Por esta razão, sempre teremos que escalar o endereço de um ponteiro void paraum outro tipo de ponteiro que aponte par aum tipo de dado concreto antes de referenciá-lo. Sãoextremamente úteis para passar parâmetros genéricos a uma função. Exemplo:#in lude <iostream>using namespa e std;void in rem (void* dado, int ptam){if ( ptam == sizeof( har) ) //sizeof retorna o tamanho em bytes de seu parâmetro. Aqui, retorna 1 ( har = 1byte){ har* p har; p har=( har*)dado; ++(*p har); }else if (ptam == sizeof(int) ){ int* pint; pint=(int*)dado; ++(*pint); }}int main (){ har a = 'x';int b = 1602;in rem (&a,sizeof(a));in rem (&b,sizeof(b)); out << a << ", " << b << endl;return 0;}

, que retornará na tela:y, 16039.1.4 Ponteiro Nulo

É um ponteiro de qualquer tipo que tem um valor especial que indica que não está apontandopara nenhum endereço.Exemplo:int * p;p = 0; // p tem um ponteiro nulo omo valor

OBS: É importantíssimo não confundir ponteiro nulo com ponteiro void. Um ponteiro nulo éum valor que qualquer ponteiro pode ter para representar que não está apontando para "lugarnenhum", enquanto um ponteiro void é um tipo especial que ponteiro que pode apontar paraalgum lugar sem um tipo específico.

9.1.5 Ponteiros para Funções

Por último, podemos fazer que os ponteiros também apontem para funções. O uso típicoé para passar uma função como argumento para uma outra função, já que ela não pode ser

73

Page 75: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

passada como referência. Para declarar um ponteiro para uma função temos que declarar comoo protótipo de uma função exceto com o nome da função entre parênteses (), e um asterisco (*)é inserido antes do nome:#in lude <iostream>using namespa e std;int adi ao(int a, int b){ return (a+b); }int subtra ao(int a, int b){ return (a-b); }int opera ao(int x, int y, int (* hamafun )(int,int)){int g;g = (* hamafun )(x,y);return (g);}int main (){int m,n;int (*menos)(int,int) = subtra ao;m = opera ao(7, 5, adi ao);n = opera ao(20, m, menos); out <<n;return 0;}

, que retorna na tela o valor 8.

No exemplo, menos é um ponteiro para uma função que tem 2 parâmetros do tipo int. É ime-diatamente feita apontar para a função subtracao, tudo na linha:int (* minus)(int,int) = subtra tion;9.2 Memória Dinâmica

Nos programas e exemplos até agora só tínhamos o tanto de memória disponível quanto de-claramos nas variáveis. Se quisermos que a quantidade de memória seja determinada durantea execução, por exemplo no caso em que queiramos que o próprio usuário insira a quantidadenecessária de espaço em memória, temos que descartar as estruturas estáticas como vetores epassar a usar estruturas dinâmicas.

Para requisitar memória dinâmica, usamos o operador new. Ele é seguido por um especifica-dor do tipo de dado e, se for requerida uma sentença de mais de um elemento, o número de

74

Page 76: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

elementos entre colchetes [ ]. Retorna um ponteiro para o começo do novo bloco de memóriaalocada.

Seu formato é:ponteiro = new tipoponteiro = new tipo [numero_de_elementos℄A primeira sentença é usada para alocar memória para conter um único elemento do tipo

tipo. A segunda sentença é usada para atribuir um vetor de elementos do tipo tipo, onde nu-mero_de_elementos é um valor inteiro representando a quantidade deles.

Exemplo:int * fulano;fulano = new int [5℄;Aqui o sistema atribui dinamicamente espaço para cinco elementos do tipo int e retorna um

ponteiro para o primeiro elemento da seqüência, que é atribuído a fulano. Então, agora fulanoaponta para um bloco de memória válido com espaço para 5 elementos do tipo int. O primeiroelemento apontado por fulano pode ser acessado tanto pela expressão fulano[0] como por *fu-lano. Já o segundo elemento por ser acessado tanto como fulano[1] ou *(fulano+1) e assim pordiante.

A memória dinâmica requerida pelo programa é alocada da memória heap pelo sistema. En-tretanto ela pode se esgotar, tornando importante termos um mecanismo para checar se nossorequerimento de alocar memória teve sucesso ou não. Em C++ temos 2 mecanismos:

Um é o tratamento de exceções, ou erros. Um erro do tipo bad_alloc é lançado quando a alo-cação falha. Exceções serão melhores explicadas adiante, mas aqui já é interessante saber quequando uma exceção é lançada e não é tratada por um manipulador específico a execução éfinalizada. Este método é o padrão usado por new e é usado em declarações como:fulano = new int[5℄; //se falhar, uma ex eção é lançada.

O outro método é conhecido como nothrow, e o que acontece quando é usado é que quandoa alocação de memória falha, ao invés de lançar uma exceção bad_alloc ou terminar o programa,o ponteiro retornado pelo new é um ponteiro nulo, e a execução é continuada. Este método podeser especificado usando um objeto especial chamado nothrow, declarado no cabeçalho <new>,como um argumento para new:fulano = new (nothrow) int [5℄;

Neste caso, se a alocação falhar, o erro poderá ser detectado checando se fulano recebeu umponteiro nulo:int * fulano;fulano = new (nothrow) int [5℄;if (fulano == 0) {// erro de alo ação de memoria.};

75

Page 77: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Este método querer mais trabalho que o primeiro método, já que o valor retornado tem queser avaliado após cada e toda alocação de memória. No entanto, usaremos em alguns exemplosdevido à sua simplicidade. Entretanto, para projetos maiores, pode ser um método que se tornatedioso, onde o método de exceções é preferido, método este que será melhor explicado adianteno curso.

Assim que o uso de memória dinâmica não for mais necessitado no programa, a área da me-mória utilizada deve ser limpa para que possa ser aproveitada por outras requisições de uso dememória dinâmica. Faremos esta limpeza usando o operador delete, cujo formato é:delete ponteiro;delete [℄ ponteiro;

A primeira pode ser usada para limpar memória alocada para um único elemento, e a segundapara memória alocada para vetores de elementos. O valor passado como argumento ao deletedeve ser ou um ponteiro para um bloco de memória previamente alocado com o new, ou umponteiro nulo (neste caso, não surtindo efeito algum). Exemplo:#in lude <iostream>#in lude <new>using namespa e std;int main (){int i,x;int * pont; out << "Quantos números gostaria de es rever? "; in >> i;pont = new (nothrow) int[i℄;if (pont == 0) out << "Erro!! memória não p�de ser alo ada!";else{for (x=0; x<i; x++){ out << "Insira um número: "; in >> pont[x℄;} out << "Vo ê inseriu: ";for (x=0; x<i; x++) out << pont[x℄ << ", ";delete[℄ pont;}return 0;}

, o que retorna na tela:Quantos números gostaria de es rever? 476

Page 78: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFInsira um número: 32Insira um número: 26Insira um número: 18Insira um número: 7Vo ê inseriu: 32, 26, 18, 7,Note que o valor entre colchetes na sentença new é um valor variável inserido pelo usuário

(i), não um valor constante: out << "Quantos números gostaria de es rever? "; in >> i;pont = new (nothrow) int[i℄;No caso anterior, se o usuário inserir um valor para i muito grande como 1 bilhão, por exemplo,

o sistema não poderia alocar memória suficiente e teríamos a mensagem de erro:Erro!! memória não p�de ser alo ada!No caso de que tentássemos alocar memória para o programa sem especificar o parâmetro

nothrow, a exceção seria lançada e, se não fosse tratada, o sistema terminaria a execução. Deve-mos, então, sempre checar se o bloco de memória dinâmica foi alocado com sucesso. Assim, seusarmos o método nothrow, sempre devemos checar o valor que o ponteiro retornou. Caso con-trário, devemos usar o método de exceções, mesmo que não tratemos a exceção. Desta maneira,o programa terminará naquele ponto sem causar o resultado inesperado de continuar a execuçãodo código assumindo que um bloco de memória foi alocado, quando na realidade não foi.

OBS: É importante salientar que os operadores new e delete são exclusivos de C++. Se usarmosa linguagem C, memória dinâmica pode ser usada através das funções malloc, calloc, realloc efree, definidas na biblioteca <cstdlib>. Como C++ é um superset de C, essas funções tambémestão disponíveis para programadores C++. No entanto, os blocos de memória alocados por es-tas funções não são necessariamente compatíveis com aqueles retornados pelo new, então cadaum deve ser manipulado com seu próprio set de funções ou operadores.

77

Page 79: Programacao cpp

Capítulo 10

Estruturas de Dados

Uma estrutura de dados é uma junção de elementos de dados agrupados recebendo umnome. Esses elementos ou membros podem ter tipos diferentes e tamanhos diferentes. Estrutu-ras de dados são declaradas em C++ na sintaxe:stru t nome_da_estrutura{membro_tipo1 membro_nome1;membro_tipo2 membro_nome2;...membro_tipox membro_nomex;} nome_do_objeto;

onde nome_da_estrutura é um nome para o tipo de estrutura, nome_do_objeto pode ser umset de identificadores válidos para objetos que têm o tipo desta estrutura. Entre chaves, existeuma lista com os membros de dados, cada um especificado com um tipo e um indentificadorválido como nome.

Uma estrutura de dados cria um novo tipo: assim que uma estrutura é declarada, um novo tipocom um identificador especificado como nome_da_estrutura é criado e pode ser usado no restodo programa como se fosse um novo tipo.Exemplo:stru t produto{int peso;float pre o;} ;produto arne;produto arroz, feijao;

Primeiro declaramos uma estrutura com 2 membros: peso e preço, e depois usamos essaestrutura para declarar três objetos do tipo "produto": carne, arroz e feijao. Depois de declarado,produto se tornou um novo tipo válido, como int, char ou short, e dali em diante podemos declararobjetos (variáveis) deste novo tipo. No fim da declaração e antes dos dois-pontos finais podemosusar o campo opcional nome_do_objeto para declarar diretamente objetos do tipo da estrutura.

78

Page 80: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Por exemplo, podemos também declarar os objetos da estrutura carne, arroz e feijao no momentoem que definimos o tipo da estrutura de dados assim:stru t produto{int peso;float pre o; arne, arroz, feijao;}

É importante diferenciar o que é o nome do tipo da estrutura e o que é um objeto (variável) quetem este tipo de estrutura. Podemos instanciar muitos objetos de um simples tipo de estrutura.Uma vez tendo declarado os 3 objetos de um determinado tipo de estrutura (carne, arroz, feijao),podemos operar diretamente com seus membros. Para isto usamos o ponto (.) inserido entreo nomedo objeto e o nome do membro. Por exemplo, podemos operar com qualquer desteselementos como se eles fossem variáveis padrão de seus respectivos tipos: arne.peso arne.pre oarroz.pesoarroz.pre ofeijao.pesofeijao.pre o

Cada uma destas tem o tipo de dado correspondente ao membro a que eles se referem:carne.peso, arroz.peso e feijao.peso são do tipo int, enquanto carne.preco, arroz.preco e fei-jao.preco são do tipo float. Vamos ver um exemplo real:#in lude <iostream>#in lude <string>#in lude <sstream>using namespa e std;stru t filmes_t {string titulo;int ano;} meu, seu;void mostrafilme(filmes_t filme);int main (){string str;meu.titulo = "Titani ";meu.ano = 1997; out << "Insira o título do filme: ";getline ( in,seu.titulo); out << "Insira o ano: ";

79

Page 81: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFgetline ( in,str);stringstream(str) >> seu.ano; out << "Meu filme favorito é:\n ";mostrafilme(meu); out << "E o seu é:\n ";mostrafilme(seu);return 0;}void mostrafilme(filmes_t filme){ out << filme.titulo; out << " (" << filme.ano << ")\n";}, que retorna na tela:Insira o título do filme: AlienInsira o ano: 1979Meu filme favorito é:Titani (1997)E o seu é:Alien (1979)O exemplo anterior mostra como podemos usar os membros de um objeto como variáveis

comuns. Por exemplo, o membro seu.ano é uma variável válida do tipo int e meu.titulo é umavariável válida do tipo string. Os objetos meu e seu também podem ser tratados como variáveisválidas do tipo filmes_t, por exemplo se as tivéssemos passado para a função mostrafilme comoteríamos feito com variáveis comuns. Assim, uma das mais importantes vantagens das estruturasde dados é que podemos nos referir tanto a seus membros individualmente quanto à estruturainteira como um bloco com apenas 1 identificador.

Estrutura de dados podem ser usadas para representar bases de dados, especialmente se con-siderarmos a possibilidade de construir vetores com elas.#in lude <iostream>#in lude <string>#in lude <sstream>using namespa e std;#define N_FILMES 3stru t filmes_t {string titulo;int ano;} films [N_FILMES℄;

80

Page 82: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFvoid mostrafilme (filmes_t filme);int main (){string str;int n;for (n=0; n<N_FILMES; n++){ out << "Insira o título: ";getline ( in,films[n℄.titulo); out << "Insira o ano: ";getline ( in,str);stringstream(str) >> films[n℄.ano;} out << "\nVo ê inseriu estes filmes:\n";for (n=0; n<N_FILMES; n++)mostrafilme (films[n℄);return 0;}void mostrafilme (filmes_t filme){ out << filme.titulo; out << " (" << filme.ano << ")\n";}, o que retorna na tela:Insira o título: Blade RunnerInsira o ano: 1982Insira o título: MatrixInsira o ano: 1999Insira o título: Taxi DriverInsira o ano: 1976Vo ê inseriu estes filmes:Blade Runner (1982)Matrix (1999)Taxi Driver (1976)Ponteiros para Estruturas

Como qualquer outro tipo, estruturas podem ser apontadas por seus próprios tipos de pontei-ros. stru t filmes_t {string titulo;

81

Page 83: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFint ano;};filmes_t afilme;filmes_t * pfilme;Aqui, afilme é um objeto de estrutura que tem o tipo filmes_t, e pfilme é um ponteiro para

objetos da estrutura filmes_t. Então, o seguinte código também seria válido:pfilme = &afilme;O valor do ponteiro pfilme seria atribuído à referência ao objeto afilme (seu endereço de me-

mória). Um outro exemplo incluíndo ponteiros, que servirão para introduzir o operador flecha(->). #in lude <iostream>#in lude <string>#in lude <sstream>using namespa e std;stru t filmes_t {string titulo;int ano;};int main (){string str;filmes_t afilme;filmes_t * pfilme;pfilme = &afilme; out << "Insira um título: ";getline ( in, pfilme->titulo); out << "Insira o Ano: ";getline ( in, str);(stringstream) str >> pfilme->ano; out << "\nVo ê inseriu:\n"; out << pfilem->titulo; out << " (" << pfilme->ano << ")\n";return 0;}

, o que retorna na tela:Insira um título: Titani 82

Page 84: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFInsira o Ano: 1997Vo ê inseriu:Titani (1997)A flecha do código anterior (->) é um operador de referência que é usado exclusivamente

com ponteiros para objetos com membros. Este operador serve para acessar um membro de umobjeto para o qual temos uma referência. No exemplo usamos:pfilme->titulo

, que é equivalente a:(*pfilme).tituloAmbas as expressões são válidas e ambas significam que estamos avaliando o membro titulo

da estrutura de dados apontada por um ponteiro chamado pfilme. Deve ser diferenciada de:*pfilme.titulo,que é equivalente a*(pfilme.titulo), e acessaria o valor do ponteiro por um membro de um ponteiro hipotético chamado titulo do

objeto da estrutura pfilme (que neste caso não seria um ponteiro). O seguinte quadro resumepossíveis combinações de ponteiros e membros de estruturas:Expressão O que é avaliado Equivalentea.b Membro b do objeto aa->b Membro b do objeto apontado por a (*a).b*a.b Valor apontado pelo membro b do objeto a *(a.b)

Estruturas Aninhadas

Estruturas também podem ser aninhadas:stru t filmes_t {string titulo;int ano;};stru t amigos_t {string nome;string email;filmes_t favorito_filme;} fulano, beltrano;amigos_t * pamigos = &fulano;Após a declaração anterior, podemos usar qualquer uma das seguintes expressões:

83

Page 85: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFfulano.nomebeltrano.favorito_filme.titulofulano.favorito_filme.anopamigos->favorito_filme.anoonde, por sinal, as duas últimas expressões referem-se ao mesmo membro.

10.1 Tipos de Dados Definidos (typedef)

Podemos definir nossos próprios tipos baseados em tipos existentes no C++. Para isto, usa-remos a palavra-chave typedef, que tem a seguinte sintaxe:typedef [tipo_existente℄ [novo_tipo℄;

Exemplo:typedef har C;typedef har field [40℄;typedef unsigned int WORD;typedef har * pChar;Aqui, definimos, respectivamente: C (char), field (char[40]), pChar (char*) e WORD (unsigned

int). Com isto, poderíamos usá-los em declarações posteriores. Exemplo:C ara , ara 2, *pp 1;WORD vpal;pChar pp 2;field nome;É importante notar que typedef não cria um tipo diferente, mas apenas cria sinônimos os

tipos existentes. Assim, vpal pode ser considerada ou WORD ou unsigned int, já que os doissão na realidade o mesmo tipo. Typedef pode ser útil para definir um alias para um tipo que éfreqüentemente utilizado em um programa. Também é útil para definir tipos quando é possívelque precisamos modificar o tipo em versões posteriores do nosso programa, ou se um tipo quequeremos usar tem um nome que é muito longo ou confuso.

10.2 Uniões (Unions)

Permitem uma mesma porção de memória ser acessada como diferentes tipos de dados,desde que todos são na verdade o mesmo local na memória. Sua declaração e uso é similar adas estruturas mas sua funcionalidade é totalmente diferente:union nome_da_uniao {tipo_do_membro1 nome_do_membro1;tipo_do_membro2 nome_do_membro2;tipo_do_membro3 nome_do_membro3;..} nomes_dos_objetos;

84

Page 86: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Todos os elementos da declaração da união ocupam o mesmo espaço físico na memória. Seutamanho é um dos maiores elementos da declaração. Por exemplo:union tipos_t { har ;int i;float f;} tipos;

define três elementos:tipos. tipos.itipos.fcada um com um tipo de dado diferente. Como todos estão se referindo ao mesmo local

na memória, a modificação de um dos elementos afetará o valor de todos eles. Não podemosarmazenar valores diferentes neles independentemente. Um dos usos do union é unir um tipoelementar com um array ou estrutura de elementos menores.Exemplo:union mix_t {long l;stru t {short hi;short lo;} s; har [4℄;} mix;

define três nomes que nos permitem acessar o mesmo grupo de 4 bytes: mix.l, mix.s, mix.c eque podemos usar de acordo com como queremos acessar esses bytes, como se fossem um tipolong de dados, ou dois elementos short, ou mesmo um array de elementos char, respectivamente.

O exato alinhamento e ordem dos membros de uma union na memória depende da plataforma.Assim, é importante levarmos em conta possiveis erros de portabilidade com este tipo de uso.

10.3 Uniões Anônimas (Anonymous unions)

Se declararmos uma union sem um nome, ela será uma união anônima e será capaz de aces-sar seus membros diretamente por seus nomes. Veja a diferença:

-estrutura com union usualstru t { har titulo[50℄; har autor[50℄;union {85

Page 87: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFfloat dolares;int ienes;} pre o;} livro;-estrutura com union anônimastru t { har titulo[50℄; har autor[50℄;union {float dolares;int ienes;};} livro;A única diferença entre os dois códigos é que no primeiro demos um nome para a union

(preco) e no segundo não. A diferença é vista quando nós acessamos os membros dolares eienes de um objeto deste tipo. Para um objeto do primeiro tipo, seria:livro.pre o.dolareslivro.pre o.ienes

Em contrapartida, para um objeto do segundo tipo, seria:livro.dolareslivro.ienesLembrando novamente, por serem uma union e não uma struct os membros dolares e ienes

ocupam o mesmo espaço físico na memória de maneira que eles não podem ser usados paraarmazenar dois diferentes valores simultaneamente. Podemos setar um valor para preco emdolares ou em ienes, mas não em ambos.

10.4 Enumerações (enum)

Enumerações criam novos tipos de dados para conter algo diferente que não é limitado aosvalores que tipos de dados fundamentais podem ter.Têm forma:enum nome_da_enumera ao{valor1,valor2,valor3,..} nomes_dos_objetos;

Por exemplo, podemos criar um novo tipo de variável chamada cores para armazenar as corescom a seguinte declarações:

86

Page 88: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFenum ores_t {preto, azul, verde, inza, vermelho, roxo, amarelo, bran o};Note que não incluímos nenhum tipo de dado fundamental na declaração. O que fizemos foi

criar todo um novo tipo de dado sem nos basearmos em nenhum outro tipo existente. Os valorespossíveis que variáveis do novo tipo cores_t podem ter são novos valores constantes incluídosentre aspas . Por exemplo, serão válidas após a declaração anterior: ores_t my olor; or = azul;if ( or == verde) or = vermelho;

Enumerações são tipos compatíveis com variáveis numéricas, então suas constantes sãosempre atribuídas a um valor numérico inteiro internamente. Se não for especificado, o valorinteiro equivalente ao primeiro valor possível é equivalente a 0 e os seguintes seguem uma pro-gressão de +1. Assim, em nosso tipo cores_t, o preto, por exemplo, seria equivalente a 0, azulequivalente a 1, verde a 2 e assim sucessivamente. Podemos especificar um valor inteiro paracada um dos valores constantes que nosso tipo enumerado pode ter. Se o valor que o segue nãoé um valor inteiro, é automaticamente assumido o mesmo valor que o anterior mais 1. Exemplo:enum meses_t { janeiro=1, fevereiro, mar o, abril,maio, junho, julho, agosto,setembro, outubro, novembro, dezembro} y2k;

Neste caso, a variável y2k do tipo enumerado meses_t pode conter qualquer uma das 12possibilidades, que vão de janeiro a dezembro e que são equivalentes a valores entre 1 e 12 (nãoentre 0 e 11, já que fizemos janeiro ser igual a 1) .

87

Page 89: Programacao cpp

Capítulo 11

Programação Orientada a Objeto - POO

11.1 Classes

Uma classe em C++ é um conceito expandido de estrutura de dados: ao invés de conterapenas dados, pode conter dados e funções. Um objeto é uma instanciação de uma classe. Emtermos de variáveis, uma classe seria o tipo e um objeto seria a variável. Formato de declaração(usa, obviamente, a palavra-chave class): lass nome_da_ lasse{espe ifi ador_de_a esso1:membro1;espe ifi ador_de_a esso1:membro2;...} nome_dos_objetos;

, onde mebros podem ser dados, declarações de funções ou opcionalmente especificadoresde acesso. Os últimos podem ser uma das três palavras-chave: private, public, protected. Estesespecificadores modificam os direitos de acesso que os membros que os seguem adquirem:

• membros private de uma classe são acessíveis somente de outros membros da mesmaclasse ou de seus friends (explicado em lições posteriores).

• membros protected são acessíveis de membros da mesma classe e de seus friends, mastambém de membros de classes derivadas.

• membros public são acessíveis de qualquer lugar onde o objeto é visível.

Por padrão, todos os membros de uma classe são declarados com acesso private, a não serque estejam especificados. Exemplo de uma classe: lass Retangulo{int x, y;publi :void seta_valores(int,int);int area (void);} retang;

88

Page 90: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Note que esta classe contém os membros x,y, seta_valores() e area(), sendo os dois primeirosprivate e os dois últimos public.Exemplo de acesso aos elementos public:retang.seta_valores(3,4);x = retang.area();

Exemplo completo de Retângulo:#in lude <iostream>using namespa e std; lass Retangulo{int x, y;publi :void seta_valores (int,int);int area () {return (x*y);}};void Retangulo::seta_valores (int a, int b) {x = a;y = b;}int main () {Retangulo retang;retang.seta_valores (3,4); out << "Area: " << retang.area();return 0;}, que retorna na tela:Area: 12Note que a definição da função membro area() foi incluída diretamente na definição da classe

Retangulo, dada sua simplicidade, onde seta_valores() tem seu protótipo declarado na classe, esua definição está fora dela. Nesta declaração externa devemos utilizar o operador de escopo (:: ), para especificar que nós estamos definindo uma função que é um membro da classe Retan-gulo e não é uma função global usual. Ele especifica, então, a classe a qual o membro que estásendo declarado pertence, garantindo exatamente a mesma propriedade de escopo, como seesta definição de função estivesse diretamente incluída na definição da classe. Por exemplo, nafunção seta_valores() do código anterior pudemos usar x e y, que são membros private da classeRetangulo (que significa que são acessíveis somente de outros membros da própria classe).

Uma das maiores vantagens de uma classe é que podemos declarar vários objetos dela. Porexemplo, seguindo o exemplo anterior, podemos ter declarado o objeto retang2 em adição a re-tang:

89

Page 91: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#in lude <iostream>using namespa e std; lass Retangulo {int x, y;publi :void seta_valores (int,int);int area () {return (x*y);}};void Retangulo::seta_valores (int a, int b) {x = a;y = b;}int main () {Retangulo retang, retang2;retang.seta_valores (3,4);retang2.seta_valores (5,6); out << "Area do Retangulo1: " << retang.area() << endl; out << "Area do Retangulo2: " << retang2.area() << endl;return 0;}, o que mostra:Area do Retangulo1: 12Area do Retangulo2: 30Neste caso concreto, a classe (tipo dos objetos) a que estamos falando é Retangulo, na qual

existem duas instâncias ou objetos: retang e retang2. Cada uma delas tem sua própria variávelmembro e funções membro. Note que chamar retang.area() não nos dá o mesmo reultado quechamar retang2.area(). Isto acontece pois cada objeto da classe Retangulo tem suas própriasvariáveis x e y, assim como também têm suas próprias funções membro seta_valores() e area(),cada uma usando suas próprias variáveis de objeto para operar.

Isto é o conceito básico da POO: dados e funções são ambos membros do objeto. Não usa-mos mais sets de variáveis globais que passamos de uma função para a outra como parâmetrosmas, ao invés disso, manipulamos objetos que têm seus próprios dados e funções embutidoscomo membros. Note que não tivemos que passar nenhum parâmetro em nenhuma das chama-das a retang.area ou retang2.area. Aquelas funções membro usaram diretamente os dados deseus respectivos objetos retang e retang2.

11.2 Construtores e Destrutores

Objetos geralmente necessitam inicializar variáveis ou atribuir memória dinamicamente du-rante seus processos de criação para se tornar operativos e para evitar o retorno de valores

90

Page 92: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

inesperados durante suas execuções. Por exemplo, o que aconteceria se no exemplo anteriorchamássemos a função membro area() antes de termos chamado a função seta_valores()? Pro-vavelmente teríamos um resultado indeterminado já que não teriam sido atribuídos valores paraos membros x e y. Para evitar isso, uma classe pode incluir uma função especial chamada cons-trutor, que é chamada automaticamente sempre que um novo objeto desta classe é criado. Esteconstrutor tem que ter o mesmo nome da classe e não deve ter nenhum tipo de retorno, nemmesmo void.Exemplo de implementação de Retangulo incluindo um construtor:#in lude <iostream>using namespa e std; lass Retangulo {int omprimento, altura;publi :Retangulo (int,int);int area () {return ( omprimento*altura);}};Retangulo::Retangulo (int a, int b) { omprimento = a;altura = b;}int main () {Retangulo retang (3,4);Retangulo retang2 (5,6); out << "Area do Retangulo1: " << retang.area() << endl; out << "Area do Retangulo2: " << retang2.area() << endl;return 0;}

, o que retorna:Area do Retangulo1: 12Area do Retangulo2: 30Perceba que o resultado do exemplo é idêntico ao do exemplo anterior. Mas agora remove-

mos a função seta_valores() e incluimos , ao invés dela, um construtor que realiza uma tarefasimilar: inicializa os valores x e y com os parâmetros que são passados a eles. Note que es-tes argumentos são passados ao construtor no mesmo instante que os objetos desta classe sãocriados:Retangulo retang (3,4);Retangulo retang2 (5,6);

Os construtores não podem ser chamados explicitamente como se eles fossem funções mem-bros comuns. Eles somente são executados quando um novo objeto da classe é criado. Já osdestrutores têm a funcionalidade oposta: são automaticamente chamados quando um objeto é

91

Page 93: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

destruído, até porque seu escopo de existência chegou ao fim (por exemplo, se foi definido comoum objeto local de uma função e a função termina) ou porque é um objeto atribuído dinamica-mente e é liberado usando o operador delete.

O destrutor deve ter o mesmo nome da classe, mas antecedido por um til ( ) e como os constru-tores, não retorna valor. Seu uso é especialmente adequado quando um objeto aloca memóriadinamicamente durante seu tempo de vida e no momento de ser destruído, queremos liberar amemória a que o objeto estava alocado.#in lude <iostream>using namespa e std; lass Retangulo {int * omprimento, *altura;publi :Retangulo (int,int);~Retangulo ();int area () {return (* omprimento * *altura);}};Retangulo::Retangulo (int a, int b) { omprimento = new int;altura = new int;* omprimento = a;*altura = b;}Retangulo::~Retangulo () {delete omprimento;delete altura;}int main () {Retangulo retang (3,4), retang2 (5,6); out << "Area do Retangulo1: " << retang.area() << endl; out << "Area do Retangulo2: " << retang2.area() << endl;return 0;}

, o que retorna:Area do Retangulo1: 12Area do Retangulo2: 3011.3 Construtores Sobrecarregados

Como qualquer outra função, um construtor também pode ser sobrecarregado com mais deuma função que tenha o mesmo nome mas tipos ou números de parâmetros diferentes. Lembre-se que para funções sobrecarregadas, o compilador chamará aquele cujos parâmetros batam

92

Page 94: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

com os argumentos usados na chamada da função. No caso dos construtores, que são chamadosautomaticamente quando o objeto é criado, o executado será aquele que bata com os argumentospassados na declaração do objeto.#in lude <iostream>using namespa e std; lass Retangulo{int omprimento, altura;publi :Retangulo ();Retangulo (int,int);int area (void) {return ( omprimento*altura);}};Retangulo::Retangulo () { omprimento = 5;altura = 5;}Retangulo::Retangulo (int a, int b) { omprimento = a;altura = b;}int main () {Retangulo retang (3,4);Retangulo retang2; out << "Area do Retangulo1: " << retang.area() << endl; out << "Area do Retangulo2: " << retang2.area() << endl;return 0;}

, o que retorna:Area do Retangulo1: 12Area do Retangulo2: 25Neste caso, retang foi declarado sem nenhum argumento então foi inicializado com o constru-

tor que não tem parâmetros, que inicializa ambos comprimento e altura com o valor de 5.

IMPORTANTE: Note que se declaramos um novo objeto e quisermos usar seu construtor pa-drão (sem parâmetros), não incluímos parênteses ():Retangulo retang; // ertoRetangulo retang2(); // errado!

93

Page 95: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

11.4 Construtor Padrão

Se não declararmos nenhum construtor na definição da classe, o compilador assume que aclasse tenha um construtor padrão sem argumentos. Assim, após declarar uma classe comoesta: lass CExemplo {publi :int a,b, ;void multiplo (int n, int m) { a=n; b=m; =a*b; };};

O compilador assume que Exemplo tem um construtor padrão, então podemos declarar obje-tos desta classe simplesmente declarando-os sem argumentos:CExemplo ex;

Entretanto, assim que declaramos nosso próprio construtor, o compilador não mais forneceum construtor padrão implícito. Devemos, com isso declarar objetos daquela classe de acordocom o protótipo do construtor que definimos para a classe: lass CExemplo {publi :int a,b, ;CExemplo (int n, int m) { a=n; b=m; };void multiplo () { =a*b; };};

Aqui declaramos um construtor que recebe 2 parâmetros do tipo int. Então a seguinte decla-ração de objeto seria correta:CExemplo ex (2,3);

mas,CExemplo ex;Não seria correto pois declaramos a classe para ter um construtor explícito, deste modo subs-

tituindo o construtor padrão. O compilador, entretanto, não apenas cria um construtor padrão senão especificarmos um, como também fornece três funções membro especiais no total que sãoimplicitamente declaradas se não declararmos as nossas. São elas o construtor cópia, a cópiado operador de atribuição e o destrutor padrão.

O construtor cópia e a cópia do operador de atribuição copiam todos os dados contidos em outroobjeto para os dados membros do objeto atual. Para CExemplo, o construtor cópia implicitamentedeclarados pelo compilador seriam algo similar a:Cexemplo::Cexemplo ( onst CExample& rv) {a=rv.a; b=rv.b; =rv. ;}

94

Page 96: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Então, as duas declarações de objetos seguintes seriam corretas:CExemplo ex (2,3);CExemplo ex2 (ex); // onstrutor ópia (dados opiados de ex)Ponteiros para Classes

Em C++ podemos criar ponteiros que apontam para classes. Simplesmente consideramos que,uma vez declaradas, classes se tornam tipos válidos, então podemos usar o nome da classecomo o tipo do ponteiro. Assim:Retangulo * pretang;

é um ponteiro para um objeto da classe Retangulo

Como acontece com estruturas de dados, para nos referirmos diretamente a um membro deum objeto apontado por um ponteiro, podemos usar o operador flecha (->) de direção. Mostrareium exemplo com algumas possíveis combinações:#in lude <iostream>using namespa e std; lass Retangulo {int omprimento, altura;publi :void seta_valores (int, int);int area (void) {return ( omprimento * altura);}};void Retangulo::seta_valores (int a, int b) { omprimento = a;altura = b;}int main () {Retangulo a, *b, * ;Retangulo * d = new Retangulo[2℄;b= new Retangulo; = &a;a.seta_valores (1,2);b->seta_valores (3,4);d->seta_valores (5,6);d[1℄.seta_valores (7,8); out << "Area de a : " << a.area() << endl; out << "Area de *b : " << b->area() << endl; out << "Area de * : " << ->area() << endl; out << "Area de d[0℄ : " << d[0℄.area() << endl; out << "Area de d[1℄ : " << d[1℄.area() << endl;delete[℄ d;

95

Page 97: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFdelete b;return 0;}, o que retorna na tela:Area de a : 2Area de *b : 12Area de * : 2Area de d[0℄ : 30Area de d[1℄ : 56A seguir temos um sumário onde mostramos como podemos ler alguns operadores entre

ponteiro e classes que aparecem no exemplo anterior:

expressão pode ser lida como*x apontado por x&x endereço de xx.y membro y do objeto xx->y membro y do objeto apontado por x(*x).y membro y do objeto apontado por x (equivalente ao anterior)x[0] primeiro objeto apontado por xx[1] segundo objeto apontado por xx[n] "enésimo mais um"(n+1) objeto apontado por x

Certifique-se de que você entenda a lógica de todas essas expressões antes de avançar àspróximas lições. Se tiver dúvidas, leia novamente esta seção e/ou consulte lições anteriores sobreponteiros e estruturas de dados.

11.5 Classes definidas com struct e union

Classes podem ser definidas não apenas com a palavra-chave class, mas também com aspalavras0chave struct e union. Os conceitos de classe e estruturas de dados são tão similaresque ambas struct e class podem ser usadas em C++ para declarar classes. A única diferençaentre ambos é que membros de classes declarados com a palavra struct têm acesso public pordefault (padrão), enquanto membros de classes declarados com a palavra class têm acesso pri-vate.

O conceito de union é diferente do de classe declarada com struct e class, já que unions apenasarmazenam um dado membro por vez. Todavia são também classes e com isto também podemcarregar funções membro. O acesso default em classes union é public.

11.6 Sobrecarregando Operadores

Em C++ podemos usar operadores padrão para realizar operações com classes em adição aoperações com tipos fundamentais. Veja o seguinte código:

96

Page 98: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFstru t {string produ t;float pri e;} a, b, ;a = b + ;Fazermos isto causaria um erro de compilação, já que não definimos o comportamento que

nossa classe deve ter com operações de adição. Entretanto, graças ao uso de operadores sobre-carregados (overloaded operators) do C++, podemos criar classes capazes de realizar operaçõesusando operadores padrão. A seguir está uma lista de todos os operadores que podem ser so-brecarregados:Overloadable operators+ - * / = < > += -= *= /= << >><<= >>= == != <= >= ++ -- % & ^ ! |~ &= ^= |= && || %= [℄ () , ->* -> newdelete new[℄ delete[℄

Para sobrecarregar um operador de maneira que os usemos com classes, declaramos funçõesde operadores, que são funções comuns cujos nomes são a palavra-chave do operador seguidapelo símbolo do operador que queremos sobrecarregar. Desta maneira:[tipo℄ [operador℄ [simbolo℄ (parametros) { /*...*/ }

A seguir temos um exemplo que sobrecarrega o operador de adição (+). Criaremos umaclasse para armazenar vetores bidimensionais e então iremos adicionar dois deles: a(3,1) eb(1,2). Para fazermos a adição de dois vetores bidimensionais adicionamos as duas coorde-nadas em x para obter a coordenada resultante x e adicionamos as duas coordenadas em y paraobter o y resultante. Neste caso, o resultado será (3+1,1+2) = (4,3).#in lude <iostream>using namespa e std; lass Vetor {publi :int x,y;Vetor () {};Vetor (int,int);Vetor operador+ (Vetor);};Vetor::Vetor (int a, int b) {x = a;y = b;}Vetor Vetor::operador+ (Vetor param) {Vetor temp;

97

Page 99: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFtemp.x = x + param.x;temp.y = y + param.y;return (temp);}int main () {Vetor a (3,1);Vetor b (1,2);Vetor ; = a + b; out << .x << "," << .y;return 0;}, o que resulta:4,3Deve ser um pouco confuso ver o identificador Vetor tantas vezes no código, mas considere

que alguns deles se referem ao nome da classe (tipo) Vetor e alguns são funções com aquelenome, já que construtores devem ter o mesmo nome da classe. Não os confunda:Vetor (int, int); // nome da função Vetor ( onstrutor)Vetor operador+ (Vetor ); // função retorna um Vetor

A função operador+ da classe Vetor é quem está a cargo de sobrecarregar o operador deadição (+). Esta função pode ser chamada tanto implicitamente usando o operador ou explicita-mente, usando o nome da função. Ambas as expressões são equivalentes: = a + b; = a.operador+ (b);

Ainda naquele exemplo anterior, note também que incluímos o construtor vazio (sem parâme-tros) e o definimos com um bloco vazio:Vetor () { };

Isto é necessário, já que declaramos explicitamente outro construtor:Vetor (int, int);Deve ser um pouco confuso ver o identificador Vetor tantas vezes no código, mas considere

que alguns deles se referem ao nome da classe (tipo) Vetor e alguns são funções com aquelenome, já que construtores devem ter o mesmo nome da classe. Não os confunda:Vetor (int, int); // nome da função Vetor ( onstrutor)Vetor operador+ (Vetor ); // função retorna um Vetor

A função operador+ da classe Vetor é quem está a cargo de sobrecarregar o operador deadição (+). Esta função pode ser chamada tanto implicitamente usando o operador ou explicita-mente, usando o nome da função. Ambas as expressões são equivalentes:

98

Page 100: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF = a + b; = a.operador+ (b);Ainda naquele exemplo anterior, note também que incluímos o construtor vazio (sem parâme-

tros) e o definimos com um bloco vazio:Vetor () { };Isto é necessário, já que declaramos explicitamente outro construtor:Vetor (int, int);E quando declaramos explicitamente algum construtor, com qualquer número de parâmetros,

o construtor padrão sem parâmetros que o compilador pode declarar automaticamente não édeclarado, então nós mesmos precisamos declará-los de maneira que possamos construir objetosdeste tipo sem parâmetros. Senão, a declaração:Vetor ;

incluida no main() não seria válida.

De qualquer modo, temos que frisar que um bloco vazio é uma má implementação para um cons-trutor, já que não preenche a funcionalidade mínima que geralmente é esperada de um construtor,que é a inicialização de todas as variáveis membro em sua classe. No nosso caso, este construtordeixa x e y indefinidas. Para isso, uma definição mais aconselhável seria algo assim:Vetor () { x=0; y=0; };

que, para simplificar e mostrar apenas o ponto do código, não mostramos no exemplo.

Da mesma maneira que uma classe inclui um construtor padrão e um construtor cópia mesmoque eles não são declarados, também inclui uma definição padrão para o operador de atribuição(=) com a classe em si como parâmetro. O comportamento que é definido por default é copiar oconteúdo inteiro dos dados membro do objeto passado como argumento (à direita do sinal) parao do lado esquerdo.Vetor d (2,3);Vetor e;e = d; // operador de atribuição ópia

A função operador de atribuição cópia é a única função operador membro implementada pordefault. Claro que podemos redefini-las para qualquer funcionalidade que queiramos, como porexemplo, copia apenas certas classes membro ou realizar procedimentos de inicialização adicio-nais.

A sobrecarga de operadores não força sua operação a suportar uma relação de sentido ma-temático ou usual do operador, apesar de ser recomendado. Por exemplo, o código não deve sermuito intuitivo se usarmos o operador + para subtrair duas classes ou operador== para preenchercom zeros uma classe, apesar de ser perfeitamente possível fazer isto.

99

Page 101: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Apesar de o protótipo de uma função operador+ poder parecer óbvio já que ele toma o queestá do lado direito do operador como parâmetro para a função operador membro do objeto dolado esquerdo, outras operações podem não ser tão óbvias. Aqui temos uma tabela com um su-mário de como as diferentes funções operadores membro têm de ser declaradas (troque @ pelooperador em cada caso):

Expressão Operador Função membro Função Global@a + - * & ! ~++ – A::operador@() operador@(A)a@ ++ – A::operador@(int) operador@(A,int)a@b + - * / % ^& | < > == A::operador@ (B) operador@(A,B)

!= <= >= « » && || ,a@b = += -= *= /= %= ^= A::operador@ (B) -

&= |= «= »= []a(b, c...) () A::operador() (B, C...) -a->x -> A::operador->() -

Onde a é um objeto da classe A, b é um objeto da classe C e c é um objeto da classe C.

Como podemos ver, existem duas maneiras de sobrecarregar alguns operadores de classe: comouma função membro e como uma função global. Seu uso é indistinto, todavia devo ressaltar quefunções que não são membros de uma classe não podem acessar membros private ou protecteddaquela classe a menos que a função global seja seu friend (friendship será explicada na lição aseguir).

11.7 Friendship e Herança

11.7.1 Funções Friend

A princípio, membros private e protected de uma classe não podem ser acessados de forade uma mesma classe na qual são declaradas. Entretanto, esta regra não afeta friends. Sequisermos declarar uma função externa a uma classe como friend, deste modo permitindo queesta função acesse membros private e protected desta classe, declaramos um protótipo destafunção externa na classe, e a precedemos com a palavra chave friend, como a seguir:#in lude <iostream>using namespa e std; lass Retangulo {int omprimento, altura;publi :void seta_valores (int, int);int area () {return ( omprimento * altura);}friend Retangulo opia (Retangulo);};void Retangulo::seta_valores (int a, int b) { omprimento = a;altura = b;

100

Page 102: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF}Retangulo opia (Retangulo retangparam){Retangulo retangres;retangres. omprimento = retangparam. omprimento*2;retangres.altura = retangparam.altura*2;return (retangres);}int main () {Retangulo retang, retangb;retang.seta_valores (2,3);retangb = opia (retang); out << retangb.area();return 0;}, o que retorna o valor 24.

A função copia é friend de Retangulo. Daquela função, somos também capazes de acessaros membros comprimento e altura de objetos diferentes do tipo Retangulo, que são membros pri-vate. Note que nem na declaração de copia() nem em seu uso posterior em main() consideramoscopia um membro da classe Retangulo. E não é. Simplesmente tem acesso a seus membrosprivate e protected sem ser um membro.

Funções friend podem servir, por exemplo, para conduzir operações entre duas classes dife-rentes. Geralmente, o uso de funções friend está fora de uma metodologia POO, então sempreque possível é melhor utilizar membros da mesma classe para relizar operações com eles. Assim,no exemplo anterior, seria mais curto integrar copia() na classe Retangulo.

Classes Friend

Podemos ainda definir alguma classe como friend de alguma outra, garantindo que a primeiratenha acesso sos membros protected e private da segunda.#in lude <iostream>using namespa e std; lass Pra a; lass Retangulo {int omprimento, altura;publi :int area (){return ( omprimento * altura);}void onverte (Pra a a);};

101

Page 103: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF lass Pra a {private:int lado;publi :void seta_lado (int a){lado=a;}friend lass Retangulo;};void Retangulo:: onverte (Pra a a) { omprimento = a.lado;altura = a.lado;}int main () {Pra a sq;Retangulo retang;sq.seta_lado(4);retang. onverte(sq); out << retang.area();return 0;}, o que retorna o valor 16.

Neste exemplo, declaramos Retangulo como uma classe friend de Praca para que funções mem-bro de Retangulo possam acessar os membros protected e private de Praca, mais concretamentePraca::lado. Vemos também uma declaração vazia de Praca no começo do programa. Isto énecessário pois, na declaração de Retangulo, nos referimos a Praca (como um parâmetro emconverte()). A definição de Praca é incluída depois, então se não incluirmos uma declaração va-zia anterior para Praca, esta classe não seria visível na definição de Retangulo.

Perceba que friends não são correspondidas se não especificarmos isso explicitamente. Nonosso exemplo, Retangulo é considerada uma classe friend por Praca, mas Retangulo não con-sidera Praca uma friend. Com isso, Retangulo pode acessar os membros private e protected dePraca, mas não o caminho contrário. Claro que poderíamos ter declarado também Praca comofriend de Retangulo se assim preferirmos.

Outra propriedade de friends é que elas não são transitivas: a friend de uma friend não é consi-derada friend a não ser que seja especificado.

Herança entre classes

Uma funcionalidade geral da POO é a herança entre classes. Em C++ não é diferente. He-rança permite criar classes que são derivadas de outras classes, então elas automaticamenteincluem alguns membros "pai", além de si mesmas. Por exemplo, suponha que queremos decla-rar uma série de classes que descrevem polígonos como nossa Retangulo, ou como Triangulo.Elas têm certas propriedades em comum, já que ambas podem ser descritas por meio de dois

102

Page 104: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

lados: altura e base.

Isto pode ser representada no mundo das classes com uma classe Poligono de onde podemosderivar as outras duas: Retangulo e Triangulo. A Classe Poligono conteria membros que são co-muns para ambos os dois tipos de poligonos. No nosso caso: altura e comprimento. E Retanguloe Triangulo seriam suas classes derivadas, que especificam funcionalidades que são diferentesde um tipo de polígono para o outro.

Classes que são derivadas de outras herdam todos os membros acessíveis da classe base(classe mãe, ou classe pai). Isso significa que se uma classe base inclui um membro A e quere-mos derivá-la a uma outra classe com um outro membro chamado B, a classe derivada conteráambos A e B.

Para derivar uma classe à outra, usamos o dois-pontos ( : ) na declaração da classe derivada, noseguinte formato: lass [nome_da_ lasse_derivada℄: publi [nome_da_ lasse_base℄{ /*...*/ };

O especificador de acesso public pode ser trocado por qualquer um dos especificadores pro-tected e private. Este especificador de acesso descreve o nível de acesso mínimo para membrosque são herdados da classe base.#in lude <iostream>using namespa e std; lass Poligono {prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b;}}; lass Retangulo: publi Poligono {publi :int area (){ return ( omprimento * altura); }}; lass Triangulo: publi Poligono{publi :int area (){ return ( omprimento * altura / 2); }};int main () {Retangulo retang;Triangulo trgl;

103

Page 105: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFretang.seta_valores (4,5);trgl.seta_valores (4,5); out << retang.area() << endl; out << trgl.area() << endl;return 0;}, o que retorna:2010Os objetos das classes Retangulo e Triangulo contêm, cada, membros herdados de Poligono.

São eles: comprimento, altura e seta_valores(). O especificador de acesso protected é similarao private. A única diferença ocorre, na verdade, com a herança. Quando uma classe herda deoutra, os membros dal classe derivada podem acessar membros protected herdados da classebase, mas não seus membros private.

Como queríamos que comprimento e altura fossem acessíveis de membros da classes deriva-das Retangulo e Triangulo e não apenas membros de Poligono, temos que usar protected aoinvés de private.

Podemos resumir os diferentes tipos de acesso de acordo com quem pode acessá-los da se-guinte maneira:

Acesso public protected privatemembros da mesma classe sim sim simmembros de classes derivadas sim sim nãonão membros sim não não

Onde "não membros"representam qualquer acesso de fora da classe, como de main(), deuma outra classe ou função. No nosso exemplo, os membros herdados por Retangulo e Triangulotêm as mesmas permissões de acesso que tinham em sua classe base Poligono.Poligono:: omprimento // a esso prote tedRetangulo:: omprimento // a esso prote tedPoligono::seta_valores() // a esso publi Retangulo::seta_valores() // a esso publi

Por isso tivemos que usar a palavra-chave public para definir relação de herança a cada umadas classes derivadas: lass Retangulo: publi Poligono { ... }

Esta palavra-chave depois dos dois-pontos ( : ) denota o nível de acesso máximo para todosos membros herdados da classe que o segue (neste caso, Poligono). Como public é o nível maisacessível, especificando esta palavra-chave a classe derivada herda todos os membros com osmesmos níveis que eles tinham na classe base. Se especificarmos um nível de acesso mais res-trito como protected, todos os membros public da classe base são herdados como protected na

104

Page 106: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

classe derivada. Também, se especificarmos o mais restrito dos níveis de acesso, private, todosos membros da classe base são herdados como private.

Por exemplo, uma classe mae é definida como: lass filha: prote ted mae;, onde filha é uma classe derivada de mae. Isto setaria protected como o nível de acesso

máximo para os membros de filha herdados de mae. Isto é, todos os membros que forem publicem mae se tornarão protected em daughter. Claro que isto não restringiria filha de declarar seuspróprios membros public. Este nível de acesso máximo é apenas setado para os membros her-dados de mae.

Se não explicitarmos nenhum nível de acesso para a herança, o compilador assume private paraclasses declaradas com a palavra-chave class e public para aquelas declaradas com struct.

O que é herdado da classe base?

A princípio, uma classe derivada herda todo membro de uma classe base, exceto:

• seu construtor e destrutor

• seus membros de operador=()

• seus friends

Apesar de os construtores e destrutores da classe base não serem herdados si mesmas, seuconstrutor padrão (sem parâmetros) e seu destrutor são sempre chamados quando um novo ob-jeto de uma classe derivada é criado ou destruido.

Se a classe base não tem um construtor padrão ou queremos que um construtor sobrecarre-gado seja chamado quando um novo objeto derivado é criado, podemos especificá-lo em cadadefinição de construtor da classe derivada:[nome_do_ onstrutor_derivado℄ (parametros) : [nome_do_ onstrutor_base℄(parametros) {...}

Exemplo:#in lude <iostream>using namespa e std; lass mae{publi :mae (){ out << "Mae: sem parametros\n"; }mae (int a){ out << "Mae: Parametro int\n"; }};105

Page 107: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF lass filha : publi mae{publi :filha (int a){ out << "filha: Parametro int\n\n"; }}; lass filho : publi mae {publi :filho (int a) : mae (a){ out << "filho: Parametro int\n\n"; }};int main () {filha ynthia (0);filho daniel(0);return 0;}, o que retorna:mae: no parametersfilha: int parametermae: int parameterfilho: int parameterNote que a diferença entre qual construtor ’mae’ é chamado quando um novo objeto filha é

criado e qual é chamado quando é um objeto filho. A diferença é entre a declaração do construtorde filha e filho:filha (int a) // nada espe ifi ado: hamada padraofilho (int a) : mae (a) // onstrutor espe ifi ado: hama este11.8 Herança Múltipla

É perfeitamente possível que uma classe herde membros de mais de uma classe. Isto éfeito simplesmente separando as diferentes classes base com vírgulas na declaração da classederivada. Por exemplo, se tivermos uma classe específica para imprimir na tela (COutput) equisermos que nossas classe Retangulo e Triangulo também herdem seus membros em adiçãoàqueles de Poligono, poderíamos escrever: lass Retangulo: publi Poligono, publi COutput; lass Triangulo: publi Poligono, publi COutput;

, aqui temos um exemplo completo:

106

Page 108: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#in lude <iostream>using namespa e std; lass Poligono {prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b;}}; lass COutput {publi :void saida (int i);};void COutput::saida (int i) { out << i << endl;} lass Retangulo: publi Poligono, publi COutput {publi :int area (){ return ( omprimento * altura); }}; lass Triangulo: publi Poligono, publi COutput {publi :int area (){ return ( omprimento * altura / 2); }};int main () {Retangulo retang;Triangulo trgl;retang.seta_valores (4,5);trgl.seta_valores (4,5);retanng.saida (retang.area());trgl.output (trgl.area());return 0;}11.9 Polimorfismo

Ponteiros para classes base

Uma das funcionalidades principais de classes derivadas é que um ponteiro para uma classe

107

Page 109: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

derivada é compatível tipamente com um ponteiro para esta classe base. Polimorfismo é a artede tirar vantagem dessa funcionalidade. Começaremos reescrevendo nosso programa sobre oretângulo e o triângulo da seção anterior considerando esta propriedade de compatibilidade deponteiros:#in lude <iostream>using namespa e std; lass Poligono {prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b; }}; lass Retangulo: publi Poligono {publi :int area (){ return ( omprimento * altura); }}; lass Triangulo: publi Poligono {publi :int area (){ return ( omprimento * altura / 2); }};int main () {Retangulo retang;Triangulo trgl;Poligono * poli1 = &retang;Poligono * poli2 = &trgl;poli1->seta_valores (4,5);poli2->seta_valores (4,5); out << retang.area() << endl; out << trgl.area() << endl;return 0;}

, o que mostra na tela:2010Na função main, criamos dois ponteiros que apontam para objetos da classe Poligono (poli1

e poli2), então atribuímos referências para retang e trgl a esses ponteiros, e como ambas sãoobjetos de classes derivadas de Poligono, são atribuições válidas.

108

Page 110: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

A única limitação em usar *poli1 e *poli2 ao invés de retang e trgl é que ambos *poli1 e *poli2 sãodo tipo Poligono* e assim apenas podemos usar estes ponteiros para nos referirmos a membrosque Retangulo e Triangulo herdam de Poligono. Por esta razão quando chamamos os membrosde area() no final do programa, temos que usar diretamente os objetos retang e trgl ao invés dosponteiros *pont1 e *pont2.

Para usar area() com os ponteiros para a classe Poligono, este membro também deve ter sido de-clarado na classe Poligono, e não apenas nas suas classes derivadas, mas o problema é que Re-tangulo e Triangulo implementam versões diferentes de area. Assim, não podemos implementá-lona classe base. Aí os membros virtuais vêm a calhar.

Membros Virtuais

Um membro de uma classe que pode ser redefinido em suas classes derivadas é conhecidocomo um membro virtual. Para declarar um membro de uma classe como virtual, devemos pre-ceder sua declaração com a palavra-chave virtual:#in lude <iostream>using namespa e std; lass Poligono {prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b; }virtual int area (){ return (0); }}; lass Retangulo: publi Poligono {publi :int area (){ return ( omprimento * altura); }}; lass Triangulo: publi Poligono {publi :int area (){ return ( omprimento * altura / 2); }};int main () {Retangulo retang;Triangulo trgl;Poligono poli;Poligono * poli1 = &retang;Poligono * poli2 = &trgl;

109

Page 111: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFPoligono * poli3 = &poli;poli1->seta_valores (4,5);poli2->seta_valores (4,5);poli3->seta_valores (4,5); out << poli1->area() << endl; out << poli2->area() << endl; out << poli3->area() << endl;return 0;}, o que mostra na tela:20100Agora as três classes têm todas os mesmos membros: comprimento, altura, seta_valores()

e area(). A função membro area() foi declarada como virtual na classe base pois é redefinidadepois em cada classe derivada. Podemos verificar se removermos essa palavra-chave virtualda declaraç ao de area() em Poligono, e rodarmos o programa o resultado será 0 para os três po-lígonos ao invés de 20, 10 e 0. Isso porque ao invés de chamar a função area() correspondentepara cada objeto (CRectangle::area(), Triangulo::area() and Poligono::area(), respectivamente),Poligono::area() será chamado em todos os casos, já que as chamadas são via ponteiro cujo tipoé Poligono.

Então, o que a palavra-chave virtual faz é permitir a um membro de uma classe derivada como mesmo nome de um na classe base seja apropriadamente chamado a partir de um ponteiro, emais precisamente quando o tipo do ponteiro é um ponteiro para a classe base, mas está apon-tando para um objeto da classe derivada, como no exemplo acima.

Uma classe que declara ou herda uma função virtual é chamada uma classe polimórfica. Noteque apesar de sua virtualidade, também fomos capazes de declarar um objeto do tipo Poligono echamar sua própria função area(), que sempre retorna 0.

Classes base abstratas

Classes base abstratas são algo parecido a nossa classe Poligono do exemplo anterior, coma diferença que neste definimos uma função area() válida com uma funcionalidade mínima paraobjetos que eram da classe Poligono (como poli), onde em uma classe base abstrata poderíamosdeixar que a função membro area() ficasse sem implementação. Isto poderia ser feito anexando=0 (igual a zero) á declaração da função. Uma classe base abstrata Poligono poderia ser algoassim: lass Poligono {prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b; }

110

Page 112: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFvirtual int area () =0;};Note que adicionamos =0 ao int area() virtual ao invés de especificar uma implementação para

a função.Este tipo de função é chamado uma função virtual pura, e todas as classes que contémno mínimo uma função virtual pura são classes base abstratas.

A principal diferença entre uma classe base abstrata e uma classe polimórfica normal é que,nas primeiras, no mínimo um de seus membros carece de implementações as quais não pode-mos criar instâncias.

Entretanto, uma classe que não pode instanciar objetos não é totalmente inútil. Podemos criarponteiros para ela e tirar vantagem de todas suas habilidades polimórficas. Assim,Poligono poli;

não seria válida para a classe base abstrata que acabamos de declarar, pois tenta instanciarum objeto. Apesar disto, os seguintes ponteiros seriam válidos:Poligono * poli1;Poligono * poli2;

Isto é assim durante o tempo que Poligono inclui uma função virtual puta e com isso não é umaclasse base abstrata. No entanto, ponteiros para essa classe base abstrata podem ser usadospara apontar para objetos de classes derivadas. Exemplo completo:#in lude <iostream>using namespa e std; lass Poligono{prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b; }virtual int area (void) =0;}; lass Retangulo: publi Poligono {publi :int area (void){ return ( omprimento * altura); }}; lass Triangulo: publi Poligono {publi :int area (void){ return ( omprimento * altura / 2); }};

111

Page 113: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFint main () {Retangulo retang;Triangulo trgl;Poligono * poli1 = &retang;Poligono * poli2 = &trgl;poli1->seta_valores (4,5);poli2->seta_valores (4,5); out << poli1->area() << endl; out << poli2->area() << endl;return 0;}, o que mostra na tela:2010Se revisarmos o programa, notaremos que nos referimos a objetos de uma classe diferente

mas relacionada, usando um único tipo de ponteiro (Poligono*). Isto pode ser tremendamenteútil. Por exemplo, agora podemos criar uma função membro da classe base abstrata Poligonoque é capaz de imprimir na tela o resultado da função area() mesmo que Poligono em si nãotenha nenhuma implementação para esta função:#in lude <iostream>using namespa e std; lass Poligono {prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b; }virtual int area (void) =0;void imprimearea (void){ out << this->area() << endl; }}; lass Retangulo: publi Poligono {publi :int area (void){ return ( omprimento * altura); }}; lass Triangulo: publi Poligono {publi :int area (void){ return ( omprimento * altura / 2); }};

112

Page 114: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFint main () {Retangulo retang;Triangulo trgl;Poligono * ppoly1 = &retang;Poligono * ppoly2 = &trgl;poli1->seta_valores (4,5);poli2->seta_valores (4,5);poli1->imprimearea();poli2->imprimearea();return 0;}, o que mostra na tela:2010Membros virtuais e classes abstratas garantem as características polimórficas de C++ e fa-

zem POO um instrumento tão útil em grandes projetos. Claro que vimos usos muito simplesdestas estruturas mas essas funcionalidades podem ser aplicadas a arrays de objetos ou objetosdinamicamente alocados. Vamos finalizar POO com o mesmo exemplo, desta vez alocando osobjetos dinamicamente:// alo ação dinâmi a e polimorfismo#in lude <iostream>using namespa e std; lass Poligono {prote ted:int omprimento, altura;publi :void seta_valores (int a, int b){ omprimento=a; altura=b; }virtual int area (void) =0;void imprimearea (void){ out << this->area() << endl; }}; lass Retangulo: publi Poligono {publi :int area (void){ return ( omprimento * altura); }}; lass Triangulo: publi Poligono {publi :int area (void){ return ( omprimento * altura / 2); }

113

Page 115: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF};int main () {Poligono * poli1 = new Retangulo;Poligono * poli2 = new Triangulo;poli1->seta_valores (4,5);poli2->seta_valores (4,5);poli1->imprimearea();poli2->imprimearea();delete poli1;delete poli2;return 0;}, o que retorna na tela:2010Note que os ponteiros poli:Poligono * poli1 = new Retangulo;Poligono * poli2 = new Triangulo;são declarados como sendo do tipo ponteiro para Poligono, mas os objetos dinamicamente

alocados foram declarados como tendo o tipo da classe derivada diretamente.

114

Page 116: Programacao cpp

Capítulo 12

Templates, Namespaces

12.1 Templates

Funções Template

São funções especiais que podem operar com tipos genéricos. Isto nos permite criar uma funçãotemplate cuja funcionalidade pode ser adaptada a mais de um tipo ou classe sem repetir o có-digo inteiro para cada tipo. Podemos atingir isso usando parmâmetros template. Um parâmetrotemplate é um tipo especial de parâmetro que pode ser usado para passar um tipo como argu-mento: da mesma maneira que parâmetros de funções normais podem ser usados para passarvalores para uma função, parâmetros template permite que passemos também tipos para umafunção. Estas funções templates podem usar estes parâmetros como se fossem qualquer outrotipo comum. Seu formato é:template < lass identifi ador> [de lara ao_da_fun ao℄;template <typename identifi ador> [de lara ao_da_fun ao℄;

OBS: A única diferença entre os dois protótipos é o uso tanto da palavra-chave class ou dapalavra-chave typename. Seu uso é indistinto, já que ambas as expressões têm exatamente omesmo significado e se comportam da mesma maneira.

Por exemplo, para criar uma função template que retorna o maior de dois objetos podemos usar:template < lass meuTipo>meuTipo tMaior (meuTipo a, meuTipo b) {return (a>b?a:b);}Aqui criamos uma função template com meuTipo como seu parâmetro template. Ele repre-

senta um tipo que ainda não foi especificado, mas pode ser usado na função template como seele fosse um tipo comum. Como podemos ver, a função template tMaior retorna o maior de doisparâmetros deste tipo ainda indefinido.

Para usar esta função template, usamos o formato para a função de chamada:[nome_da_fun ao℄ <tipo> (parametros);115

Page 117: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Por exemplo, para chamarmos tMaior para comparar dois valores inteiros do tipo int, podemosescrever:int x,y;tMaior <int> (x,y);

Quando o compilador encontra esta chamada à função template, ele usa o template para gerarautomaticamente uma função trocando cada apararição de meuTipo pelo tipo passado como oatual parâmetro do template (no caso, int) e então chamá-lo. Por ser realizado pelo compilador, éum processo invisível ao programador.Exemplo completo:#in lude <iostream>using namespa e std;template < lass T>T tMaior (T a, T b) {T resultado;resultado = (a>b)? a : b;return (resultado);}int main () {int i=5, j=6, k;long l=10, m=5, n;k=tMaior<int>(i,j);n=tMaior<long>(l,m); out << k << endl; out << n << endl;return 0;}

, o que retorna na tela:610Neste caso, usamos T como o nome do parâmetro template ao invés de meuTipo porque é

menor e na verdade é um nome comum de um parâmetro template. Entretanto, podemos usarqual identificador quisermos. Note também que usamos a função template tMaior() duas vezes.A primeira com argumentos do tipo int e a segunda com argumentos do tipo long. O compiladorinstanciou e então chamou cada vez a versão apropriada da função.

Como podemos ver, o tipo T é usado na função template tMaior() até para declarar novos ob-jetos daquele tipo:T resultado;

116

Page 118: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Assim, resultado será um objeto do mesmo tipo que os parâmetros a e b quando a funçãotemplate é instanciada com um tipo específico. Neste caso específico, onde o tipo genérico T éusado como um parâmetro para tMaior o compilador pode perdeber automaticamente qual tipode dado tem que instanciar sem ter que explicitamente especificar isso entre < e >. Poderíamos,então, ter escrito no lugar:int i,j;tMaior (i,j);

Já que ambos i e j são do tipo int, e o compilador pode perceber automaticamente que oparâmetro template pode ser apenas int. Este método implícito produz exatamente o mesmoresultado:#in lude <iostream>using namespa e std;template < lass T>T tMaior (T a, T b) {return (a>b?a:b);}int main () {int i=5, j=6, k;long l=10, m=5, n;k=tMaior(i,j);n=tMaior(l,m); out << k << endl; out << n << endl;return 0;}

, o que retorna na tela:610Note como neste caso chamamos nossa função template tMaior() sem especificar explicita-

mente o tupo entre <>. O compilador automaticamente determina que tipo é necessário em cadachamada. Como nossa função template inclui apenas um parâmetro template (class T) e a fun-ção template em si aceita dois, ambos do tipo T, nao podemos chamar nossa função com doisobjetos de diferentes tipos como argumento:int i;long l;k = tMaior (i,l);

Isto seria incorreto, já que nossa função template tMaior espera dois argumentos do mesmotipo, e neste chamada usamos dois parâmetros de tipos diferentes.

Também podemos definir funções templates que aceitam mais de um tipo de parâmetro, sim-plesmente especificando mais parâmetros template entre os <>. Assim:

117

Page 119: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFtemplate < lass T, lass U>T tMenor (T a, U b) {return (a<b?a:b);}Aqui, tMenor() aceita dois parâmetros de tipos diferentes e retorna um objeto do mesmo tipo

que o primeiro parâmetro (T) que é passado. Por exemplo, após a declaração poderíamos chamartMenor() com:int i,j;long l;i = tMenor<int,long> (j,l);

ou simplesmente:i = tMenor (j,l);mesmo que j e l tenham tipos diferentes, já que o compilador pode determinar a instanciação

apropriada de qualquer modo.

Classes templates

Ainda podemos escrever classes templates, de maneira que uma classe pode ter membros queusam parâmetros template como tipos. Por exemplo:template < lass T> lass mPar {T valores [2℄;publi :mPar (T primeiro, T segundo){valores[0℄=primeiro; valores[1℄=segundo;}};

A classe que acabamos de definir serve para armazenar dois elementos de qualquer tipo vá-lido. Por exemplo, se quiséssemos declarar um objeto desta classe para armazenar dois valoresinteiros do tipo int com os valores 115 e 36, escreveríamos:mPar<int> mObjeto (115, 36);

Esta mesma classe também seria usada para criar um objeto para armazenar qualquer outrotipo: mPar<double> mFloats (3.0, 2.18);

A única função membro na a classe template anterior foi definida em linha com a declaraçãoda classe em si. No caso em que definimos uma função membro fora da declaração da classetemplate, devemos sempre preceder aquela definição com o prefixo template <...>

118

Page 120: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#in lude <iostream>using namespa e std;template < lass T> lass mPar {T a, b;publi :mPar (T primeiro, T segundo){a=primeiro; b=segundo;}T tmaior();};template < lass T>T mPar<T>::tmaior (){T retval;retval = a>b? a : b;return retval;}int main () {mPar <int> mObjeto (100, 75); out << mObjeto.tmaior();return 0;}, o que retorna o valor 100.

Note que a sintaxe da definição da função membro tmaior:template < lass T>T mPar<T>::tmaior ()No código, talvez podemos nos confundir com os tantos T’s, por isso explico novamente o

que é cada um: o primeiro é o parâmetro template. O segundo se refere ao tipo retornado pelafunção. E o terceiro, entre <>, também é um requerimento, e especifica que este parâmetro dafunção template também é um parâmetro da classe template.

Especialização do template

Se quisermos definir uma implementação diferente para um template quando um tipo específico épassado como um parâmetro template, podemos declarar uma especialização daquele template.Por exemplo, vamos supor que temos uma classe muito simples chamada mcontainer que podearmazenar um elemento de qualquer tipo e que tem uma função membro chamada incrementa.Percebemos, entretanto, que ao armazenar um elemento do tipo char seria mais conveniente teruma implementação completamente diferente, com uma função membro letramaiuscula, entãodecidimos declarar uma especialização da classe template para aquele tipo:// espe ializaçao do template

119

Page 121: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#in lude <iostream>using namespa e std;// lasse templatetemplate < lass T> lass m ontainer {T elemento;publi :m ontainer (T arg) {elemento=arg;}T in rementa () {return ++elemento;}};// espe ializa ao da lasse templatetemplate <> lass m ontainer < har> { har elemento;publi :m ontainer ( har arg) {elemento=arg;} har letramaius ula (){if ((elemento>='a')&&(elemento<='z'))elemento+='A'-'a';return elemento;}};int main () {m ontainer<int> mint (7);m ontainer< har> m har ('j'); out << mint.in rementa() << endl; out << m har.letramaius ula() << endl;return 0;}, o que retorna na tela:8JEsta é a sintaxe usada na especialização da classe template:template <> lass m ontainer < har> { ... };Note, primeiramente, que precedemos o nome da classe template com uma lista de parâme-

tros vazia template <>. Isto é feito para declarar explicitamente uma especialização do template.Mas, mais importante do que este prefixo é o o parâmetro de especialização <char> depois donome da classe template. Este parâmetro de especialização por si só identifica o tipo para o qualdeclararemos uma especialização da classe template (char). Note as diferenças entre classestemplate genéricas e a especialização, respectivamente:

120

Page 122: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFtemplate < lass T> lass m ontainer { ... };template <> lass m ontainer < har> { ... };Ao declararmos especializações para uma classe template, devemos também definir todos os

seus membros, mesmo aqueles exatamente iguais à classe template genérica, pois não existe"herança"de membros do template genérico para a especialização.

Parâmetros não-tipados para templates

Apesar de argumentos de templates serem precedidos pelas palavras-chave classe ou typename,que representam tipos, templates também podem ter parâmetros tipados comuns, similarmenteàqueles encontrados nas funções. Como um exemplo, vejamos esta classe template que é usadapara conter seqüências de elementos:#in lude <iostream>using namespa e std;template < lass T, int N> lass msequen ia {T blo omem [N℄;publi :void setamembro (int x, T valor);T tmembro (int x);};template < lass T, int N>void msequen ia<T,N>::setamembro (int x, T valor) {blo omem[x℄=valor;}template < lass T, int N>T msequen ia<T,N>::tmembro (int x) {return blo omem[x℄;}int main () {msequen ia <int,5> mints;msequen ia <double,5> mfloats;mints.setamembro (0,100);mfloats.setamembro (3,3.1416); out << mints.tmembro(0) << '\n'; out << mfloats.tmembro(3) << '\n';return 0;}

, o que retorna na tela:1003.1416121

Page 123: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Também é possível setar valores ou tipos default para parâmetros de classe template. Porexemplo, se a definição da classe template anterior fosse:template < lass T= har, int N=10> lass msequen ia {..};

poderíamos criar objetos usando os parâmetros template padrões declarando:msequen ia<> mseq;Que seria equivalente a:msequen ia< har,10> mseq;Templates e arquivos de projeto múltiplos

Do ponto de vista do compilador, templates não são funções ou classes formais. Elas são compi-ladas por demanda, o que significa que o código de uma função template não é compilada até queuma instanciação que especifique os argumentos de template seja requerida. Neste momento,quando a instanciação é requerida, o compilador gera uma função especificamente para aquelesargumentos do template.

Quando projetos crescem é comum dividir o código de um programa em diferentes arquivos-fontede código. Nestes casos, a interface e a implementação são geralmente separadas. Tomandocomo exemplo as bibliotecas de funções, a interface geralmente consiste de declarações de pro-tótipos de todas as funções que podem ser chamadas. Estas são geralmente declaradas num"arquivo de cabeçalho"com a extensão .h, e a implementação (a definição destas funções) estáem um arquivo independente, com código c++.

Como templates são compilados quando requeridos, isto força uma restrição para arquivos deprojeto múltiplos: a implementação (definição) de uma classe template ou função template deveestar no mesmo arquivo que sua declaração. Isto significa que não podemos separar a interfacenum arquivo de cabeçalho separado, e que devemos incluir ambas interface e implementação emqualquer arquivo que utilize templates.

Já que nenhum código é gerado até que um template é instanciado quando requerido, compi-ladores são preparados para permitir a inclusão mais de uma vez do mesmo arquivo templatecom ambas as declarações e definições num projeto sem gerar erros de linkagem.

12.2 Namespaces

Namespaces permitem agrupar entidades como classes, objetos e funções sobre um nome.Assim, o escopo global pode ser dividido em sub-escopos, cada um com seu próprio nome. Oformato é:namespa e identifi ador{entidades}

122

Page 124: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Por exemplo:namespa e meuNspa e{int a, b;}Para acessar as variáveis a e b de fora de meuNspace temos que usar o operador de escopo

( :: ). Por exemplo, podemos escrever:meuNspa e::ameuNspa e::bA funcionalidade de namespaces é especialment eútil no caso em que existe a possibilidade

de que um objeto ou função globais usem o mesmo identificador como algum outro, causandoerros de redefinição. Por exemplo:#in lude <iostream>using namespa e std;namespa e nspa e1{int x = 5;}namespa e nspa e2{double x = 3.1416;}int main () { out << nspa e1::x << endl; out << nspa e2::x << endl;return 0;}

, o que retorna:53.1416Neste caso, existem duas variáveis globais com o mesmo nome: x. Uma é definida no na-

mespace nspace1 e a outra no namespace nspace2. Não acontece erros de redefinição graçasao namespace.

Using

A palavra-chave using é usada para introduzir um nome de um namespace na região declara-tiva atual. Por exemplo:

123

Page 125: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#in lude <iostream>using namespa e std;namespa e nspa e1{int x = 5;int y = 10;}namespa e nspa e2{double x = 3.1416;double y = 2.7183;}int main () {using nspa e1::x;using nspa e2::y; out << x << endl; out << y << endl; out << nspa e1::y << endl; out << nspa e2::x << endl;return 0;}, o que retorna:52.7183103.1416Note como neste código x (sem nenhum qualificador de nome) se refere a nspace1::x en-

quanto y se refere a nspace2::y, exatamente como nossa declaração do using especificou. Aindatemos acesso a nspace1::y e nspace2::x usando seus nomes completos qualificados. A palavrausing também pode ser usada como uma diretiva para introduzir um namespace inteiro:#in lude <iostream>using namespa e std;namespa e nspa e1{int x = 5;int y = 10;}namespa e nspa e2{double x = 3.1416;

124

Page 126: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFdouble y = 2.7183;}int main () {using namespa e nspa e1; out << x << endl; out << y << endl; out << nspa e2::x << endl; out << nspa e2::y << endl;return 0;}, que retorna na tela:5103.14162.7183Aqui, como declaramos que estávamos usando namespace nspace1, todas os usos diretos

de x e y sem qualificadores de nome estavam se referindo à suas declarações em namespacenspace1.

Também, "using"e "using namespace"têm validade apenas no mesmo bloco em que eles sãofirmados ou no código inteiro se eles forem usados diretamente no escopo global. por exemplo,se tivéssemos a intenção de usar primeiramente os objetos de um namespace e então aquelesde outro namespace, poderíamos fazer algo assim:#in lude <iostream>using namespa e std;namespa e nspa e1{int x = 5;}namespa e nspa e2{double x = 3.1416;}int main () {{using namespa e nspa e1; out << x << endl;}{using namespa e nspa e2; out << x << endl;

125

Page 127: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF}return 0;}, o que retorna:53.1416Namespace alias

Podemos declarar nomes alternados para namespaces existentes de acordo com o formato:namespa e novo_nome = nome_atual;Namespace std

Todos os arquivos na biblioteca padrão C++ declaram todas as suas entidades no namespacestd. Por isso temos geralmente incluído o "using namespace std;"em todos os programas queusaram qualquer entidade definida em iostream.

126

Page 128: Programacao cpp

Capítulo 13

Exceptions e Diretivas

Exceções fornecem um modo de reagir a circunstâncias excepcionais (como erros de execu-ção) no nosso programa transferindo o controle para funções especiais chamadas manipuladoresou handlers. Para capturar exceções, devemos colocar um pedaço de código sobre uma inspe-ção excepcional. Isto é feito colocando aquela porção de código em um bloco try. Quando umacircunstância excepcional acontece no bloco, uma exceção é lançada, o que transfere o controlepara o handler. Se nenhuma exceção é lançada, o código continua normalmente e os handlerssão ignorados.

Uma exceção é lançada usando a palavra-chave throw dentro do bloco try. Tratadores de ex-ceções, os handlers são declarados com a palavra-chave catch, que deve ser inserida imediata-mente após o bloco try:#in lude <iostream>using namespa e std;int main () {try{throw 20;} at h (int e){ out << "Um erro o orreu. Ex eção Numero " << e << endl;}return 0;}

, o que mostrará na tela:Um erro o orreu. Ex eção Numero 20Neste exemplo, o código simplesmente lança uma exceção:throw 20;

127

Page 129: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Uma expressão throw aceita um parâmetro (neste caso um inteiro de valor 20), que é passadocomo argumento para o handler.

Como podemos ver, o handler segue imediatamente as chaves depois do bloco try. O formatodo catch é similar a uma função normal que sempre tem no mínimo um parâmetro. O tipo desteparâmetro é muito importante, já que o tipo do argumento passado pela expressão throw é com-parado com ele, e apenas no caso de serem iguais a exceção é capturada.

Podemos encadear multiplos handlers (expressões catch), cada uma com um tipo de parâme-tro diferente. Apenas o handler que bate seu tipo com o argumento especificado na expressãothrow é executado. Se usarmos três-pontos (...) como parâmetro do catch, aquele handler irácapturar qualquer exceção, não importando o tipo de exceção que é lançada. Pode ser usadocomo handler padrão que captura todas as exceções não capturadas por outros handlers se forespecificado por útimo:try {// odigo} at h (int param) { out << "ex e ao int"; } at h ( har param) { out << "ex e ao har"; } at h (...) { out << "ex e ao default"; }

No código anterior, o último handler capturaria qualquer exceção lançada com qualquer parâ-metro que não seja int ou char.

OBS: Após uma exceção ter sido tratada pelo handler, a execução do programa prosegue apóso bloco try-catch, não após a expressão throw.

Também é possível aninhar blocos try-catch em blocos try mais externos. Nesses casos, te-mos a possibilidade de que um bloco catch interno siga a exceção de seu nível externo. Isto éfeito com a expressão throw; sem argumentos. Por exemplo:try {try {// odigo} at h (int n) {throw;}} at h (...) { out << "Erro O orreu";}

Especificações de Exceções

Ao declarar uma função, podemos limitar o tipo da exceção que ela irá diretamente ou indire-tamente lançar anexando um sufixo à declaração da função:

128

Page 130: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFfloat minhafun ao ( har param) throw (int);Isto declara uma função chamada minhafuncao que tem um argumento do tipo char e retorna

um elemento do tipo float. A punica exceção que esta função pode lançar é uma exceção do tipoint. Se lançar uma exceção com um tipo diferente, mesmo diretamente ou indiretamente, nãopode ser capturada por um handler de tipo int comum.

Se este especificador throw é deixado vazio sem tipo, significa que à função não é permitidaa lançar exceções. Funções sem especificador throw (funções normais) são permitidas de lançarexceções com qualquer tipo:int minhafun ao (int param) throw(); // ex e oes nao permitidasint minhafun ao (int param); // todas as ex e oes permitidas

Exceções Padrão

A biblioteca padrão de C++ fornece uma classe base especificamente projetada para declararobjetos para serem lançados como exceções. É chamado exception e é definido no arquivo decabeçalho <exception> sobre o namespace std. Esta classe tem o default usual e construtorescópia, operadores e destrutores, e ainda uma função membro virtual adicional chamada whatque retorna uma seqüência de caracteres terminadas em nulo (já explicado nas lições anterio-res) e que podem ser sobrescritas em classes derivadas para conter um pouco de descrição dasexceções.#in lude <iostream>#in lude <ex eption>using namespa e std; lass minhaex e ao: publi ex eption{virtual onst har* what() onst throw(){return "Minha ex e ao a onte eu";}} mex;int main () {try{throw mex;} at h (ex eption& e){ out << e.what() << endl;}return 0;}

, o que retorna na tela:

129

Page 131: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DFMinha ex e ao a onte eu.Colocamos um handler que captura objetos de exceção por referência (note o & após o tipo),

para que capture também classes derivadas da exceção, como nosso objeto mex da classe mi-nhaexcecao;

Todas as exceções lançadas por componentes da Biblioteca Padrão de C++ lançam exceçõesderivadas desta classe std::ex eption. São elas:

exceção descriçãobad_alloc lançada por new em falha de alocaçãobad_cast lançada por dynamic_cast quando acontece falha com um

tipo de referênciabad_exception lançada quando um tipo de exceção não bate com nenhum catchbad_typeid lançada por typeidios_base::failure lançada por funções na biblioteca iostream

Por exemplo, se usarmos o operador new e a memória não puder ser alocada, uma exceçãodo tipo bad_alloc é lançada:try{int * vet = new int[1000℄;} at h (bad_allo &){ out << "Erro alo ando memoria." << endl;}

É recomendado incluir todas as alocações de memória com um bloco try catch que capturaeste tipo de exceção para realizar uma ação limpa, ao invés de um término anormal da aplicação,que é o que acontece quqando este tipo de exceção é lançado e não tratado. Se quiser forçaruma exceção bad_alloc para vê-la em ação, você pode tentar alocar um array enorme; Talveztentar alocar 1 bilhão de inteiros já vá resultar em uma exceção bad_alloc.

Como bad_alloc é derivada da exceção da classe base padrão, podemos tratar a mesma ex-ceção capturando refer?ncias para a classe de exceção:#in lude <iostream>#in lude <ex eption>using namespa e std;int main () {try{int* vet = new int[1000℄;} at h (ex eption& e){

130

Page 132: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF out << "Ex e ao padrao: " << e.what() << endl;}return 0;}13.1 Diretivas Pré-Processamento

São linhas projetadas incluídas no código que não de nossos programas que não são expres-sões do programa mas diretivas para o pré-processamento. Estas linhas são sempre precedidaspor um (#). O pré-processamento é executado antes da compilação começar.

As diretivas se extendem apenas através de uma única linha de código. Assim que um caracterde nova linha é encontrado, o pré-processamento é considerado finalizado. Ponto-e-vírgula nãosão necessários no final de uma diretiva. A única maneira que uma diretiva pré-processamentopode se extender por mais de uma linha é precedendo o caracter de nova linha no fim da linhapor uma barra invertida.

Definições macro (#define, #undef)

Para definir macros pré-processamento podemos usar #define, cujo formato é:#define identifi ador tro aQuando o pré-procesamento encontra esta diretiva, ele substitui qualquer ocorrência do iden-

tificador no resto do código por troca. Esta substituição pode ser uma expressão, um bloco, ousimplesmente nada. O pré-processamento não entende C++, simplesmente troca qualquer ocor-rência de identificador por troca.Exemplo:#define TAMANHO_TABELA 100int tabela1[TAMANHO_TABELA℄;int tabela2[TAMANHO_TABELA℄;

Após o pré-processamento ter trocado TAMANHO_TABELA, o código é equivalente a:int tabela1[100℄;int tabela2[100℄;Este uso de #define é comum, mas ele também pode funcionar com parâmetros para definir

funções macros:#define tMaior(a,b) a>b?a:bFazzendo isto, poderíamos substituir qualquer ocorrência de tMaior com dois argumentos pela

expressão de troca, mas também substituíndo cada argumento por seu identificador exatamentecomo experaríamos se fosse a função:

131

Page 133: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF// fun ao ma ro#in lude <iostream>using namespa e std;#define tMaior(a,b) ((a)>(b)?(a): (b))int main(){int x=5, y;y= tMaior(x,2); out << y << endl; out << tMaior(7,x) << endl;return 0;}, o que retornaria na tela:57macros definidas não são afetadas pela estrutura do bloco. Uma macro dura até sua indefini-

ção com a diretiva #undef:#define TAMANHO_TABELA 100int tabela1[TAMANHO_TABELA℄;#undef TAMANHO_TABELA#define TAMANHO_TABELA 200int tabela2[TAMANHO_TABELA℄;Isto geraria o mesmo que:int tabela1[100℄;int tabela2[200℄;Definições de funções macro aceitam dois operadores especiais (# e ##) na seqüência de

substituição:

Se o operador # for usado antes que um parâmetro é usado na seqüência de troca, aqueleparâmetro é substituído por uma string literal (como se ela estivesse entre aspas duplas).#define str(x) #x out << str(teste);

Isto seria traduzido para: out << "teste";O operador ## concatena dois argumentos, não deixando espaço em branco entre eles:#define fun (a,b) a ## bfun ( ,out) << "teste";

132

Page 134: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Isto também seria traduzido para: out << "teste";Como as substituições pré-processamento acontecem antes da qualquer checagem sintática

em C++, definições macro podem ser uma funcionalidade ótima, mas deve ser usada com cui-dado: códigos que dependem muito de macros complicadas podem gerar um resultado obscuropara outros programadores, já que a sintaxe que eles experam é, na maioria dos casos, diferentede expressões comuns que programadores esperam em C++.

Inclusões condicionais (#ifdef, #ifndef, #if, #endif, #el se and #elif)

São diretivas que permitem incluir ou descartar parte do código de um programa se uma certacondição for encontrada.#ifdef TAMANHO_TABELAint tabela[TAMANHO_TABELA℄;#endif

#ifdef permite que uma seção de um programa seja compilada apenas se a macro que é es-pecificada como parâmetro tiver sido definida, não importando qual é o seu valor. Exemplo:

neste caso, a linha de código int tabela[TAMANHO_TABELA]; é compilada apenas se TAMA-NHO_TABELA foi definido previamente com #define, independentemente de seu valor. Se não foidefinida, aquela linha não será incluída na compilação do programa.

#ifndef serve para o oposto: o código entre as diretivas #ifndef e #endif apenas é compiladose o identificador especificado não foi definido previamente. Exemplo:#ifndef TAMANHO_TABELA#define TAMANHO_TABELA 100#endifint tabela[TAMANHO_TABELA℄;

Neste caso, se quando chegarmos neste pedaço de código, a macro TAMANHO_TABELAainda não foi definida, seria definida com um valor de 100. Se já existia, manteria o valor anteriorjá que a diretiva #define não seria executada.

As diretivas #if, #else e #elif (ou seja, else if) servem para especificar alguma condição a serencontrada para que a porção de código que elas cercam seja compilada.A condição que segue#if ou #elif pode apenas avaliar expressões constantes, inluíndo expressões macro. Exemplo:#if TAMANHO_TABELA>200#undef TAMANHO_TABELA#define TAMANHO_TABELA 200#elif TAMANHO_TABELA<50#undef TAMANHO_TABELA#define TAMANHO_TABELA 50

133

Page 135: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF#else#undef TAMANHO_TABELA#define TAMANHO_TABELA 100#endifint tabela[TAMANHO_TABELA℄;Note como a estrutura inteira de diretivas #if, #elif e #else encadeadas terminam com #endif.

o comportamento de #ifdef e #ifndef também podem ser alcançados usando os operadores es-peciais definided e !defined respectivamente em qualquer uma das diretivas #if ou #elif:#if !defined TAMANHO_TABELA#define TAMANHO_TABELA 100#elif defined TAMANHO_VETOR#define TAMANHO_TABELA TAMANHO_VETORint tabela[TAMANHO_TABELA℄;

Controle de Linha (#line)

Quando compilamos um programa e algum erro acontece durante este processo, o compiladormostra uma mensagem de erro com referências ao nome do arquivo onde o erro aconteceu e onúmero da linha, o que facilita a localização do código que gerou o erro.

A diretiva #line nos permite controlar ambas as coisas, os números das linhas nos arquivos decódigo assim como o nome do arquivo que queremos que apareça quando um erro acontece.Seu formato é:#line numero "nomedoarquivo"

, onde numero é o novo número da linha que será atribuído à próxima linha de código. Osnúmeros das linhas de sucessivas linhas será incrementado um a um a partir deste ponto. Jánomedoarquivo é um parâmetro opcional que permite redefinir o nome do arquivo que será mos-trado. Exemplo:#line 20 "atribuindo variavel"int a?;

Este código irá gerar um erro que será mostrado como erro no arquivo atribuindo variavel,linha 20.

Diretiva Error (#error)

Esta diretiva aborta o processo de compilação quando é encontrada, gerando uma compilaçãodo erro que pode ser especificado como seu parâmetro:#ifndef __ plusplus#error Um ompilador C++ se faz ne essario!#endif

134

Page 136: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Este exemplo aborta o processo de compilação se o nome da macro __cplusplus não estádefinido (o nome desta macro está definido por padrão em todos os compiladores de C++).

Inclusão de arquivo fonte (#include)

Esta diretiva também foi usada assiduamente em códigos anteriores do curso. Quando o pré-processamento encontra uma diretiva #include, ele a substitui por um conteúdo inteiro de umarquivo especificado. Existem duas maneiras de especificar um arquivo a ser incluído:#in lude "arquivo"#in lude <arquivo>

A única diferença entre ambas as expressões é o local (diretórios) onde o compilador irá pro-curar pelo arquivo. No primeiro caso, onde o nome do arquivo é especificado entre aspas duplas,o arquivo é procurado primeiramente no mesmo diretório que inclui o arquivo contendo a diretiva.No caso em que não esteja lá, o compilador procura o arquivo nos diretórios onde é configu-rado para procurar pelos arquivos de cabeçalhos padrão. Se o nome do arquivo está entre < e> o arquivo é procurado diretamente nestes locais. Assim, arquivos de cabeçalho padrão sãonormalmente incluídos entre < e >, enquanto outros arquivos de cabeçalhos específicos são in-cluídos usando aspas simples.

Diretiva (#pragma)

Esta diretiva é usada para especificar diversas opções ao compilador. Estas opções são especí-ficas para a plataforma e compilador que você estiver usando. Consulte o manual ou a referênciade seu compilador para mais informações dos possíveis parâmetros que você pode definir com#pragma.

Se o compilador não suporta um argumento específico para #pragma, ele é ignorado - não égerado erro.

Nomes de Macros Pré-Definidos

Os seguintes nomes de macros são definidos a qualquer momento:

macro valor__LINE__ Valor inteiro representando a linha atual no arquivo

fonte sendo compilado.__FILE__ Uma string contendo o nome presumido do arquivo fonte

sendo compilado.__DATE__ Uma string na forma "Mm dd aaaa"contendo a data em que

o processo de compilação se iniciou.__TIME__ Uma string na forma "hh:mm:ss"contendo a hora em que o

processo de compilação se iniciou.__cplusplus Um valor inteiro. Todos os compiladores C++ têm esta constante

definida com algum valor.Se o compilador está totalmente deacordo com o padrão C++, seu valor é igual ou maior que 199711Ldependendo da versão do padrão a que eles estão de acordo.

135

Page 137: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

Exemplo:#in lude <iostream>using namespa e std;int main(){ out << "Este é o número da linha " << __LINE__; out << " do arquivo " << __FILE__ << ".\n"; out << "A ompila ao ome ou em " << __DATE__; out << " às " << __TIME__ << ".\n"; out << "O ompilador dá um valor __ plusplus de " << __ plusplus;return 0;}, o que retornaria:Este é o número da linha 7 do arquivo /home/jay/stdma ronames. pp.A ompila ao ome ou em Nov 1 2005 às 10:12:29.O ompilador dá um valor __ plusplus de 1

136

Page 138: Programacao cpp

Capítulo 14

Entrada/Saída com Arquivos

Temos à nossa disposição as seguintes classes em C++ para relizar operações de entrada esaída de caracteres de/para arquivos:

• ofstream: classe Stream para escrever em arquivos.

• ifstream: classe Stream para ler de arquivos.

• fstream: classe Stream para ambos ler e escrever de/para arquivos.

Essas classes são derivadas direta ou indiretamente de classes istream e ostream. Já usamosobjetos cujos tipos eram essas classes: cin é um objeto da classe istream e cout é um objeto daclasse ostream. Assim, já viemos utilizando classes que são relacionadas a nosso arquivo stream.E, de fato, podemos usar nosso arquivo streams da mesma maneira que já fizemos para usar cine cout, com a diferença que temos que associar essas streams com arquivos físicos. Vejamosum exemplo:#in lude <iostream>#in lude <fstream>using namespa e std;int main () {ofstream marquivo;marquivo.open ("exemplo.txt");marquivo << "Es revendo em um arquivo.\n";marquivo. lose();return 0;}

, o que resulta numa escrita num arquivo:[file exemplo.txt℄Es revendo em um arquivoEste código cria um arquivo chamado exemplo.txt e insere uma sentença nele da mesma ma-

neira que fazíamos com cout, mas usando o arquivo stream meuarquivo como saída.Explicando por partes

137

Page 139: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

A primeira operação geralmente realizada em um objeto de uma dessas classes é associá-laa um arquivo real. Este procedimento é conhecido como "abrir um arquivo". Um arquivo aberto érepresentado em um programa por um objeto stream (uma instanciação de uma dessas classes,no exemplo anterior: meuarquivo) e qualquer operação de entrada ou saída realizada neste ob-jeto stream será aplicada ao arquivo físico associado a ela.

Para abrir um arquivo com um objeto stream usamos sua função membro open():open (nome\_do\_arquivo, mode);, onde nome_do_arquivo é uma seqüência de caracteres terminadas em nulo do tipo const

char * representando o nome de um arquivo para ser aberto, e mode é um parâmetro opcionalcom uma combinação das seguintes flags:

ios::in Open (Abrir) para operações de entradaios::out Open para operações de saídaios::binary Open para modo binárioios::ate Seta a posição inicial no fim do arquivo. Se este flag não está setado

com nenhum valor, a posição inicial é o início do arquivo.ios::app Todas as operações de saída são realizadas no fim do arquivo, anexando o

conteúdo ao conteúdo atual do arquivo. Este flag pode ser usado apenas emstreams Open para operações de saída.

ios::trunc Se o arquivo aberto para operações de saída já existirem antes, seu conteúdoanterior é deletado e substituído pelo novo.

Todos estes flags podem ser combinados usando o operador OR (|). Por exemplo, se quiser-mos abrir o arquivo exemplo.bin no modo binário para adicionar dados, podemos usar a seguintechamada à função membro open():ofstream marquivo;marquivo.open ("exemplo.bin", ios::out | ios::app | ios::binary);

Cada uma das funções membro open() das classes ofstream, ifstream e fstream tem um modopadrão que é usado se o arquivo é aberto sem um segundo argumento:

classe parâmetro mode padrãoofstream ios::outifstream ios::infstream ios::in | ios::out

Para classes ifstream e ofstream, ios:in e ios:out são automaticamente e respectivamente as-sumidos, mesmo se um modo que não os inclui é passado como segundo argumento para afunção membro open(). O valor padrão apenas é aplicado se a função é chamada sem especifi-car nenhum valor para o parâmetro mode. Se a função é chamada com qualquer valor naqueleparâmetro o modo pardão é sobrescrito, não combinado.

Arquivo streams abertos em modo binário realizam operações de entrada e saída independen-temente de quaisquer considerações de formato. Arquivos não binários são conhecidos como"arquivos texto", e algumas traduções devem ocorrer devido à formatação de alguns caracteres

138

Page 140: Programacao cpp

CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF

especiais (como newline).

Como a primeira tarefa que é realizada em um arquivo objeto stream é geralmente abrir um ar-quivo, estas três classes incluem um construtor, que chama automaticamente a função membroopen() e tem exatamente os mesmos parâmetros que este membro. Assim, poderíamos tambémter declarado o objeto marquivo anterior e conduzido a mesma operação de abertura no exemplofazendo:ofstream marquivo ("exemplo.bin", ios::out | ios::app | ios::binary);

Combinando construção do objeto e abertura de stream em uma mesma expressão. Ambasas formas de abrir um arquivo são válidas e equivalentes.

Para checar se um arquivo stream teve sucesso ao abrir um arquivo, podemos fazer isto cha-mando o membro is_open() sem argumentos. Ela retorna um valor booleano de true, no caso emque realmente o objeto stream for associado com um arquivo aberto, ou false em caso contrário.if (marquivo.is_open()) { /* ok, prossiga om a saida*/ }

Fechando um arquivo

Quando finalizamos com nossas operações de entrada e saída em um arquivo, devemos fechá-lopara que ses recursos se tornem disponíveis novamente. Para isso, temos que chamar a funçãomembro strem close(). Esta função membro não recebe parâmetros, e o que ela faz é esvaziaros buffers e fechar o arquivo:marquivo. lose();

uma vez que esta função membro é chamada, o objeto stream pode ser usado para abrirum outro arquivo, e o arquivo está disponível para ser aberto por outros processos. No casoem que um objeto é destruído enquanto ainda é associado a um arquivo aberto, o destrutorautomaticamente chama a função membro close().

139