Este documento apresenta um plano de ensino para programação C++, cobrindo tópicos como introdução à linguagem, tipos de dados, operadores, estruturas de controle, vetores, ponteiros, programação orientada a objetos, templates e namespaces.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
É dada permissão para copiar, distribuir e/ou modificar este documento sob os termos
da Licença de Documentação Livre GNU, Versão 1.1 ou qualquer versão posterior
publicada pela Free Software Foundation; com o Capítulo Invariante SOBRE ESSA
APOSTILA. 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 seus
colegas de turma respeitando-os e fazendo ser respeitado pelo mesmo.
• 5. Organização pessoal: planejar e organizar tudo é fundamental para facilitar a sua revisão
e a sua recuperação de materiais.
• 6. Vontade para realizar as atividades no tempo correto: anotar todas as suas obrigações e
realizá-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, aprendizagens
e 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ão
controla 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ções
que sejam pertinentes ao curso (avisos, notícias). As mensagens postadas nele são enviadas a
8
10.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
todos participantes. Assim, se o monitor ou algum outro participante tiver uma informação que
interesse ao grupo, favor postá-la aqui.
Porém, se o que você deseja é resolver alguma dúvida ou discutir algum tópico específico do
curso, é recomendado que você faça uso do Fórum de dúvidas gerais que lhe dá recursos mais
efetivos para esta prática.
. O fórum de dúvidas gerais tem por objetivo disponibilizar um meio fácil, rápido e interativo
para solucionar suas dúvidas e trocar experiências. As mensagens postadas nele são enviadas
a todos participantes do curso. Assim, fica muito mais fácil obter respostas, já que todos podem
ajudar.
Se você receber uma mensagem com algum tópico que saiba responder, não se preocupe com a
formalizaçã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 podem
ser 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, por
pessoas 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 das
ferramentas 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 respectivos
valores e atitudes, incentiva mas é honesto, imparcial, amável, positivo, respeitador, aceita as
idéias dos estudantes, é paciente, pessoal, tolerante, apreciativo, compreensivo e pronto a ajudar.
9
11.
CDTC Centro deDifusã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 tutor
ou 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 um
reparo de um estudante: ’os comentários deixam-nos com uma sensação de crítica, de
ameaç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
CDTC Centro deDifusã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 melhor
a 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 the
distribution terms for software that uses the GFDL–only the original English text of the GFDL does
that. However, we hope that this translation will help Portuguese speakers understand the GFDL
better.
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, mas
não é permitido alterá-lo.
INTRODUÇÃO
O propósito desta Licença é deixar um manual, livro-texto ou outro documento escrito "livre"no
sentido 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ém
para o autor e editor uma forma de ter crédito por seu trabalho, sem ser considerado responsável
pelas modificações feitas por terceiros.
Esta Licença é um tipo de "copyleft"("direitos revertidos"), o que significa que derivações do
documento 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 software
livre precisa de documentação livre: um programa livre deve ser acompanhado de manuais que
provenham as mesmas liberdades que o software possui. Mas esta Licença não está restrita a
manuais de software; ela pode ser usada para qualquer trabalho em texto, independentemente
do 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 pelo
detentor dos direitos autorais dizendo que ele pode ser distribuído sob os termos desta Licença.
12
14.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
O "Documento"abaixo se refere a qualquer manual ou texto. Qualquer pessoa do público é um
licenciado e é referida como "você".
Uma "Versão Modificada"do Documento se refere a qualquer trabalho contendo o documento
ou uma parte dele, quer copiada exatamente, quer com modificações e/ou traduzida em outra
lí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 do
Documento (ou assuntos relacionados) e não contém nada que poderia ser incluído diretamente
nesse assunto geral (Por exemplo, se o Documento é em parte um livro texto de matemática, a
Seçã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, como
sendo 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 Capa
Frontal 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, cujos
conteúdos possam ser vistos e editados diretamente e sem mecanismos especiais com editores
de 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 de
servir como entrada a formatadores de texto ou para tradução automática para uma variedade
de formatos que sirvam de entrada para formatadores de texto. Uma cópia feita em um formato
de 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 XML
usando uma DTD disponibilizada publicamente, e HTML simples, compatível com os padrões, e
projetado para ser modificado por pessoas. Formatos opacos incluem PostScript, PDF, formatos
proprietá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 estejam
disponíveis para o público, e HTML gerado automaticamente por alguns editores de texto com
finalidade 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ão
tenham 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
15.
CDTC Centro deDifusã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ão
comercial, desde que esta Licença, as notas de copyright, e a nota de licença dizendo que esta
Licenç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 de
có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ém
pode 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 do
Documento obrigar Textos de Capa, você precisará incluir as cópias em capas que tragam, clara
e legivelmente, todos esses Textos de Capa: Textos de Capa da Frente na capa da frente, e
Textos da Quarta Capa na capa de trás. Ambas as capas também precisam identificar clara e
legivelmente 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 adicionar
outros materiais às capas. Fazer cópias com modificações limitadas às capas, tanto quanto estas
preservem o título do documento e satisfaçam a essas condições, pode ser tratado como cópia
exata em outros aspectos.
Se os textos requeridos em qualquer das capas for muito volumoso para caber de forma
legível, você deve colocar os primeiros (tantos quantos couberem de forma razoável) na capa
verdadeira, 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ópia
Opaca, ou informar, em ou com, cada cópia Opaca a localização de uma cópia Transparente
completa do Documento acessível publicamente em uma rede de computadores, a qual o público
usuário de redes tenha acesso a download gratuito e anônimo utilizando padrões públicos de
protocolos 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 assegurar
que esta cópia Transparente vai permanecer acessível desta forma na localização especificada
por 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 de
redistribuir qualquer grande número de cópias, para lhes dar uma oportunidade de prover você
com uma versão atualizada do Documento.
14
16.
CDTC Centro deDifusã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ção
e modificação da Versão Modificada para quem quer que possua uma cópia da mesma. Além
disso, 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 listados
na seção "Histórico do Documento"). Você pode usar o mesmo título de uma versão anterior se
o 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 cinco
dos autores principais do Documento (todos os seus autores principais, se ele tiver menos que
cinco);
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 às
outras notas de copyright;
F. Incluir, imediatamente depois das notas de copyright, uma nota de licença dando ao público
o direito de usar a Versão Modificada sob os termos desta Licença, na forma mostrada no tópico
abaixo;
G. Preservar nessa nota de licença as listas completas das Seções Invariantes e os Textos de
Capa 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 dizendo
pelo menos o título, ano, novos autores e editor da Versão Modificada como dados na Página de
Título. Se não houver uma sessão denominada "Histórico"no Documento, criar uma dizendo o
título, ano, autores, e editor do Documento como dados em sua Página de Título, então adicionar
um 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 uma
có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 publicado
pelo menos quatro anos antes do Documento, ou se o editor original da versão a que ela se refira
der sua permissão;
K. Em qualquer seção entitulada "Agradecimentos"ou "Dedicatórias", preservar o título da
15
17.
CDTC Centro deDifusã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 em
seus 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ão
Modificada;
N. Não reentitular qualquer seção existente com o título "Endossos"ou com qualquer outro
título dado a uma Seção Invariante.
Se a Versão Modificada incluir novas seções iniciais ou apêndices que se qualifiquem como
Seções Secundárias e não contenham nenhum material copiado do Documento, você pode optar
por designar alguma ou todas aquelas seções como invariantes. Para fazer isso, adicione seus
tí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 - por
exemplo, declarações de revisores ou de que o texto foi aprovado por uma organização como a
definiçã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 Textos
de Capa na Versão Modificada. Somente uma passagem de Texto da Capa da Frente e uma de
Texto 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 por
você ou por acordo feito com alguma entidade para a qual você esteja agindo, você não pode
adicionar um outro; mas você pode trocar o antigo, com permissão explícita do editor anterior que
adicionou a passagem antiga.
O(s) autor(es) e editor(es) do Documento não dão permissão por esta Licença para que seus
nomes sejam usados para publicidade ou para assegurar ou implicar endossamento de qualquer
Versão Modificada.
COMBINANDO DOCUMENTOS
Você pode combinar o Documento com outros documentos publicados sob esta Licença, sob
os 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 liste
todas 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 Invariantes
Idênticas com multiplas ocorrências podem ser substituídas por apenas uma cópia. Se houver
múltiplas Seções Invariantes com o mesmo nome mas com conteúdos distintos, faça o título de
16
18.
CDTC Centro deDifusã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 editor
origianl daquela seção, se for conhecido, ou um número que seja único. Faça o mesmo ajuste
nos 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 combine
quaisquer seções entituladas "Agradecimentos", ou "Dedicatórias". Você precisa apagar todas as
seções entituladas como "Endosso".
COLETÂNEAS DE DOCUMENTOS
Você pode fazer uma coletânea consitindo do Documento e outros documentos publicados
sob esta Licença, e substituir as cópias individuais desta Licença nos vários documentos com
uma única cópia incluida na coletânea, desde que você siga as regras desta Licença para cópia
exata de cada um dos Documentos em todos os outros aspectos.
Você pode extrair um único documento de tal coletânea, e distribuí-lo individualmente sob
esta Licença, desde que você insira uma cópia desta Licença no documento extraído, e siga esta
Licenç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 pela
compilação. Tal compilação é chamada um "agregado", e esta Licença não se aplica aos outros
trabalhos auto-contidos compilados junto com o Documento, só por conta de terem sido assim
compilados, 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 Capa
do 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ções
do Documento sob os termos da seção 4. A substituição de Seções Invariantes por traduções
requer uma permissão especial dos detentores do copyright das mesmas, mas você pode incluir
traduções de algumas ou de todas as Seções Invariantes em adição às versões orignais dessas
Seçõ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
19.
CDTC Centro deDifusã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 direitos
sob esta Licença. Entretanto, terceiros que tenham recebido cópias, ou direitos de você sob esta
Licença não terão suas licenças terminadas, tanto quanto esses terceiros permaneçam em total
acordo 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ão
presente, mas podem diferir em detalhes ao abordarem novos porblemas e preocupações. Veja
http://www.gnu.org/copyleft/.
A cada versão da Licença é dado um número de versão distinto. Se o Documento especificar
que 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ão
posterior que tenha sido publicada (não como rascunho) pela Free Software Foundation. Se o
Documento não especificar um número de Versão desta Licença, você pode escolher qualquer
versã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ça
no 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ça
de 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 da
Capa 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 de
dizer quais são invariantes. Se você não tiver Textos de Capa da Frente, escreva "sem Textos de
Capa da Frente"ao invés de "com os Textos de Capa da Frente sendo LISTE"; o mesmo para os
Textos 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
20.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
tal como a GNU General Public License, para permitir o seu uso em software livre.
19
Capítulo 1
O queé o C++
O C++ é uma linguagem de programação de alto nível com facilidades para o uso em baixo
nível (herdados do C), multiparadigma e de uso geral. Desde os anos 1990 é uma das linguagens
comerciais mais populares, sendo bastante usada também na academia por seu grande desem-
penho e base de utilizadores.
21
23.
Capítulo 2
Plano deensino
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 de
aprendizado que será dado na primeira semana e um módulo de avaliação que será dado na
segunda 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
24.
CDTC Centro deDifusã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 menor
do 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ções
quanto a da avaliação serão consideradas para a nota final. Todos os módulos ficarão visíveis
para que possam ser consultados durante a avaliação final.
Aconselhamos a leitura da "Ambientação do Moodle"para que você conheça a plataforma de
Ensino 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á ser
enviada 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
25.
CDTC Centro deDifusã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 e
obtenção do certificado o participante deverá obter nota final maior ou igual a 6.0 de acordo
com a fórmula abaixo:
• Nota Final = ((ML x 7) + (AF x 3)) / 10 = Média aritmética das lições
• AF = Avaliações
24
26.
CDTC Centro deDifusã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
27.
Capítulo 3
Introdução eBreve 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 baixo
ní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 grande
desempenho e base de utilizadores.
Durante sua fase inicial de desenvolvimento, a linguagem era chamada "novo C"ou ainda "C
com 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 à vendagem
do livro "The C Programmign Language"e ao fato de ser independente de hardware. Vale notar
que 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
28.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Em 1980, Bjarne Stroustrup desenvolveu o C++ no Bell Labs como um adicional à linguagem
C. Hoje em dia quase todas as grandes empresas que desenvolvem softwares usam C++. Mas a
pergunta principal é: "Devemos aprender primeiro o C e depois C++ ou ir direto ao C++? Bjarne
Stroustrup 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 principais
novidades 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ços
de 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. Maior
compreensã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 uma
sucessora à linguagem C, inclusive servindo de inspiração para outras linguagens como Java, a
IDL 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 ao
programador escolher a opção errada;
27
29.
CDTC Centro deDifusã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 grupos
de desenvolvedores;
• C++ não exige overhead (tempo de processamento excessivo) para facilidades que não são
utilizadas;
• C++ é desenvolvido para ser utilizado mesmo sem um ambiente de desenvolvimento sofis-
ticado.
3.3 Alguns conceitos básicos
Debuger
Ajuda o programador a encontrar os erros de programação, famosos bugs.
Profiler
Ajuda 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 ou
função.
Linker
Transforma um ou mais arquivos *.o (no Unix/Linux) em um arquivo executável. Os arquivos que
serão unidos são definidos em um arquivo de projeto ou em um arquivo makefile. No linux, depois
de linkado, um programa tem um arquivp ’a.out’. Os erros de ligação são detectados pelo linker.
Compilador
Encontra 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 desenvolvimento
integrado (IDE) que rodam em ambiente Linux:
28
30.
CDTC Centro deDifusã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 compiladores
como 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ão
muitos os compiladores existentes. Para dúvidas, entre em contato com os monitores no fórum
de dúvidas.
3.5 Incompatibilidades
Considerar o C++ como um superconjunto, uma linguagem que implementa completamente o
C 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 elas
que tornam alguns trechos de código C válidos em código C++ inválido, ou códigos que exibem
comportamentos 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álido
então o seguinte código em C++:
ÒØ ¶ Ñ ÐÐÓ
´× Þ Ó ´ ÒØµ ¶ µ
, a não ser que explicitemos a conversão:
ÒØ ¶ ´ ÒØ ¶µ Ñ ÐÐÓ
´× Þ Ó ´ ÒØµ ¶ µ
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
31.
Capítulo 4
Iniciando
4.1 Layout
Odesenvolvimento 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 definir
em que seqüência devem ser compilados. Contém, então, uma lista com os nomes dods
arquivos de cabeçalho (*.h), de implementação (*.cpp) e a forma como os mesmos serão
compilados. A organização do programa separando o código em vários arquivos facilita a
manutençã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 a
extensão *.cpp. ;
• 4) É necessário um arquivo com a definição da função main, um aruqivo também *.cpp, que
usa 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 formato
usado:
»»¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹Ì ÔÐ
Óº
»»»
Ð Ö ÙÑ
Ð ×× Ñ Ò Ñ Ð ×Ø
Ð ×× Ì ÔÐ
Ó
ß
ÔÙ Ð
»»»Å ØÓ Ó Ü
Ù Ó ÔÐ
Ó
ÚÓ ÊÙÒ´µ
»»¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹Ì ÔÐ
Óº
ÔÔ
Ò
ÐÙ Ó×ØÖ Ñ
30
32.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
»» Ò Ñ ØÓ Ó
Ð ×× º
Ò
ÐÙ Ì ÔÐ
Óº
»¶¶
Ç Ñ ØÓ Ó ÊÙÒ ×
Ö Ú ÙÑ Ñ× Ò Ø Ð
¶»
ÚÓ Ì ÔÐ
Ó ÊÙÒ´µ
ß
»» Ò
Ó Ó Ñ ØÓ Ó
»»×Ø
ÓÙØ ×
Ö Ú Ò Ø Ð
»»
ÓÙØ
ÓÙØ
ר
ÓÙØ Ñ Ú Ò Ó Ó ·· ¸¸×Ø Ò ½
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 objeto
ou variável. Para atribuições usa-se o símbolo de igual (=).
Exemplo:
Ü
¿
·½
Declaração: Declara que existe tal objeto, mas não o cria.
Exemplo:
ÒØ Ü
Ð ×× Ø Ð
ÐÓ Ø ÙÒ
Ó´µ
רÖÙ
Ø ×
ÜØ ÖÒ
ÓÒר ÒØ
Inicialização: As variáveis, no ato de sua declaração podem ser inicializadas com algum valor
que terão até o fim do programa ou até que este valor seja alterado.
Exemplo:
ÒØ Ü ½¼
Ö
³ ³
ÒØ ¼
Escopo: Define aonde um objeto é visível. Pode ser objeto local, de classe , de função, glo-
bal, ou de arquivo.
31
33.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ ÒØ Ö
Ö
ÙÒ× Ò ÒØ Ò »»
¸ Ò × Ó Ú Ö Ú × ÐÓ ×
ÒØ Ñ Ò ´µß
ÙÒ× Ò × ÓÖØ Ñ
ÐÓ Ø Ü¸ Ý »»Ü¸Ý¸Ñ × Ó Ú Ö Ú × ÐÓ
×
ººº
Especificadores: São palavras reservadas da linguagem, usadas para atribuir determinadas
propriedades ao tipos ou definir o tipo do objeto.
Exemplo:
ÒØ Ü
ÒØÐ Ò ÚÓ ´µ
ߺºº
ØÝÔ ÐÓ Ø Ö
ÓÒ Ð
»»× Ó ÒØ
ÓÖ × ÒØ¸ ÒØÐ Ò ¸ ØÝÔ º
Diretrizes pré-processamento: Informações no início do programa que são passadas ao
compilador. Iniciam-se com o símbolo #.
Lvalue: é uma expressão que se refere a um objeto ou função. Pode aparecer à esquerda do
sinal 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:
ÒØ Ü¸Ý¸Ü »»Ü¸ Ý Þ × Ó Ó× ÒØ
ÓÖ ×º
Operadores: Operadores são símbolos cujo uso já vem definido na linguagem. São eles:
± ² ¶ ´µ ¹ · ß ℄ ³ ¸ º »
32
34.
CDTC Centro deDifusã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 a
variáveis.
Exemplo:
Ð ×׸ ×ØÖ Ò ¸ Ð× ¸ Ø Ò¸ Ñ Òººº
Literais: Tipos previamente definidos na linguagem para serem usados representando obje-
tos de uso corrente. Exemplo:
ÒØ Ü ¿ »»Ç ÒÙÑ ÖÓ ÙÑ Ð Ø Ö Ð
Ö
³ ³ »» Ð ØÖ ³ ³ ÙÑ Ð Ø Ö Ð
ÐÓ Ø Ý º »»ÓÒ Ñ ÖÓ º¿ ÙÑ Ð Ø Ö Ð
Ö¶ ÒÓÑ ÙÐ Ó »» ÙÐ Ó ÙÑ Ð Ø Ö Ð
4.4 Os Operadores
Atribuição
Usados para atribuir um valor para a variável.
Operadores aritméticos
Operadores 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 armazenado
nela. São eles:
· ¸ ¹ ¸ ¶ ¸ » ¸ ± ¸ ¸ ¸ ² ¸ ¸ º
Exemplos:
Ü · ¿ »»Ü Ü·¿
Ü ¹ ¿ »»Ü ܹ¿
Ü ¿ »»Ü ܶ¿
Ü » ¿ »»Ü Ü»¿
Ü ± ¿ »»Ü ܱ¿
33
35.
CDTC Centro deDifusã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:
Ü · ½
Ü··
Ü Ü · ½
ou
Ü ¹ ½
ܹ¹
Ü Ü ½
OBS: Note a diferença existente entre os dois exemplos seguintes, onde no primeiro é usado
como prefixo e no segundo é usado como sufixo:
1 2
A=++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:
´ µ »» Ö ØÓÖÒ Ð×
´ µ »» Ö ØÓÖÒ ØÖÙ
´¿ ¾µ »» Ö ØÓÖÒ ØÖÙ
´ µ »» Ö ØÓÖÒ ØÖÙ
´ µ »» Ö ØÓÖÒ Ð× º
Lógicos
Usados para expressar negação, conjunção ou disjunção.
Exemplos:
´¿ ¿µ »» Ö ØÓÖÒ Ð×Ó ÔÓ × ¿ ¿ Ú Ö º
´½¼ ¾µ »» Ö ØÓÖÒ ØÖÙ ÔÓ × Ö ØÓÖÒ Ö Ð×Óº
34
36.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ØÖÙ Ð×
²² »»Ö ØÓÖÒ Ð×Ó
ØÖÙ Ð×
»»Ö ØÓÖÒ ØÖÙ
Condicional (?) e vírgula (,)
O condicional ’?’ é usado para avaliar uma expressão, retornando um valor (resultado1) se a
expressão for verdadeira e um outro valor (resultado2) se ela for falsa. Neste formato:
ÓÒ Ó Ö ×ÙÐØ Ó½ Ö ×ÙÐØ Ó¾
Exemplo:
¿ »» Ö ØÓÖÒ ¿¸ ÕÙ Ò Ó Ù Ð º
·¾ ¿ »» Ö ØÙÖÒ× ¸ × Ò
× ÕÙ Ð ØÓ ·¾º
Já a vírgula é usada para separar duas ou mais expressões que são incluídas onde apenas
uma expressão é esperada.
´ ¸ · µ
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ários
Modificam 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 a
menor, é esta:
35
37.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Nível Operador Agrupamento
1 :: esquerda para a direita.
2 () [] . -> ++ – esquerda para a direita.
dynamic_cast static_cast reinterpret_cast
const_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:
ÒØ
ÐÓ Ø ¿º½
´ ÒØµ
Este código converte um float (3.14) para um inteiro (3). Outra maneira é:
ÒØ ´ µ
O último operador a vermos é o × Þ Ó ´µ. 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.
× Þ Ó ´
Öµ
Com esse comando, atribuímos o valos 1 a a pois char é um tipo constituído de um byte.
36
38.
Capítulo 5
Constantes
5.1 Tiposde Dados Fundamentais de C++
Ao programar, o valor das variáveis são armazenados na memória do computador, mas este
tem 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 podemos
gerenciar 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, o
computador pode manipular tipos de dados mais complexos que aparecem do agrupamento de
vá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
39.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Nome Descrição
Tamanho
Intervalo de valores
char usualmente caracteres
1 byte
c/ sinal: -128 a 127
sem sinal: 0 a 255.
short inteiros curtos
2 byte
c/ sinal: -32768 a 32767
sem sinal: 0 a 65535.
int inteiros
4 byte
c/ sinal: -2147483648 a 2147483647
sem sinal: 0 a 4294967295.
long inteiros longos
4 byte
c/ sinal: -2147483648 a 2147483647
sem sinal: 0 a 4294967295.
bool valores booleanos true ou false
1 byte
true ou false.
float números em ponto flutuante.
4 byte
3.4e +/- 38 (7 dígitos).
double precisão double de números em ponto flutuante.
8 byte
1.7e +/- 308 (15 diítos).
long double precisão long de números em ponto flutuante.
8 byte
1.7e +/- 308 (15 dígitos).
wchar_t caracter wide
2 ou 4 byte
1 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. Para
outros sistemas, entretanto, a especificação genérica é que int tem o tamanho natural sugerido
pela arquitetura do sistema (uma "palavra", 4 bytes ou 8 bytes por exemplo) e os outros tipos
inteiros (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 o
precede.
38
40.
CDTC Centro deDifusã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 divididas
em Números Inteiros, Números em Ponto-Flutuante, Caracteres, Strings, Valores Booleanos.
Inteiros:
½¼
¿
¹
Sã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:
»»
Ñ Ð
¼½½¿ »»
Ñ Ð Ñ Ó
Ø Ð
¼Ü »»
Ñ Ð Ñ Ü
Ñ Ð
Por padrão, literais inteiros têm um tipo pré-definido: int.
Ponto-Flutuante
Expressam números com decimais e/ou expoentes.
Exemplo:
¿º½ ½ »» ¿º½ ½ º¼¾ ¾¿ »» º¼¾ Ü ½¼ ¾¿ ½º ¹½ »» ½º Ü ½¼ ¹½ ¿º¼ »» ¿º¼
O tipo padrão para ponto-flutuante é double.
39
41.
Capítulo 6
I/O comArquivos
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ões
da 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 o
programa 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:
ÓÙØ ÇÐ ÅÙÒ Ó »» ÇÐ ÅÙÒ Ó ÑÔÖ ××Ó Ò Ø Ð
ÓÙØ Ü »» ÑÔÖ Ñ Ò Ø Ð Ó Ú ÐÓÖ Ü
ÓÙØ Ü »» ÑÔÖ Ñ ×ØÖ Ò »
Ö
Ø Ö Ü Ò Ø Ð
ÓÙØ ÇÐ ÅÙÒ Ó¸ ×ØÓ ÙÑ Ö × »» ÑÔÖ Ñ ÇÐ ÅÙÒ Ó¸ ×ØÓ ÙÑ Ö × º
ÓÙØ ÇÐ ÅÙÒ Ó¸ ר Ó ÒÙÑ Ü ÑÔÐÓ ÒÙÑÐ
Ó Ð Ó
O operador « insere o dado que o segue na stream que o precede. Nos casos anteriores, x
e a string "Olá Mundo"são inseridas em ’cout’, por exemplo. Deve-se ressaltar que o ’cout’ não
insere uma quebra de linha automática, devendo esta ser explicitada.
ÓÙØ Á×ØÓ ÙÑ Ö ×
ÓÙØ × Ñ ÕÙ Ö Ð Ò ÙØÓÑ Ø
º
O exemplo anterior será mostrado desta maneira:
Á×ØÓ ÙÑ Ö × × Ñ ÕÙ Ö Ð Ò ÙØÓÑ Ø
º
Já neste caso:
ÓÙØ Á×ØÓ ÙÑ Ö × Ò
ÓÙØ
ÓÑ ÕÙ Ö Ò
ÓÙØ Ð Ò ÙØÓÑ Ø
º
a frase será impressa desta maneira:
40
42.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Á×ØÓ ÙÑ Ö ×
ÓÑ ÕÙ Ö
Ð Ò ÙØÓÑ Ø
º
Para imprimirmos a frase com a quebra de linha também podemos usar o manipulador endl
(endline), da seguinte maneira:
ÓÙØ Ö ×
ÓÑ Ò Ð
ÓÙØ ÕÙ Ö Ð Ò Ò Ð
que mostrará na tela:
Ö ×
ÓÑ
ÕÙ Ö Ð Ò
O 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 seguido
pela variável que irá armazenar os dados que serão extraídos da stream. Desta maneira:
ÒØ ÒÙÑ ÖÓ
Ò ÒÙÑ ÖÓ
A primeira linha declara uma variável numero do tipo int e a segunda linha espera que o
usuá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 tecla
de retorno tiver sido pressionada. Com isso, mesmo se fizermos a requisição de um caracter
simples, a extração do cin não vai processar a entrada até que o usuário pressione a tecla de
retorno depois que o caracter for introduzido. Exemplo:
»» Ü ÑÔÐÓ ÒØÖ × ººº
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÒØ
ÓÙØ ÁÒ× Ö ÙÑ Ú ÐÓÖ ÒØ ÖÓ
Ò Ü
ÓÙØ Ç Ú ÐÓÖ Ò× Ö Ó Ü
ÓÙØ × Ù ÕÙ Ö Ó Ü¶Ü º Ò
Ö ØÙÖÒ ¼
resultado:
ÁÒ× Ö ÙÑ Ú ÐÓÖ ÒØ ÖÓ ½¼
Ç Ú ÐÓÖ Ò× Ö Ó ½¼ × Ù ÕÙ Ö Ó ½¼¼º
Podemos usar cin para pedir ao usuário que insira mais de um dado: São equivalentes os
dois exemplos:
41
43.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò Ü Ý
e
Ò Ü
Ò Ý
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ções
cin, temos que confiar que o usuário irá inserir os dados corretamente, sem caracteres ou algo
similar quando é preciso. Mais à frente, quando formos ver a classe stringstream, veremos uma
possível solução para esses tipos de erros.
Podemos ainda usar o cin para extrair strings da mesma maneira que fizemos com os outros
tipos de váriaveis usando o mesmo operador ».
Ò Ö ×
Contudo, essa extração com o cin para de ler dados do usuário assim que encontra um espaço
em branco. Sendo desta maneira, só podemos pegar uma palavra do usuário por extração, e não
uma frase inteira. Para pegarmos as frases inteiras podemos usar a função getline, que é mais
recomendável. Teremos, por exemplo, como resultado se o nome inserido pelo usuário for "Fulano
de Tal":
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ ×ØÖ Ò
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
×ØÖ Ò ÒÓÑ
ÓÙØ ÈÓÖ ÚÓÖ¸ Ò× Ö × Ù ÒÓÑ
ÓÑÔÐ ØÓ
ØÐ Ò ´
Ò¸ ÒÓÑ µ
ÓÙØ ÇÐ ¸ ÒÓÑ º Ò
Ö ØÙÖÒ ¼
resultado:
ÈÓÖ ÚÓÖ¸ Ò× Ö × Ù ÒÓÑ
ÓÑÔÐ ØÓ
ÇÐ ÙÐ ÒÓ Ì Ðº
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ção
ou inserção de/para strings, especialmente úteis para converter strings para valores numéricos e
vice-versa. Se quisermos extrair um inteiro de uma strings podemos fazer:
42
44.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
×ØÖ Ò ×ÒÙÑ ´ ½ µ
ÒØ ÒÙÑ ÖÓ
×ØÖ Ò ×ØÖ Ñ´×ÒÙѵ ÒÙÑ ÖÓ
Após isto, a variável numero deve conter o numérico 1997.
»» ×ØÖ Ò ×ØÖ Ñ×
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ ×ØÖ Ò
Ò
ÐÙ ××ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
×ØÖ Ò Ö
ÒØ ÒÓÒÙÑ ¼
ÒØ Ñ ×ÒÙÑ ¼
ÒØ ÒÙÑ ¼
ÓÙØ ÒØÖ
ÓÑ Ó ÒÓ Ó × Ù Ò ×
Ñ ÒØÓ
ØÐ Ò ´
Ò¸Ö
µ
×ØÖ Ò ×ØÖ Ñ´Ö
µ ÒÓÒÙÑ
ÓÙØ ÒØÖ
ÓÑ Ó Ñ × Ó × Ù Ò ×
Ñ ÒØÓ
ØÐ Ò ´
Ò¸Ö
µ
×ØÖ Ò ×ØÖ Ñ´Ö
µ Ñ ×ÒÙÑ
ÓÙØ ÒØÖ
ÓÑ Ó Ó × Ù Ò ×
Ñ ÒØÓ
ØÐ Ò ´
Ò¸Ö
µ
×ØÖ Ò ×ØÖ Ñ´Ö
µ ÒÙÑ
ÓÙØ Ø Ò ×
Ñ ÒØÓ ÒÙÑ Ñ ×ÒÙÑ ÒÓÒÙÑ Ò Ð
Ö ØÙÖÒ ¼
que resulta em:
ÒØÖ
ÓÑ Ó ÒÓ Ó × Ù Ò ×
Ñ ÒØÓ ½ ¾
ÒØÖ
ÓÑ Ó Ñ × Ó × Ù Ò ×
Ñ ÒØÓ ¼½
ÒØÖ
ÓÑ Ó Ó × Ù Ò ×
Ñ ÒØÓ ½
Ø Ò ×
Ñ ÒØÓ ½ ¼½ ½ ¾
43
45.
Capítulo 7
Estruturas deIteração e Desvios
Condicionais
7.1 Estruturas de Iteração
A maioria das linguagens de programação têm certas estruturas que servem para desviar o
controle 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:
´Ü ½¾¿µ
ÓÙØ Ç Ú ÐÓÖ Ü ½¾¿
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 as
linhas de código entre chaves , assim:
´Ü ½¾¿µ
ß
ÓÙØ Ç Ú ÐÓÖ Ü ½¾¿
ÓÙØ Ç Ú ÐÓÖ Ü Ò Ó ½¼¼
Se a condição tiver sido falsa e quisermos executar algum trecho de código neste caso, usa-
mos o Else:
´Ü ½¾¿µ
ÓÙØ Ç Ú ÐÓÖ Ü ×ÙÔ Ö ÓÖ ½¾¿
Ð× ´Ü ½¾¿µ
ÓÙØ Ç Ú ÐÓÖ Ü Ò Ö ÓÖ ½¾¿
Ð×
ÓÙØ Ç Ú ÐÓÖ Ü Þ ÖÓ
44
46.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Aqui, se o valor de x for superior a 123, ele imprime: Ç Ú ÐÓÖ Ü ×ÙÔ Ö ÓÖ ½¾¿ já se
o valor de x for inferior a 123, ele imprime: Ç Ú ÐÓÖ Ü Ò Ö ÓÖ ½¾¿ ou se for 0, ele
imprime: Ç Ú ÐÓÖ Ü Þ ÖÓº
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 for
satisfeita.
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÒØ Ò
ÓÙØ ÁÒ× Ö ÙÑ Ú ÐÓÖ Ò
Ó
Ò Ò
Û Ð ´Ò ¼µ ß
ÓÙØ Ò ¸
¹¹Ò
ÓÙØ ÇÇÅ Ò
Ö ØÙÖÒ ¼
O que resulta em:
ÁÒ× Ö ÙÑ Ú ÐÓÖ Ò
Ó
¸ ¸ ¸ ¸ ¿¸ ¾¸ ½¸ ÇÇÅ
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 atribuindo
um 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
47.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
OBS: ao criarmos a estrutura while, devemos levar em conta que ela deve terminar a algum
ponto. Para isso, devemos fornecer algum método para forçar a condição a se tornar falsa em
algum 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 bloco
seja executado ao menos 1 vez. Por exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÙÒ× Ò ÐÓÒ Ò
Ó ß
ÓÙØ ÁÒ× Ö ÙÑ Ú ÐÓÖ ´ÁÒ× Ö ¼ Ô Ö × Öµ
Ò Ò
ÓÙØ ÎÓ
Ò× Ö Ù Ò Ò
Û Ð ´Ò ¼µ
Ö ØÙÖÒ ¼
que retorna na tela:
ÁÒ× Ö ÙÑ Ú ÐÓÖ ´ÁÒ× Ö ¼ Ô Ö × Öµ ½¿¾
ÎÓ
Ò× Ö Ù ½¾¿
ÁÒ× Ö ÙÑ Ú ÐÓÖ ´ÁÒ× Ö ¼ Ô Ö × Öµ ¿¾½
ÎÓ
Ò× Ö Ù ¿¾½
ÁÒ× Ö ÙÑ Ú ÐÓÖ ´ÁÒ× Ö ¼ Ô Ö × Öµ ¼
ÎÓ
Ò× Ö Ù ¼
No 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 permanece
verdadeira, 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 é
ÓÖ ´ Ò
Ð Þ Ó
ÓÒ Ó Ò
Ö Ñ ÒØÓµß
Exemplo:
46
48.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÓÖ ´ ÒØ Ò ½¼ Ò ¼ Ò¹¹µ ß
ÓÙØ Ò ¸
ÓÙØ ÇÇÅ Ò
Ö ØÙÖÒ ¼
que mostra na tela:
½¼¸ ¸ ¸ ¸ ¸ ¸ ¸ ¿¸ ¾¸ ½¸ ÇÇÅ
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:
ÓÖ ´ Ò ½¼ µß
já as vírgulas podem ser usadas para especificar mais de uma expressão em um dos campos,
assim:
ÓÖ ´ Ò ¼¸ ½¼¼ Ò Ò··¸ ¹¹ µß
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:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÒØ Ü
ÓÖ ´Ü ½¼ Ü ¼ ܹ¹µ
ß
ÓÙØ Ü ¸
´Ü ¿µ
ß
ÓÙØ ÓÒØ Ñ Ò Ð Þ
Ö
Ö ØÙÖÒ ¼
47
49.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
que retorna:
½¼¸ ¸ ¸ ¸ ¸ ¸ ¸ ¿¸ ÓÒØ Ñ Ò Ð Þ
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:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÓÖ ´ ÒØ Ü ½¼ Ü ¼ ܹ¹µ ß
´Ü µ
ÓÒØ ÒÙ
ÓÙØ Ü ¸
ÓÙØ Ò Ð Ò
Ö ØÙÖÒ ¼
que mostra na tela:
½¼¸ ¸ ¸ ¸ ¸ ¸ ¿¸ ¾¸ ½¸ Ò Ð
Goto
O goto permite desviarmos para um ponto qualquer no programa. Por este motivo, deve ser
usado com cautela, já que sua execução causa um desvio incondicional que ignora qualquer tipo
de limite de escopo. O destino é definido com um label, que é usado como um argumento para o
goto. Este label é feito de um identificador válido seguido de dois-pontos (sorriso.
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÒØ Ü ½¼
ÐÓÓÔ
ÓÙØ Ü ¸
ܹ¹
´Ü ¼µ ÓØÓ ÐÓÓÔ
ÓÙØ Ò Ð Ò
Ö ØÙÖÒ ¼
que mostra na tela:
48
50.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
½¼¸ ¸ ¸ ¸ ¸ ¸ ¸ ¿¸ ¾¸ ½¸ Ò Ð
Exit
O exit é uma função definida na biblioteca cstdlib cuja função é terminar o programa atual com
um código específico. Seu protótipo é:
ÚÓ Ü Ø ´ ÒØ Ü Ø
Ó µ
O exitcode é usado por alguns sistemas operacionais e pode ser usado por programas que o
chamem. por convenção, um exitcode 0 significa que o programa terminou normalmente. Outros
valores 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:
×Û Ø
´ ÜÔÖ ×× Óµ
ß
×
ÓÒר ÒØ ½
ß ÐÓ
Ó
Ó ½
Ö
×
ÓÒר ÒØ ¾
ß ÐÓ
Ó
Ó ¾
Ö
º
º
º
ÙÐØ
ß ÐÓ
Ó
Ó Ô Ö Ó
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, o
programa desvia ao fim do switch.
Se o valor da expressão não for igual à constante_1, o switch checa a constante_2, seguindo o
mesmo procedimento anterior. Note que os três-pontos mostram que podem ser usadas quantas
constantes e blocos de códigos sejam necessáris. Se por ventura nenhuma dessas constantes
for igual ao valor da expressão, o switch executará o bloco_de_código_padrao, do default. Por
este 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 forem
usados, o switch poderá entrar na primeira clausula, por exemplo, e continuar executando
as outras sem interrução do loop. Esta é a importância do break dentro do switch. Apesar
disso, como o default deve ser o último label a ser inserido, ele não exige o desvio break.
49
51.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
• 2) O switch só pode ser usado para comparar expressões com constantes. Assim, não
podemos colocar variáveis como labels.
Ambos os seguintes trechos de código têm o mesmo funcionamento:
×Û Ø
´Üµ ß
× ½
ÓÙØ Ü ½
Ö
× ¾
ÓÙØ Ü ¾
Ö
ÙÐØ
ÓÙØ Î ÐÓÖ ×
ÓÒ
Ó Ü
Funciona da mesma maneira que:
´Ü ½µ ß
ÓÙØ Ü ½
Ð× ´Ü ¾µ ß
ÓÙØ Ü ¾
Ð× ß
ÓÙØ Î ÐÓÖ ×
ÓÒ
Ó Ü
Veja um outro exemplo de switch:
×Û Ø
´Ü¶¾µ
ß
× ¾
ß
ÓÙØ Ç Ú ÐÓÖ ÜÔÖ ×× Ó ¾º
Ö
×
ß
ÓÙØ Ç Ú ÐÓÖ ÜÔÖ ×× Ó º
Ö
×
ß
ÓÙØ Ç Ú ÐÓÖ ÜÔÖ ×× Ó º
Ö
ÙÐØ
ß
50
52.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÓÙØ Ç Ú ÐÓÖ ÜÔÖ ×× Ó ×
ÓÒ
Ó
que, no caso em que x é 3 resulta:
Ç Ú ÐÓÖ ÜÔÖ ×× Ó º
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++ pode
oferecer.
O formato padrão de funções é:
Ì ÔÓ Ó ÒÓÑ ÙÒ
Ó ´Ô Ö Ñ ØÖÓ½¸ Ô Ö Ñ ØÖÓ¾¸ ºººµß
ÐÓ
Ó
Ó ÙÒ
Ó
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á-la
quando for necessário. Os parâmetros podem ser quantos forem necessários. São tipos de
dados 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 a
função quando é chamada. Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ ×ÓÑ ´ ÒØ ¸ ÒØ µ
ß
ÒØ Ü
Ü ·
Ö ØÙÖÒ ´Üµ
ÒØ Ñ Ò ´µ
ß
ÒØ Ý
Ý ×ÓÑ ´¾¼¼¸½¼¼µ
ÓÙØ Ç Ö ×ÙÐØ Ó Ý
Ö ØÙÖÒ ¼
Que mostra na tela:
Ç Ö ×ÙÐØ Ó ¿¼¼º
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 os
parâmetros 200 e 100 retornará. Ao chamar a função soma, o controle é desviado para esta
função, que soma os dois numeros recebidos como parâmetros e retornam o resultado para onde
ela foi chamada. o valor de y resultante na função main então se altera para 300 e é impresso na
tela com o cout.
51
53.
CDTC Centro deDifusã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 numa
funçã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 erro
indicando que a variável não pode ser reconhecida pelo compilador. Da mesma maneira, z não
poderia ser utilizada na função soma.
Resumidamente, o escopo das variáveis segue o seguinte:
Variávels Locais
Seu escopo é limitado ao mesmo nível de bloco em que são declaradas.
Variáveis Globais
Variá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:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ ×Ù ØÖ
Ó ´ ÒØ ¸ ÒØ µ
ß
ÒØ Ö ×
Ö × ¹
Ö ØÙÖÒ ´Ö ×µ
ÒØ Ñ Ò ´µ
ß
ÒØ Ü ¸ Ý ¿¸ Þ
Þ ×Ù ØÖ
Ó´ ¸¾µ
ÓÙØ Ç ÔÖ Ñ ÖÓ Ö ×ÙÐØ Ó Þ ³ Ò³
ÓÙØ Ç × ÙÒ Ó Ö ×ÙÐØ Ó ×Ù ØÖ
Ó´ ¸¾µ ³ Ò³
ÓÙØ Ç Ø Ö
ÖÓ Ö ×ÙÐØ Ó ×Ù ØÖ
Ӵܸݵ ³ Ò³
Þ · ×Ù ØÖ
Ӵܸݵ
ÓÙØ Ç ÕÙ ÖØÓ Ö ×ÙÐØ Ó Þ ³ Ò³
Ö ØÙÖÒ ¼
,o que mostra na tela:
Ç ÔÖ Ñ ÖÓ Ö ×ÙÐØ Ó
Ç × ÙÒ Ó Ö ×ÙÐØ Ó
Ç Ø Ö
ÖÓ Ö ×ÙÐØ Ó ¾
Ç ÕÙ ÖØÓ Ö ×ÙÐØ Ó
52
54.
CDTC Centro deDifusã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. Mas
devemos saber que podemos não querer retornar valor algum. Imagine que somente queremos
que uma função retorne algo na tela. Não queremos, então, que ela retorne valor algum e usamos
o void para demonstrar isto ao compilador.
Exemplo de uso do void:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÚÓ Ñ Ò× Ñ´µ
ß
ÓÙØ Å Ò× Ñ ØÓ
ÒØ Ñ Ò ´µ
ß
Ñ Ò× Ñ´µ
Ö ØÙÖÒ ¼
, que retorna na tela:
Å Ò× Ñ ØÓ
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:
ÚÓ Ñ Ò× Ñ ´ÚÓ µ
ß
ÓÙØ Å Ò× Ñ ØÓ
2) Mesmo que a função não contenha parâmetros, é imprescindível o uso dos parênteses na
sua declaração:
ÚÓ Ñ Ò× Ñ ´µ
ß
ÓÙØ Ð Ð Ð
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"de
seus 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 valores
forem alterados ao longo da função, as variáveis originais continuarão tendo o mesmo valor fora
dela.
Parte do Exemplo anterior:
53
55.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÒØ Ü ¿¸ Ý
ÒØ Þ
Þ
Ӵܸݵ
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ão
foram 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, mas
sim o ENDEREÇO de uma variável global. Portanto, qualquer modificação que for realizada no
conteúdo deste parâmetro afetará também a variável global que está associada a ele. Durante a
execução do subprograma, ou função, os parâmetros passados por referência são análogos às
variáveis globais.
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÚÓ Ó ÖÓ´ ÒØ² ¸ ÒØ² ¸ ÒØ²
µ
ß
¶ ¾
¶ ¾
¶ ¾
ÒØ Ñ Ò ´µ
ß
ÒØ Ü ½¸ Ý ¿¸ Þ
Ó ÖӴܸ ݸ Þµ
ÓÙØ Ü Ü ¸ Ý Ý ¸ Þ Þ
Ö ØÙÖÒ ¼
,o que retorna na tela:
Ü ¾¸ Ý ¸ Þ ½
Note 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 o
programa ter chamado a função, os parâmetros x, y e z têm seus valores alterados, situação esta
que 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), o
valor anterior a ele e o valor posterior a ele. Veja:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
54
56.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÚÓ ÒØ ÔÓר´ ÒØ ܸ ÒØ² ÒØ¸ ÒØ² ÔÓרµ
ß
ÒØ ܹ½
ÔÓר Ü·½
ÒØ Ñ Ò ´µ
ß
ÒØ Ü ½¼¼¸ ݸ Þ
ÒØ ÔÓר´Ü¸ ݸ Þµ
ÓÙØ Î ÐÓÖ ÒØ Ö ÓÖ Ý ¸ Î ÐÓÖ ÈÓר Ö ÓÖ Þ
Ö ØÙÖÒ ¼
que, como o valor de x é 100, retorna na tela:
Î ÐÓÖ ÒØ Ö ÓÖ ¸ Î ÐÓÖ ÈÓר Ö ÓÖ ½¼½
7.4 Valores Padrões nos Parâmetros
Ao declararmos uma função podemos especificar um valor padrão para cada parâmetro. Este
valor será usado se o argumento correspondente for deixado em branco na hora de chamar a
função. Para isto, simplesmente usamos o operador de atribuição e um valor para os argumentos
na 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 na
chamada da função, este valor padrão é ignorado e o valor passado à função é usado.
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ú × Ó´ ÒØ ¸ ÒØ ¾µ
ß
ÒØ Ü
Ü »
Ö ØÙÖÒ ´Üµ
ÒØ Ñ Ò ´µ
ß
ÓÙØ Ú × Ó´½¾µ
ÓÙØ Ò Ð
ÓÙØ Ú × Ó´¾¼¸ µ
Ö ØÙÖÒ ¼
que resulta em:
55
57.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
No 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úmero
de parâmetros diferentes ou tipos diferentes nos parâmetros.
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ
Ð
ÙÐ Ö´ ÒØ ¸ ÒØ µ
ß
Ö ØÙÖÒ ´ ¶ µ
ÐÓ Ø
Ð
ÙÐ Ö´ ÐÓ Ø ¸ ÐÓ Ø µ
ß
Ö ØÙÖÒ ´ » µ
ÒØ Ñ Ò ´µ
ß
ÒØ Ü ¸Ý ¾
ÐÓ Ø Ò º¼¸Ñ ¾º¼
ÓÙØ
Ð
ÙРִܸݵ
ÓÙØ Ò
ÓÙØ
Ð
ÙРִҸѵ
ÓÙØ Ò
Ö ØÙÖÒ ¼
que retorna como resultado na tela:
½¼
¾º
Neste 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 para
sugerir ao compilador que o código gerado pelo corpo da função seja inserido em cada ponto de
chamada da função, ao invés de ser inserido apenas uma vez e ser feita uma chamada normal a
56
58.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ela, o que geralmente envolve um tempo de execução adicional.
Seu formato:
ÒÐ Ò Ø ÔÓ ÒÓÑ ÙÒ
Ó ´ Ö ÙÑ ÒØÓ× ººº µ
ß ÐÓ
Ó ÒרÖÙ
Ó ×
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ó indica
que 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:
Ò Ò ¶ ´Ò¹½µ ¶ ´Ò¹¾µ ¶ ´Ò¹¿µ ººº ¶ ½
em um programa teríamos:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÐÓÒ ØÓÖ Ð ´ÐÓÒ Üµ
ß
´Ü ½µ
Ö ØÙÖÒ ´Ü ¶ ØÓÖ Ð ´Ü¹½µµ
Ð×
Ö ØÙÖÒ ´½µ
ÒØ Ñ Ò ´µ
ß
ÐÓÒ ÒÙÑ
ÓÙØ ÁÒ× Ö ÙÑ Ú ÐÓÖ
Ò ÒÙÑ
ÓÙØ ÒÙÑ ØÓÖ Ð ´ÒÙѵ
Ö ØÙÖÒ ¼
que mostra na tela:
ÁÒ× Ö ÙÑ Ú ÐÓÖ ½¼
½¼ ¿ ¾ ¼¼
57
59.
CDTC Centro deDifusã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 valor
passado como argumento for maior que 1. Caso contrário, a função executa um loop infinito
recursivo em que, assim que atingir o valor 0, continuaria multiplicando por todos os números
negativos (o que provavelmente geraria um erro de overflow na execução). Neste exemplo, por
termos 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 no
código. Acontece que se fizermos o teste de inverter o main e declararmos as funções após
ele, teríamos erros de compilação, já que elas devem já ter sido declaradas para poderem ser
chamadas no main. No entanto, existe uma maneira de evitar termos que escrever o código
inteiro da função antes de chamá-la. Basta declararmos sua existência, ao invés da definição
completa. Esta declaração tem a forma:
Ø ÔÓ ÒÓÑ ÙÒ
Ó ´Ø ÔÓ Ö ÙÑ ÒØÓ½¸ Ø ÔÓ Ö ÙÑ ÒØÓ¾¸ ºººµ
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 dos
protótipos de uma função são válidas:
ÒØ ÙÒ
Ó½ ´ ÒØ ¸ ÒØ µ
ÒØ ÙÒ
Ó½ ´ ÒØ¸ ÒØµ
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÚÓ ÑÔ Ö´ ÒØ ܵ
ÚÓ Ô Ö´ ÒØ ܵ
ÒØ Ñ Ò ´µ
ß
ÒØ
Ó ß
ÓÙØ ÙÑ Ú ÐÓÖ ´ Ø ¼ Ô Ö × Öµ
Ò
ÑÔ Ö´ µ
Û Ð ´ ¼µ
Ö ØÙÖÒ ¼
ÚÓ ÑÔ Ö´ ÒØ ܵ
ß
´´Ü±¾µ ¼µ
ÓÙØ Æ Ñ ÖÓ ÑÔ Öº Ò
Ð× Ô Ö´Üµ
58
60.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÚÓ Ô Ö´ ÒØ ܵ
ß
´´Ü±¾µ ¼µ
ÓÙØ Æ Ñ ÖÓ Ô Öº Ò
Ð× ÑÔ Ö´Üµ
o que mostra na tela:
ÙÑ Ú ÐÓÖ ´ Ø ¼ Ô Ö × Öµ ¿
Æ Ñ ÖÓ ÑÔ Öº
ÙÑ Ú ÐÓÖ ´ Ø ¼ Ô Ö × Öµ ½¼¼¼
Æ Ñ ÖÓ Ô Öº
ÙÑ Ú ÐÓÖ ´ Ø ¼ Ô Ö × Öµ ½
Æ Ñ ÖÓ ÑÔ Öº
ÙÑ Ú ÐÓÖ ´ Ø ¼ Ô Ö × Öµ ¼
Æ Ñ ÖÓ Ô Öº
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ática
mostrou-se eficiente para a limpeza do código, já que isso acaba facilitando a localização das
funções existentes no programa.
59
61.
Capítulo 8
Vetores eSeqüência de Caracteres
8.1 Vetores
Um vetor ou array é uma série de elementos do mesmo tipo colocados em seqüencia em
locais 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 que
declarar 6 diferentes variáveis, cada uma com um identificador. Para fazer isso, criamos um vetor
com um identificador único (por exemplo vet) e referenciamos as posições usando índices (por
exemplo 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 antes
de usá-lo, como fizemos com as variáveis. Fazemos assim:
Ø ÔÓ ÒÓÑ Ó Ú ØÓÖ ÒÙÑ ÖÓ Ð Ñ ÒØÓ×℄
onde tipo é qualquer tipo válido ja conhecido (int, float, etc...), nome_do_vetor deve ser um
identificador 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 determinado
antes da execução. Exemplo:
ÒØ ÒÓØ × ¿¼℄
60
62.
CDTC Centro deDifusã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 valor
seja atribuído a eles. Localmente e globalmente, ao declararmos um vetor, podemos atribuir
valores iniciais às posições do vetor colocando-os entre chaves e separados por vírgulas (,).
Assim:
ÒØ ÒÓØ × ℄ ß ½¼¸ ¸ ¸ ¿¸
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 dos
colchetes [ ];
Acessando os valores
Para acessarmos os valores do vetor individualmente, como se fossem variáveis, podemos usar
índices, como já foi falado. Desta maneira:
ÒÓÑ Ó Ú ØÓÖ Ò
℄
,para armazenarmos um valor do vetor em uma variável separada fazemos por exemplo:
ÒØ Ü ÒÓØ × ¿℄
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 desta
meneira:
ÒÓØ × ¾℄
São também operações válidas de vetores:
ÒÓØ × ¼℄
ÒÓØ × ℄
Ü ÒÓØ × ·¾℄
ÒÓØ × ÒÓØ × ℄℄ ÒÓØ × ¾℄ · ¾
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 usados
para isolar os índices, na hora de acessar as posições do vetor. Exemplo:
61
63.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÒØ ÒÓØ × ℄
ÒÓØ × ¾℄
Exemplo de código com vetores:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ ÒÓØ × ℄ ß½¸ ¾¸ ¿¸ ¸
ÒØ Ò¸ Ö ×ÙÐØ Ó ¼
ÒØ Ñ Ò ´µ
ß
ÓÖ ´ Ò ¼ Ò Ò·· µ
ß
Ö ×ÙÐØ Ó · ÒÓØ × Ò℄
ÓÙØ Ö ×ÙÐØ Ó
Ö ØÙÖÒ ¼
, 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 Multidimensional
Ñ Ø, por exemplo, representa um vetor bidimensional de 4 por 5 do tipo inteiro. Declaramos
desta maneira:
ÒØ ÒÓÑ Ó ÖÖ Ý ÒÙÑ ÖÓ Ð Ò ×℄ ÒÙÑ ÖÓ
ÓÐÙÒ ×℄
Exemplo:
ÒØ Ñ Ø ℄ ℄
62
64.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Lembrando que os índices começam sempre em 0, referenciamos o 2º elemento verticalmente
e 3º horizontalmente, por exemplo (marcado em vermelho na figura), desta maneira:
Ñ Ø ½℄ ¾℄
8.3 Passando Vetores Como Parâmetros
Podemos querer, em algum momento, passar vetores como parâmetros de funções. Como
não é possível passar um bloco completo de memória por valor como um parâmetro, passamos
apenas os endereços. Na prática, tem quase o mesmo efeito e é mais eficiente e rápido. A única
coisa que necessitamos é especificar na declaração da função o tipo do vetor, um identificador e
os colchetes [ ]. Desta maneira:
ÚÓ ÙÒ
Ó ´ ÒØ Ú Ø ℄µ
ß ÐÓ
Ó ÒרÖÙ ×
A declaração de função anterior aceita um parâmetro do tipo "vetor de inteiros", neste caso o
vet. Para passar a esta função um vetor declarado como:
ÒØ Ú ØÓÖ ¿¼℄
,podemos chamar a funcao desta maneira:
ÙÒ
Ó´Ú Øµ
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÚÓ ÑÓ×ØÖ Ú ØÓÖ´ ÒØ Ú Ø ℄¸ ÒØ Ð Ò Ø µ ß
ÓÖ ´ ÒØ Ò ¼ Ò Ð Ò Ø Ò··µ
ÓÙØ Ú Ø Ò℄
ÓÙØ Ò
ÒØ Ñ Ò ´µ
ß
ÒØ Ú ØÓÖ½ ℄ ß ¸ ½¼¸ ½
ÒØ Ú ØÓÖ¾ ℄ ß¾¸ ¸ ¸ ¸ ½¼
ÑÓ×ØÖ Ú ØÓÖ´Ú ØÓÖ½¸¿µ
ÑÓ×ØÖ Ú ØÓÖ´Ú ØÓÖ¾¸ µ
Ö ØÙÖÒ ¼
,que mostra na tela:
½¼ ½
¾ ½¼
63
65.
CDTC Centro deDifusã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:
Ø ÔÓ ÒÓÑ ÙÒ
Ó ´Ø ÔÓ ÒÓÑ ℄ ÔÖÓ ÙÒ ℄ ÔÖÓ ÙÒ ℄µ
ß ÐÓ
Ó ÒרÖÙ ×
Exemplo:
ÚÓ ÙÒ
Ó ´ ÒØ ÑÙÐØ ℄ ¿℄ ℄µ
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 profundidade
de cada dimensão adicional.
8.4 Seqüencia de Caracteres
Assim como em várias linguagens, podemos representar em C++ as strings como vetores de
caracteres, já que elas são, na verdade, seqüências de caracteres. Desta maneira, a seguinte
expressão:
Ö Ö × ¿¼℄
,é 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 o
caracter null:
³ ¼³
Podemos representar graficamente como:
Figura 8.5: Seqüência de caracteres
Inicialização de seqüências de caracteres terminadas com null
Como podem ser considerados simples vetores, as seqüências de caracteres seguem as mesmas
regras. Se quisermos inicializar um vetor de caracteres com alguma seqüência pré-determinada,
por exemplo, fazemos igual a qualquer outro vetor:
Ö Ö × ℄ ß ³ ³¸ ³ ³¸ ³Ñ³¸ ³ ³¸ ³Î³¸ ³ ³¸ ³Ò³¸ ³ ³¸ ³Ó³¸ ³×³¸ ³ ¼³
64
66.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Arrays de caractere, no entanto, ainda contam com outro método para terem seus valores
inicializados: usando strings. Sabemos que:
ר ÙÑ Ö ×
é uma string cujo tipo é, na verdade, um array de caracteres. Então strings também contêm o
caracter null ao final. Com isso podem ser usados para inicializar um vetor de caracteres, desta
maneira:
Ö Ö × ℄ Ñ Î Ò Ó×
,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 deste
tipo:
Ö × Ñ Ú Ò Ó×
Ö × ß ³ ³¸ ³ ³¸ ³Ñ³¸ ³ ³¸ ³Î³¸ ³ ³¸ ³Ò³¸ ³ ³¸ ³Ó³¸ ³×³¸ ³ ¼³
Ö × ℄ Ñ Ú Ò Ó×
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 bloco
de memória.
Cin e cout suportam seqüências terminadas em null como containers válidos para seqüências
de caracteres. Podem, com isso, ser diretamente usados para extrair strings de caracteres do cin
ou para inserí-las no cout.
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
Ö Ô Ö ℄ ÈÓÖ ÚÓÖ¸ Ò× Ö × Ù ÈÖ Ñ ÖÓ ÒÓÑ
Ö Ö ×Ô ℄ Ñ Ú Ò Ó¸
Ö ÒÓÑ ¼℄
ÓÙØ Ô Ö
Ò ÒÓÑ
ÓÙØ Ö ×Ô ÒÓÑ
Ö ØÙÖÒ ¼
, o que mostrará:
ÈÓÖ ÚÓÖ¸ Ò× Ö × Ù ÈÖ Ñ ÖÓ ÒÓÑ Â Ð Ó
Ñ Ú Ò Ó¸ Â Ð Ó
65
67.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Como podemos ver, declaramos três arrays de caracteres. Nos dois primeiros, inicializamos
com strings e o terceiro não foi inicializado. Em todos os casos é necessário definir o tamanho do
vetor. Nos dois primeiros está implícito, definido pelo comprimento da string com que eles foram
inicializados. O último está explícito que são 90 posições. Por fim, seqüências de caracteres
armazenadas em vetores de caracteres podem ser facilmente convertidas em strings apenas
usando o operador de atribuição, desta maneira:
×ØÖ Ò ×ØÖ
Ö Ø ÜØ ℄ Ñ Ð
Ó
×ØÖ Ø ÜØ
66
68.
Capítulo 9
Ponteiros eMemória Dinâmica
9.1 Ponteiros
A memória do computador pode ser abstraída como uma sucessão de células, representando
as 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 um
bloco 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 da
variá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 onde
nossa variável está armazenada durante a execução com a finalidade de operar com posições
relativas a ela.
O endereço que identifica uma variável na memória é o que chamamos de uma referência àquela
variá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:
Ú Ö½ ²Ú Ö¾
Isto significa que estamos atribuindo var1 para o endereço da variável var2. Não estamos
falando sobre o conteúdo da variável em si ao preceder var2 pelo operador &, mas sim sobre sua
referência, seu endereço de memória. Mostrarei um exemplo simples para clarificar um pouco
mais.
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 na
memória, sendo este número somente para exemplificar). Veja o código:
Ú Ö½ ¼
Ú Ö¾ Ú Ö½
Ú Ö¿ ²Ú Ö½
Os valores contidos nas variáveis são:
67
69.
CDTC Centro deDifusã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 valor
era 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 var3
no último exemplo. Abstraindo novamente, ponteiros são ditos apontando para a variável cuja
referê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 identificador
do ponteiro pelo asterisco (*), que pode ser literalmente traduzido para "valor apontado por".
Exemplo:
Ú Ö ¶Ú Ö¿ »»Ú Ö Ù Ð Ó Ú ÐÓÖ ÔÓÒØ Ó ÔÓÖ Ú Ö¿º ÓÑÓ Ú Ö¿ ÖÑ Þ Ò Ó Ò Ö Ó ½¾
»»ººº Ó Ú ÐÓÖ
ÓÒØ Ó ÒÓ Ò Ö Ó ½¾¿ ¼¸ Ú Ö Ö
Ö ¼º
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. Note
que anteriormente fizemos as seguintes atribuições:
Ú Ö½ ¼
Ú Ö¿ ²Ú Ö½
Após estas atribuições, as seguintes sentenças retornariam true (verdadeiro) se executadas:
Ú Ö½ ¼
²Ú Ö½ ½¾¿
Ú Ö¿ ½¾¿
¶Ú Ö¿ ¼
68
70.
CDTC Centro deDifusã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:
Ø ÔÓ ¶ ÒÓÑ
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:
ÒØ ¶ ÒÙÑ
Ö ¶
ÐÓ Ø ¶ ÒÙÑ
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 para
o qual eles apontam não ocupam o mesmo espaço nem são do mesmo tipo: o primeiro aponta
para um int, o segundo para um char e o terceiro para um float. Com isso, apesar de serem todos
ponteiros, são ditos terem tipos diferentes: int*, char* e float* respectivamente.
OBS: é importante frisar que o asterisco (*) usado ao declararmos aqui um ponteiro só indica
que é um ponteiro, e não deve ser confundido com o operador visto anteriormente usado como
um referenciador, que também é escrito com um asterisco (*).
Exemplo de declaração de ponteiros:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÒØ Ú Ð½¸ Ú Ð¾
ÒØ ¶ ÔÓÒØ
ÔÓÒØ ²Ú н
¶ÔÓÒØ ½¼
ÔÓÒØ ²Ú о
¶ÔÓÒØ ¾¼
ÓÙØ Ú Ð½ Ú Ð½ Ò Ð
ÓÙØ Ú Ð¾ Ú Ð¾ Ò Ð
Ö ØÙÖÒ ¼
, o que retorna:
Ú Ð½ ½¼
Ú Ð¾ ¾¼
69
71.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Note que mesmo que não tenhamos diretamente setado um valor para val1 e val2, os dois
terminam com um valor setado indiretamente pelo uso de pont. Isto pois ao atribuirmos um valor
para o local de memória apontado por pont, modificamos o valor de val1 e val2. Note que um
ponteiro pode aceitar diversos valores diferentes durante o mesmo programa.
Um exemplo um pouco mais elaborado:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÒØ Ú Ð½ ¸ Ú Ð¾ ½
ÒØ ¶ Ô½¸ ¶ Ô¾
Ô½ ²Ú н »» Ô½ Ò Ö Ó Ú Ð½
Ô¾ ²Ú о »» Ô¾ Ò Ö Ó Ú Ð¾
¶Ô½ ½¼ »» Ú ÐÓÖ ÔÓÒØ Ó ÔÓÖ Ô½ ½¼
¶Ô¾ ¶Ô½ »» Ú ÐÓÖ ÔÓÒØ Ó ÔÓÖ Ô¾ Ú ÐÓÖ ÔÓÒØ Ó ÔÓÖ Ô½
Ô½ Ô¾ »» Ô½ Ô¾ ´Ú ÐÓÖ Ó ÔÓÒØ ÖÓ
ÓÔ Óµ
¶Ô½ ¾¼ »» Ú ÐÓÖ ÔÓÒØ Ó ÔÓÖ Ô½ ¾¼
ÓÙØ Ú Ð½ Ú Ð½ Ò Ð
ÓÙØ Ú Ð¾ Ú Ð¾ Ò Ð
Ö ØÙÖÒ ¼
,o que retorna na tela:
Ú Ð½ ½¼
Ú Ð¾ ¾¼
Note 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:
ÒØ ¶ Ô½¸ ¶ Ô¾
, que declara dois ponteiros usados no exemplo. Mas perceba que há um asterisco (*) para
cada ponteiro. Se não usássemos os dois asteriscos, deixando p2 sem o asterisco por exemplo,
o tipo dela seria somente int. Desta maneira:
ÒØ ¶ Ô½¸ Ô¾
Aqui, p1 tem o tipo int* mas p2 somente tem o tipo int, que não serviria de nada no exemplo.
70
72.
CDTC Centro deDifusã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 ambas
adição e subtração têm um diferente comportamento com ponteiros de acordo com o tamanho
do tipo de dados para o qual ele aponta. Quando vimos os tipos fundamentais vimos que alguns
ocupam mais ou menos memória que os outros. Por exemplo, assuma que numa certa máquina
char recebe 1 byte, short recebe 2 bytes, e long recebe 4. Suponha também que definimos 3
ponteiros:
Ö ¶Ô
Ö
× ÓÖØ ¶Ô× ÓÖØ
ÐÓÒ ¶ÔÐÓÒ
, e que saibamos que eles apontam para os locais de memória 1000, 2000 e 3000 respectiva-
mente. Então, se escrevermos:
Ô
Ö··
Ô× ÓÖØ··
ÔÐÓÒ ··
ou
Ô
Ö Ô
Ö · ½
Ô× ÓÖØ Ô× ÓÖØ · ½
ÔÐÓÒ ÔÐÓÒ · ½
, 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 para
o elemento seguinte do mesmo tipo em que ele foi definido, e assim o tamanho em bytes do
tipo apontado é adicionado ao ponteiro. Isto é aplicável ao adicionarmos ou subtrairmos algum
nú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 pode
levar a uma confusão:
¶Ô··
Como (++) tem precedêndia maior que (*), esta expressão é equivalente a *(p++). Então, o
que 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:
´¶Ôµ··
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 este
ponteiro. Se escrevermos:
71
73.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
¶Ô·· ¶Õ··
, 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 que
sejam incrementados. Seria equivalente a
¶Ô ¶Õ
··Ô
··Õ
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 um
asterisco (*) para cada nível de referência nas declarações.
Ö
Ö ¶
Ö ¶¶
³Þ³
²
²
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 de
memó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.
Ø Ñ Ø ÔÓ
Ö¶¶ ÙÑ Ú ÐÓÖ ¼ ¾
¶
Ø Ñ Ø ÔÓ
Ö¶ ÙÑ Ú ÐÓÖ ¾¿¼
¶¶
Ø Ñ Ø ÔÓ
Ö ÙÑ Ú ÐÓÖ ³Þ³
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
74.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
(tendo, com isso, tamanho indeterminado). Isto permite que ponteiros void apontem para dados
de qualquer tipo. Porém, têm uma limitação: o dado apontado por ele não pode ser referenciado
diretamente. Por esta razão, sempre teremos que escalar o endereço de um ponteiro void para
um outro tipo de ponteiro que aponte par aum tipo de dado concreto antes de referenciá-lo. São
extremamente úteis para passar parâmetros genéricos a uma função. Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÚÓ Ò
Ö Ñ ´ÚÓ ¶ Ó¸ ÒØ ÔØ ѵ
ß
´ ÔØ Ñ × Þ Ó ´
Öµ µ »»× Þ Ó Ö ØÓÖÒ Ó Ø Ñ Ò Ó Ñ ÝØ × × Ù Ô Ö Ñ ØÖÓº ÕÙ ¸ Ö
ß
Ö¶ Ô
Ö Ô
Ö ´
Ö¶µ Ó ··´¶Ô
Öµ
Ð× ´ÔØ Ñ × Þ Ó ´ ÒØµ µ
ß ÒØ¶ Ô ÒØ Ô ÒØ ´ ÒØ¶µ Ó ··´¶Ô ÒØµ
ÒØ Ñ Ò ´µ
ß
Ö ³Ü³
ÒØ ½ ¼¾
Ò
Ö Ñ ´² ¸× Þ Ó ´ µµ
Ò
Ö Ñ ´² ¸× Þ Ó ´ µµ
ÓÙØ ¸ Ò Ð
Ö ØÙÖÒ ¼
, que retornará na tela:
ݸ ½ ¼¿
9.1.4 Ponteiro Nulo
É um ponteiro de qualquer tipo que tem um valor especial que indica que não está apontando
para nenhum endereço.
Exemplo:
ÒØ ¶ Ô
Ô ¼ »» Ô Ø Ñ ÙÑ ÔÓÒØ ÖÓ ÒÙÐÓ
ÓÑÓ Ú ÐÓÖ
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 "lugar
nenhum", enquanto um ponteiro void é um tipo especial que ponteiro que pode apontar para
algum 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
75.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
passada como referência. Para declarar um ponteiro para uma função temos que declarar como
o protótipo de uma função exceto com o nome da função entre parênteses (), e um asterisco (*)
é inserido antes do nome:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ
Ó´ ÒØ ¸ ÒØ µ
ß Ö ØÙÖÒ ´ · µ
ÒØ ×Ù ØÖ
Ó´ ÒØ ¸ ÒØ µ
ß Ö ØÙÖÒ ´ ¹ µ
ÒØ ÓÔ Ö
Ó´ ÒØ ܸ ÒØ ݸ ÒØ ´¶
Ñ ÙÒ
µ´ ÒØ¸ ÒØµµ
ß
ÒØ
´¶
Ñ ÙÒ
µ´Ü¸Ýµ
Ö ØÙÖÒ ´ µ
ÒØ Ñ Ò ´µ
ß
ÒØ ѸÒ
ÒØ ´¶Ñ ÒÓ×µ´ ÒØ¸ ÒØµ ×Ù ØÖ
Ó
Ñ ÓÔ Ö
Ó´ ¸ ¸
Óµ
Ò ÓÔ Ö
Ó´¾¼¸ Ѹ Ñ ÒÓ×µ
ÓÙØ Ò
Ö ØÙÖÒ ¼
, 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:
ÒØ ´¶ Ñ ÒÙ×µ´ ÒØ¸ ÒØµ ×Ù ØÖ
Ø ÓÒ
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 durante
a execução, por exemplo no caso em que queiramos que o próprio usuário insira a quantidade
necessária de espaço em memória, temos que descartar as estruturas estáticas como vetores e
passar 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
76.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
elementos entre colchetes [ ]. Retorna um ponteiro para o começo do novo bloco de memória
alocada.
Seu formato é:
ÔÓÒØ ÖÓ Ò Û Ø ÔÓ
ÔÓÒØ ÖÓ Ò Û Ø ÔÓ ÒÙÑ ÖÓ Ð Ñ ÒØÓ×℄
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:
ÒØ ¶ ÙÐ ÒÓ
ÙÐ ÒÓ Ò Û ÒØ ℄
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 fulano
aponta para um bloco de memória válido com espaço para 5 elementos do tipo int. O primeiro
elemento 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 por
diante.
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 nosso
requerimento 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 que
quando 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:
ÙÐ ÒÓ Ò Û ÒØ ℄ »»× Ð Ö¸ ÙÑ Ü
Ó Ð Ò º
O outro método é conhecido como nothrow, e o que acontece quando é usado é que quando
a 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 pode
ser especificado usando um objeto especial chamado nothrow, declarado no cabeçalho <new>,
como um argumento para new:
ÙÐ ÒÓ Ò Û ´ÒÓØ ÖÓÛµ ÒØ ℄
Neste caso, se a alocação falhar, o erro poderá ser detectado checando se fulano recebeu um
ponteiro nulo:
ÒØ ¶ ÙÐ ÒÓ
ÙÐ ÒÓ Ò Û ´ÒÓØ ÖÓÛµ ÒØ ℄
´ ÙÐ ÒÓ ¼µ ß
»» ÖÖÓ ÐÓ
Ó Ñ ÑÓÖ º
75
77.
CDTC Centro deDifusã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 que
ser avaliado após cada e toda alocação de memória. No entanto, usaremos em alguns exemplos
devido à sua simplicidade. Entretanto, para projetos maiores, pode ser um método que se torna
tedioso, onde o método de exceções é preferido, método este que será melhor explicado adiante
no 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 de
memória dinâmica. Faremos esta limpeza usando o operador delete, cujo formato é:
Ð Ø ÔÓÒØ ÖÓ
Ð Ø ℄ ÔÓÒØ ÖÓ
A primeira pode ser usada para limpar memória alocada para um único elemento, e a segunda
para memória alocada para vetores de elementos. O valor passado como argumento ao delete
deve ser ou um ponteiro para um bloco de memória previamente alocado com o new, ou um
ponteiro nulo (neste caso, não surtindo efeito algum). Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ Ò Û
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ
ß
ÒØ ¸Ü
ÒØ ¶ ÔÓÒØ
ÓÙØ ÉÙ ÒØÓ× Ò Ñ ÖÓ× Óר Ö ×
Ö Ú Ö
Ò
ÔÓÒØ Ò Û ´ÒÓØ ÖÓÛµ ÒØ ℄
´ÔÓÒØ ¼µ
ÓÙØ ÖÖÓ Ñ Ñ Ö Ò Ó Ô × Ö ÐÓ
Ð×
ß
ÓÖ ´Ü ¼ Ü Ü··µ
ß
ÓÙØ ÁÒ× Ö ÙÑ Ò Ñ ÖÓ
Ò ÔÓÒØ Ü℄
ÓÙØ ÎÓ
Ò× Ö Ù
ÓÖ ´Ü ¼ Ü Ü··µ
ÓÙØ ÔÓÒØ Ü℄ ¸
Ð Ø ℄ ÔÓÒØ
Ö ØÙÖÒ ¼
, o que retorna na tela:
ÉÙ ÒØÓ× Ò Ñ ÖÓ× Óר Ö ×
Ö Ú Ö
76
78.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÁÒ× Ö ÙÑ Ò Ñ ÖÓ ¿¾
ÁÒ× Ö ÙÑ Ò Ñ ÖÓ ¾
ÁÒ× Ö ÙÑ Ò Ñ ÖÓ ½
ÁÒ× Ö ÙÑ Ò Ñ ÖÓ
ÎÓ
Ò× Ö Ù ¿¾¸ ¾ ¸ ½ ¸ ¸
Note que o valor entre colchetes na sentença new é um valor variável inserido pelo usuário
(i), não um valor constante:
ÓÙØ ÉÙ ÒØÓ× Ò Ñ ÖÓ× Óר Ö ×
Ö Ú Ö
Ò
ÔÓÒØ Ò Û ´ÒÓØ ÖÓÛµ ÒØ ℄
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:
ÖÖÓ Ñ Ñ Ö Ò Ó Ô × Ö ÐÓ
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, se
usarmos 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ção
do 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 usarmos
a linguagem C, memória dinâmica pode ser usada através das funções malloc, calloc, realloc e
free, definidas na biblioteca cstdlib. Como C++ é um superset de C, essas funções também
estã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 cada
um deve ser manipulado com seu próprio set de funções ou operadores.
77
79.
Capítulo 10
Estruturas deDados
Uma estrutura de dados é uma junção de elementos de dados agrupados recebendo um
nome. Esses elementos ou membros podem ter tipos diferentes e tamanhos diferentes. Estrutu-
ras de dados são declaradas em C++ na sintaxe:
רÖÙ
Ø ÒÓÑ ×ØÖÙØÙÖ ß
Ñ Ñ ÖÓ Ø ÔÓ½ Ñ Ñ ÖÓ ÒÓÑ ½
Ñ Ñ ÖÓ Ø ÔÓ¾ Ñ Ñ ÖÓ ÒÓÑ ¾
º
º
º
Ñ Ñ ÖÓ Ø ÔÓÜ Ñ Ñ ÖÓ ÒÓÑ Ü
ÒÓÑ Ó Ó ØÓ
onde nome_da_estrutura é um nome para o tipo de estrutura, nome_do_objeto pode ser um
set de identificadores válidos para objetos que têm o tipo desta estrutura. Entre chaves, existe
uma lista com os membros de dados, cada um especificado com um tipo e um indentificador
válido como nome.
Uma estrutura de dados cria um novo tipo: assim que uma estrutura é declarada, um novo tipo
com um identificador especificado como nome_da_estrutura é criado e pode ser usado no resto
do programa como se fosse um novo tipo.
Exemplo:
רÖÙ
Ø ÔÖÓ ÙØÓß
ÒØ Ô ×Ó
ÐÓ Ø ÔÖ
Ó
ÔÖÓ ÙØÓ
ÖÒ
ÔÖÓ ÙØÓ ÖÖÓÞ¸ Ó
Primeiro declaramos uma estrutura com 2 membros: peso e preço, e depois usamos essa
estrutura 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 declarar
objetos (variáveis) deste novo tipo. No fim da declaração e antes dos dois-pontos finais podemos
usar o campo opcional nome_do_objeto para declarar diretamente objetos do tipo da estrutura.
78
80.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Por exemplo, podemos também declarar os objetos da estrutura carne, arroz e feijao no momento
em que definimos o tipo da estrutura de dados assim:
רÖÙ
Ø ÔÖÓ ÙØÓß
ÒØ Ô ×Ó
ÐÓ Ø ÔÖ
Ó
ÖÒ ¸ ÖÖÓÞ¸ Ó
É importante diferenciar o que é o nome do tipo da estrutura e o que é um objeto (variável) que
tem 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 entre
o nomedo objeto e o nome do membro. Por exemplo, podemos operar com qualquer destes
elementos como se eles fossem variáveis padrão de seus respectivos tipos:
ÖÒ ºÔ ×Ó
ÖÒ ºÔÖ
Ó
ÖÖÓÞºÔ ×Ó
ÖÖÓÞºÔÖ
Ó
ÓºÔ ×Ó
ÓºÔÖ
Ó
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:
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ ×ØÖ Ò
Ò
ÐÙ ××ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
רÖÙ
Ø ÐÑ × Ø ß
×ØÖ Ò Ø ØÙÐÓ
ÒØ ÒÓ
Ñ Ù¸ × Ù
ÚÓ ÑÓ×ØÖ ÐÑ ´ ÐÑ × Ø ÐÑ µ
ÒØ Ñ Ò ´µ
ß
×ØÖ Ò ×ØÖ
Ñ ÙºØ ØÙÐÓ Ì Ø Ò
Ñ Ùº ÒÓ ½
ÓÙØ ÁÒ× Ö Ó Ø ØÙÐÓ Ó ÐÑ
ØÐ Ò ´
Ò¸× ÙºØ ØÙÐÓµ
ÓÙØ ÁÒ× Ö Ó ÒÓ
79
81.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ØÐ Ò ´
Ò¸×ØÖµ
×ØÖ Ò ×ØÖ Ñ´×ØÖµ × Ùº ÒÓ
ÓÙØ Å Ù ÐÑ ÚÓÖ ØÓ Ò
ÑÓ×ØÖ ÐÑ ´Ñ Ùµ
ÓÙØ Ó × Ù Ò
ÑÓ×ØÖ ÐÑ ´× Ùµ
Ö ØÙÖÒ ¼
ÚÓ ÑÓ×ØÖ ÐÑ ´ ÐÑ × Ø ÐÑ µ
ß
ÓÙØ ÐÑ ºØ ØÙÐÓ
ÓÙØ ´ ÐÑ º ÒÓ µ Ò
, que retorna na tela:
ÁÒ× Ö Ó Ø ØÙÐÓ Ó ÐÑ Ð Ò
ÁÒ× Ö Ó ÒÓ ½
Å Ù ÐÑ ÚÓÖ ØÓ
Ì Ø Ò
´½ µ
Ó × Ù
Ð Ò ´½ µ
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 é uma
variável válida do tipo string. Os objetos meu e seu também podem ser tratados como variáveis
válidas do tipo filmes_t, por exemplo se as tivéssemos passado para a função mostrafilme como
teríamos feito com variáveis comuns. Assim, uma das mais importantes vantagens das estruturas
de dados é que podemos nos referir tanto a seus membros individualmente quanto à estrutura
inteira 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.
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ ×ØÖ Ò
Ò
ÐÙ ××ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ò Æ ÁÄÅ Ë ¿
רÖÙ
Ø ÐÑ × Ø ß
×ØÖ Ò Ø ØÙÐÓ
ÒØ ÒÓ
ÐÑ× Æ ÁÄÅ Ë℄
80
82.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÚÓ ÑÓ×ØÖ ÐÑ ´ ÐÑ × Ø ÐÑ µ
ÒØ Ñ Ò ´µ
ß
×ØÖ Ò ×ØÖ
ÒØ Ò
ÓÖ ´Ò ¼ Ò Æ ÁÄÅ Ë Ò··µ
ß
ÓÙØ ÁÒ× Ö Ó Ø ØÙÐÓ
ØÐ Ò ´
Ò¸ ÐÑ× Ò℄ºØ ØÙÐÓµ
ÓÙØ ÁÒ× Ö Ó ÒÓ
ØÐ Ò ´
Ò¸×ØÖµ
×ØÖ Ò ×ØÖ Ñ´×ØÖµ ÐÑ× Ò℄º ÒÓ
ÓÙØ ÒÎÓ
Ò× Ö Ù ×Ø × ÐÑ × Ò
ÓÖ ´Ò ¼ Ò Æ ÁÄÅ Ë Ò··µ
ÑÓ×ØÖ ÐÑ ´ ÐÑ× Ò℄µ
Ö ØÙÖÒ ¼
ÚÓ ÑÓ×ØÖ ÐÑ ´ ÐÑ × Ø ÐÑ µ
ß
ÓÙØ ÐÑ ºØ ØÙÐÓ
ÓÙØ ´ ÐÑ º ÒÓ µ Ò
, o que retorna na tela:
ÁÒ× Ö Ó Ø ØÙÐÓ Ð ÊÙÒÒ Ö
ÁÒ× Ö Ó ÒÓ ½ ¾
ÁÒ× Ö Ó Ø ØÙÐÓ Å ØÖ Ü
ÁÒ× Ö Ó ÒÓ ½
ÁÒ× Ö Ó Ø ØÙÐÓ Ì Ü Ö Ú Ö
ÁÒ× Ö Ó ÒÓ ½
ÎÓ
Ò× Ö Ù ×Ø × ÐÑ ×
Ð ÊÙÒÒ Ö ´½ ¾µ
Å ØÖ Ü ´½ µ
Ì Ü Ö Ú Ö ´½ µ
Ponteiros para Estruturas
Como qualquer outro tipo, estruturas podem ser apontadas por seus próprios tipos de pontei-
ros.
רÖÙ
Ø ÐÑ × Ø ß
×ØÖ Ò Ø ØÙÐÓ
81
83.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÒØ ÒÓ
ÐÑ × Ø ÐÑ
ÐÑ × Ø ¶ Ô ÐÑ
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:
Ô ÐÑ ² ÐÑ
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
(-).
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ ×ØÖ Ò
Ò
ÐÙ ××ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
רÖÙ
Ø ÐÑ × Ø ß
×ØÖ Ò Ø ØÙÐÓ
ÒØ ÒÓ
ÒØ Ñ Ò ´µ
ß
×ØÖ Ò ×ØÖ
ÐÑ × Ø ÐÑ
ÐÑ × Ø ¶ Ô ÐÑ
Ô ÐÑ ² ÐÑ
ÓÙØ ÁÒ× Ö ÙÑ Ø ØÙÐÓ
ØÐ Ò ´
Ò¸ Ô ÐÑ ¹ Ø ØÙÐÓµ
ÓÙØ ÁÒ× Ö Ó ÒÓ
ØÐ Ò ´
Ò¸ רֵ
´×ØÖ Ò ×ØÖ Ñµ ×ØÖ Ô ÐÑ ¹ ÒÓ
ÓÙØ ÒÎÓ
Ò× Ö Ù Ò
ÓÙØ Ô Ð Ñ¹ Ø ØÙÐÓ
ÓÙØ ´ Ô ÐÑ ¹ ÒÓ µ Ò
Ö ØÙÖÒ ¼
, o que retorna na tela:
ÁÒ× Ö ÙÑ Ø ØÙÐÓ Ì Ø Ò
82
84.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÁÒ× Ö Ó ÒÓ ½
ÎÓ
Ò× Ö Ù
Ì Ø Ò
´½ µ
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 um
objeto para o qual temos uma referência. No exemplo usamos:
Ô ÐÑ ¹ Ø ØÙÐÓ
, que é equivalente a:
´¶Ô ÐÑ µºØ ØÙÐÓ
Ambas 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:
¶Ô ÐÑ ºØ ØÙÐÓ
,que é equivalente a
¶´Ô ÐÑ ºØ ØÙÐÓµ
, 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 resume
possíveis combinações de ponteiros e membros de estruturas:
ÜÔÖ ×× Ó Ç ÕÙ Ú Ð Ó ÕÙ Ú Ð ÒØ
º Å Ñ ÖÓ Ó Ó ØÓ
¹ Å Ñ ÖÓ Ó Ó ØÓ ÔÓÒØ Ó ÔÓÖ ´¶ µº
¶ º Î ÐÓÖ ÔÓÒØ Ó Ô ÐÓ Ñ Ñ ÖÓ Ó Ó ØÓ ¶´ º µ
Estruturas Aninhadas
Estruturas também podem ser aninhadas:
רÖÙ
Ø ÐÑ × Ø ß
×ØÖ Ò Ø ØÙÐÓ
ÒØ ÒÓ
רÖÙ
Ø Ñ Ó× Ø ß
×ØÖ Ò ÒÓÑ
×ØÖ Ò Ñ Ð
ÐÑ × Ø ÚÓÖ ØÓ ÐÑ
ÙÐ ÒÓ¸ ÐØÖ ÒÓ
Ñ Ó× Ø ¶ Ô Ñ Ó× ² ÙÐ ÒÓ
Após a declaração anterior, podemos usar qualquer uma das seguintes expressões:
83
85.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÙÐ ÒÓºÒÓÑ
ÐØÖ ÒÓº ÚÓÖ ØÓ ÐÑ ºØ ØÙÐÓ
ÙÐ ÒÓº ÚÓÖ ØÓ ÐÑ º ÒÓ
Ô Ñ Ó×¹ ÚÓÖ ØÓ ÐÑ º ÒÓ
onde, 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:
ØÝÔ Ø ÔÓ Ü ×Ø ÒØ ℄ ÒÓÚÓ Ø ÔÓ℄
Exemplo:
ØÝÔ
Ö
ØÝÔ
Ö Ð ¼℄
ØÝÔ ÙÒ× Ò ÒØ ÏÇÊ
ØÝÔ
Ö ¶ Ô Ö
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:
Ö
¸
Ö
¾¸ ¶ÔÔ
½
ÏÇÊ ÚÔ Ð
Ô Ö ÔÔ
¾
Ð ÒÓÑ
É 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 dois
sã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ível
que precisamos modificar o tipo em versões posteriores do nosso programa, ou se um tipo que
queremos 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 a
das estruturas mas sua funcionalidade é totalmente diferente:
ÙÒ ÓÒ ÒÓÑ ÙÒ Ó ß
Ø ÔÓ Ó Ñ Ñ ÖÓ½ ÒÓÑ Ó Ñ Ñ ÖÓ½
Ø ÔÓ Ó Ñ Ñ ÖÓ¾ ÒÓÑ Ó Ñ Ñ ÖÓ¾
Ø ÔÓ Ó Ñ Ñ ÖÓ¿ ÒÓÑ Ó Ñ Ñ ÖÓ¿
º
º
ÒÓÑ × Ó× Ó ØÓ×
84
86.
CDTC Centro deDifusã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. Seu
tamanho é um dos maiores elementos da declaração. Por exemplo:
ÙÒ ÓÒ Ø ÔÓ× Ø ß
Ö
ÒØ
ÐÓ Ø
Ø ÔÓ×
define três elementos:
Ø ÔÓ׺
Ø ÔÓ׺
Ø ÔÓ׺
cada 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 podemos
armazenar valores diferentes neles independentemente. Um dos usos do union é unir um tipo
elementar com um array ou estrutura de elementos menores.
Exemplo:
ÙÒ ÓÒ Ñ Ü Ø ß
ÐÓÒ Ð
רÖÙ
Ø ß
× ÓÖØ
× ÓÖØ ÐÓ
×
Ö
℄
Ñ Ü
define três nomes que nos permitem acessar o mesmo grupo de 4 bytes: mix.l, mix.s, mix.c e
que podemos usar de acordo com como queremos acessar esses bytes, como se fossem um tipo
long 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 usual
רÖÙ
Ø ß
Ö Ø ØÙÐÓ ¼℄
Ö ÙØÓÖ ¼℄
ÙÒ ÓÒ ß
85
87.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÐÓ Ø ÓÐ Ö ×
ÒØ Ò ×
ÔÖ
Ó
Ð ÚÖÓ
-estrutura com union anônima
רÖÙ
Ø ß
Ö Ø ØÙÐÓ ¼℄
Ö ÙØÓÖ ¼℄
ÙÒ ÓÒ ß
ÐÓ Ø ÓÐ Ö ×
ÒØ Ò ×
Ð ÚÖÓ
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 e
ienes de um objeto deste tipo. Para um objeto do primeiro tipo, seria:
Ð ÚÖÓºÔÖ
Óº ÓÐ Ö ×
Ð ÚÖÓºÔÖ
Óº Ò ×
Em contrapartida, para um objeto do segundo tipo, seria:
Ð ÚÖÓº ÓÐ Ö ×
Ð ÚÖÓº Ò ×
Lembrando 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 para
armazenar dois diferentes valores simultaneamente. Podemos setar um valor para preco em
dolares 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 aos
valores que tipos de dados fundamentais podem ter.
Têm forma:
ÒÙÑ ÒÓÑ ÒÙÑ Ö
Óß
Ú ÐÓÖ½¸
Ú ÐÓÖ¾¸
Ú ÐÓÖ¿¸
º
º
ÒÓÑ × Ó× Ó ØÓ×
Por exemplo, podemos criar um novo tipo de variável chamada cores para armazenar as cores
com a seguinte declarações:
86
88.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÒÙÑ
ÓÖ × Ø ßÔÖ ØÓ¸ ÞÙи Ú Ö ¸
ÒÞ ¸ Ú ÖÑ Ð Ó¸ ÖÓÜÓ¸ Ñ Ö ÐÓ¸ Ö Ò
Ó
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 valores
possíveis que variáveis do novo tipo cores_t podem ter são novos valores constantes incluídos
entre aspas . Por exemplo, serão válidas após a declaração anterior:
ÓÖ × Ø ÑÝ
ÓÐÓÖ
ÓÖ ÞÙÐ
´
ÓÖ Ú Ö µ
ÓÖ Ú ÖÑ Ð Ó
Enumerações são tipos compatíveis com variáveis numéricas, então suas constantes são
sempre atribuídas a um valor numérico inteiro internamente. Se não for especificado, o valor
inteiro 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, azul
equivalente a 1, verde a 2 e assim sucessivamente. Podemos especificar um valor inteiro para
cada 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:
ÒÙÑ Ñ × × Ø ß Ò ÖÓ ½¸ Ú Ö ÖÓ¸ Ñ Ö
Ó¸ Ö Ð¸
Ñ Ó¸ ÙÒ Ó¸ ÙÐ Ó¸ Óרӏ
× Ø Ñ ÖÓ¸ ÓÙØÙ ÖÓ¸ ÒÓÚ Ñ ÖÓ¸ Þ Ñ ÖÓ Ý¾
Neste caso, a variável y2k do tipo enumerado meses_t pode conter qualquer uma das 12
possibilidades, que vão de janeiro a dezembro e que são equivalentes a valores entre 1 e 12 (não
entre 0 e 11, já que fizemos janeiro ser igual a 1) .
87
89.
Capítulo 11
Programação Orientadaa Objeto - POO
11.1 Classes
Uma classe em C++ é um conceito expandido de estrutura de dados: ao invés de conter
apenas dados, pode conter dados e funções. Um objeto é uma instanciação de uma classe. Em
termos 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):
Ð ×× ÒÓÑ
Ð ×× ß
×Ô
ÓÖ
××Ó½
Ñ Ñ ÖÓ½
×Ô
ÓÖ
××Ó½
Ñ Ñ ÖÓ¾
ººº
ÒÓÑ Ó× Ó ØÓ×
, onde mebros podem ser dados, declarações de funções ou opcionalmente especificadores
de acesso. Os últimos podem ser uma das três palavras-chave: private, public, protected. Estes
especificadores 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 mesma
classe ou de seus friends (explicado em lições posteriores).
• membros protected são acessíveis de membros da mesma classe e de seus friends, mas
també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 ser
que estejam especificados. Exemplo de uma classe:
Ð ×× Ê Ø Ò ÙÐÓß
ÒØ ܸ Ý
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ ×´ ÒØ¸ ÒØµ
ÒØ Ö ´ÚÓ µ
Ö Ø Ò
88
90.
CDTC Centro deDifusã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 primeiros
private e os dois últimos public.
Exemplo de acesso aos elementos public:
Ö Ø Ò º× Ø Ú ÐÓÖ ×´¿¸ µ
Ü Ö Ø Ò º Ö ´µ
Exemplo completo de Retângulo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ê Ø Ò ÙÐÓß
ÒØ ܸ Ý
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ¸ ÒØµ
ÒØ Ö ´µ ßÖ ØÙÖÒ ´Ü¶Ýµ
ÚÓ Ê Ø Ò ÙÐÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ ß
Ü
Ý
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò
Ö Ø Ò º× Ø Ú ÐÓÖ × ´¿¸ µ
ÓÙØ Ö Ö Ø Ò º Ö ´µ
Ö ØÙÖÒ ¼
, que retorna na tela:
Ö ½¾
Note 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, e
sua 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 se
esta definição de função estivesse diretamente incluída na definição da classe. Por exemplo, na
função seta_valores() do código anterior pudemos usar x e y, que são membros private da classe
Retangulo (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. Por
exemplo, seguindo o exemplo anterior, podemos ter declarado o objeto retang2 em adição a re-
tang:
89
91.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ê Ø Ò ÙÐÓ ß
ÒØ ܸ Ý
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ¸ ÒØµ
ÒØ Ö ´µ ßÖ ØÙÖÒ ´Ü¶Ýµ
ÚÓ Ê Ø Ò ÙÐÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ ß
Ü
Ý
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò ¸ Ö Ø Ò ¾
Ö Ø Ò º× Ø Ú ÐÓÖ × ´¿¸ µ
Ö Ø Ò ¾º× Ø Ú ÐÓÖ × ´ ¸ µ
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ½ Ö Ø Ò º Ö ´µ Ò Ð
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ¾ Ö Ø Ò ¾º Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que mostra:
Ö Ó Ê Ø Ò ÙÐÓ½ ½¾
Ö Ó Ê Ø Ò ÙÐÓ¾ ¿¼
Neste 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ável
membro e funções membro. Note que chamar retang.area() não nos dá o mesmo reultado que
chamar retang2.area(). Isto acontece pois cada objeto da classe Retangulo tem suas próprias
variá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âmetros
mas, ao invés disso, manipulamos objetos que têm seus próprios dados e funções embutidos
como 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 de
seus 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
92.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
inesperados durante suas execuções. Por exemplo, o que aconteceria se no exemplo anterior
chamá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 para
os 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. Este
construtor tem que ter o mesmo nome da classe e não deve ter nenhum tipo de retorno, nem
mesmo void.
Exemplo de implementação de Retangulo incluindo um construtor:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ê Ø Ò ÙÐÓ ß
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
Ê Ø Ò ÙÐÓ ´ ÒØ¸ ÒØµ
ÒØ Ö ´µ ßÖ ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ¶ ÐØÙÖ µ
Ê Ø Ò ÙÐÓ Ê Ø Ò ÙÐÓ ´ ÒØ ¸ ÒØ µ ß
ÓÑÔÖ Ñ ÒØÓ
ÐØÙÖ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò ´¿¸ µ
Ê Ø Ò ÙÐÓ Ö Ø Ò ¾ ´ ¸ µ
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ½ Ö Ø Ò º Ö ´µ Ò Ð
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ¾ Ö Ø Ò ¾º Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que retorna:
Ö Ó Ê Ø Ò ÙÐÓ½ ½¾
Ö Ó Ê Ø Ò ÙÐÓ¾ ¿¼
Perceba 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 tarefa
similar: 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ão
criados:
Ê Ø Ò ÙÐÓ Ö Ø Ò ´¿¸ µ
Ê Ø Ò ÙÐÓ Ö Ø Ò ¾ ´ ¸ µ
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á os
destrutores têm a funcionalidade oposta: são automaticamente chamados quando um objeto é
91
93.
CDTC Centro deDifusã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 como
um 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ória
dinamicamente durante seu tempo de vida e no momento de ser destruído, queremos liberar a
memória a que o objeto estava alocado.
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ê Ø Ò ÙÐÓ ß
ÒØ ¶
ÓÑÔÖ Ñ ÒØÓ¸ ¶ ÐØÙÖ
ÔÙ Ð
Ê Ø Ò ÙÐÓ ´ ÒØ¸ ÒØµ
Ê Ø Ò ÙÐÓ ´µ
ÒØ Ö ´µ ßÖ ØÙÖÒ ´¶
ÓÑÔÖ Ñ ÒØÓ ¶ ¶ ÐØÙÖ µ
Ê Ø Ò ÙÐÓ Ê Ø Ò ÙÐÓ ´ ÒØ ¸ ÒØ µ ß
ÓÑÔÖ Ñ ÒØÓ Ò Û ÒØ
ÐØÙÖ Ò Û ÒØ
¶
ÓÑÔÖ Ñ ÒØÓ
¶ ÐØÙÖ
Ê Ø Ò ÙÐÓ Ê Ø Ò ÙÐÓ ´µ ß
Ð Ø
ÓÑÔÖ Ñ ÒØÓ
Ð Ø ÐØÙÖ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò ´¿¸ µ¸ Ö Ø Ò ¾ ´ ¸ µ
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ½ Ö Ø Ò º Ö ´µ Ò Ð
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ¾ Ö Ø Ò ¾º Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que retorna:
Ö Ó Ê Ø Ò ÙÐÓ½ ½¾
Ö Ó Ê Ø Ò ÙÐÓ¾ ¿¼
11.3 Construtores Sobrecarregados
Como qualquer outra função, um construtor também pode ser sobrecarregado com mais de
uma 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
94.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
com os argumentos usados na chamada da função. No caso dos construtores, que são chamados
automaticamente quando o objeto é criado, o executado será aquele que bata com os argumentos
passados na declaração do objeto.
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ê Ø Ò ÙÐÓß
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
Ê Ø Ò ÙÐÓ ´µ
Ê Ø Ò ÙÐÓ ´ ÒØ¸ ÒØµ
ÒØ Ö ´ÚÓ µ ßÖ ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ¶ ÐØÙÖ µ
Ê Ø Ò ÙÐÓ Ê Ø Ò ÙÐÓ ´µ ß
ÓÑÔÖ Ñ ÒØÓ
ÐØÙÖ
Ê Ø Ò ÙÐÓ Ê Ø Ò ÙÐÓ ´ ÒØ ¸ ÒØ µ ß
ÓÑÔÖ Ñ ÒØÓ
ÐØÙÖ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò ´¿¸ µ
Ê Ø Ò ÙÐÓ Ö Ø Ò ¾
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ½ Ö Ø Ò º Ö ´µ Ò Ð
ÓÙØ Ö Ó Ê Ø Ò ÙÐÓ¾ Ö Ø Ò ¾º Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que retorna:
Ö Ó Ê Ø Ò ÙÐÓ½ ½¾
Ö Ó Ê Ø Ò ÙÐÓ¾ ¾
Neste 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 ():
Ê Ø Ò ÙÐÓ Ö Ø Ò »»
ÖØÓ
Ê Ø Ò ÙÐÓ Ö Ø Ò ¾´µ »» ÖÖ Ó
93
95.
CDTC Centro deDifusã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 a
classe tenha um construtor padrão sem argumentos. Assim, após declarar uma classe como
esta:
Ð ×× Ü ÑÔÐÓ ß
ÔÙ Ð
ÒØ ¸ ¸
ÚÓ ÑÙÐØ ÔÐÓ ´ ÒØ Ò¸ ÒØ ѵ ß Ò Ñ
¶
O compilador assume que Exemplo tem um construtor padrão, então podemos declarar obje-
tos desta classe simplesmente declarando-os sem argumentos:
Ü ÑÔÐÓ Ü
Entretanto, assim que declaramos nosso próprio construtor, o compilador não mais fornece
um construtor padrão implícito. Devemos, com isso declarar objetos daquela classe de acordo
com o protótipo do construtor que definimos para a classe:
Ð ×× Ü ÑÔÐÓ ß
ÔÙ Ð
ÒØ ¸ ¸
Ü ÑÔÐÓ ´ ÒØ Ò¸ ÒØ ѵ ß Ò Ñ
ÚÓ ÑÙÐØ ÔÐÓ ´µ ß
¶
Aqui declaramos um construtor que recebe 2 parâmetros do tipo int. Então a seguinte decla-
ração de objeto seria correta:
Ü ÑÔÐÓ Ü ´¾¸¿µ
mas,
Ü ÑÔÐÓ Ü
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 se
não especificarmos um, como também fornece três funções membro especiais no total que são
implicitamente declaradas se não declararmos as nossas. São elas o construtor cópia, a cópia
do 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 outro
objeto para os dados membros do objeto atual. Para CExemplo, o construtor cópia implicitamente
declarados pelo compilador seriam algo similar a:
Ü ÑÔÐÓ Ü ÑÔÐÓ ´
ÓÒר Ü ÑÔÐ ² ÖÚµ ß
ÖÚº ÖÚº
ÖÚº
94
96.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Então, as duas declarações de objetos seguintes seriam corretas:
Ü ÑÔÐÓ Ü ´¾¸¿µ
Ü ÑÔÐÓ Ü¾ ´ ܵ »»
ÓÒרÖÙØÓÖ
Ô ´ Ó×
ÓÔ Ó× Üµ
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 classe
como o tipo do ponteiro. Assim:
Ê Ø Ò ÙÐÓ ¶ ÔÖ Ø Ò
é um ponteiro para um objeto da classe Retangulo
Como acontece com estruturas de dados, para nos referirmos diretamente a um membro de
um objeto apontado por um ponteiro, podemos usar o operador flecha (-) de direção. Mostrarei
um exemplo com algumas possíveis combinações:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ê Ø Ò ÙÐÓ ß
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ¸ ÒØµ
ÒØ Ö ´ÚÓ µ ßÖ ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
ÚÓ Ê Ø Ò ÙÐÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ ß
ÓÑÔÖ Ñ ÒØÓ
ÐØÙÖ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ ¸ ¶ ¸ ¶
Ê Ø Ò ÙÐÓ ¶ Ò Û Ê Ø Ò ÙÐÓ ¾℄
Ò Û Ê Ø Ò ÙÐÓ
²
º× Ø Ú ÐÓÖ × ´½¸¾µ
¹ × Ø Ú ÐÓÖ × ´¿¸ µ
¹ × Ø Ú ÐÓÖ × ´ ¸ µ
½℄º× Ø Ú ÐÓÖ × ´ ¸ µ
ÓÙØ Ö º Ö ´µ Ò Ð
ÓÙØ Ö ¶ ¹ Ö ´µ Ò Ð
ÓÙØ Ö ¶
¹ Ö ´µ Ò Ð
ÓÙØ Ö ¼℄ ¼℄º Ö ´µ Ò Ð
ÓÙØ Ö ½℄ ½℄º Ö ´µ Ò Ð
Ð Ø ℄
95
97.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ð Ø
Ö ØÙÖÒ ¼
, o que retorna na tela:
Ö ¾
Ö ¶ ½¾
Ö ¶
¾
Ö ¼℄ ¿¼
Ö ½℄
A 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 x
x.y membro y do objeto x
x-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 x
x[1] segundo objeto apontado por x
x[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 às
próximas lições. Se tiver dúvidas, leia novamente esta seção e/ou consulte lições anteriores sobre
ponteiros 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 as
palavras0chave struct e union. Os conceitos de classe e estruturas de dados são tão similares
que ambas struct e class podem ser usadas em C++ para declarar classes. A única diferença
entre ambos é que membros de classes declarados com a palavra struct têm acesso public por
default (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 apenas
armazenam um dado membro por vez. Todavia são também classes e com isto também podem
carregar 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 a
operações com tipos fundamentais. Veja o seguinte código:
96
98.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
רÖÙ
Ø ß
×ØÖ Ò ÔÖÓ Ù
Ø
ÐÓ Ø ÔÖ
¸ ¸
·
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ções
usando operadores padrão. A seguir está uma lista de todos os operadores que podem ser so-
brecarregados:
ÇÚ ÖÐÓ Ð ÓÔ Ö ØÓÖ×
· ¹ ¶ » · ¹ ¶ »
·· ¹¹ ± ²
² ²² ± ℄ ´µ ¸ ¹ ¶ ¹ Ò Û
Ð Ø Ò Û ℄ Ð Ø ℄
Para sobrecarregar um operador de maneira que os usemos com classes, declaramos funções
de operadores, que são funções comuns cujos nomes são a palavra-chave do operador seguida
pelo símbolo do operador que queremos sobrecarregar. Desta maneira:
Ø ÔÓ℄ ÓÔ Ö ÓÖ℄ × Ñ ÓÐÓ℄ ´Ô Ö Ñ ØÖÓ×µ ß »¶ººº¶»
A seguir temos um exemplo que sobrecarrega o operador de adição (+). Criaremos uma
classe para armazenar vetores bidimensionais e então iremos adicionar dois deles: a(3,1) e
b(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 para
obter o y resultante. Neste caso, o resultado será (3+1,1+2) = (4,3).
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Î ØÓÖ ß
ÔÙ Ð
ÒØ ܸÝ
Î ØÓÖ ´µ ß
Î ØÓÖ ´ ÒØ¸ ÒØµ
Î ØÓÖ ÓÔ Ö ÓÖ· ´Î ØÓÖµ
Î ØÓÖ Î ØÓÖ ´ ÒØ ¸ ÒØ µ ß
Ü
Ý
Î ØÓÖ Î ØÓÖ ÓÔ Ö ÓÖ· ´Î ØÓÖ Ô Ö Ñµ ß
Î ØÓÖ Ø ÑÔ
97
99.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ø ÑÔºÜ Ü · Ô Ö ÑºÜ
Ø ÑÔºÝ Ý · Ô Ö ÑºÝ
Ö ØÙÖÒ ´Ø ÑÔµ
ÒØ Ñ Ò ´µ ß
Î ØÓÖ ´¿¸½µ
Î ØÓÖ ´½¸¾µ
Î ØÓÖ
·
ÓÙØ
ºÜ ¸
ºÝ
Ö ØÙÖÒ ¼
, o que resulta:
¸¿
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 aquele
nome, já que construtores devem ter o mesmo nome da classe. Não os confunda:
Î ØÓÖ ´ ÒØ¸ ÒØµ »» ÒÓÑ ÙÒ Ó Î ØÓÖ ´
ÓÒרÖÙØÓÖµ
Î ØÓÖ ÓÔ Ö ÓÖ· ´Î ØÓÖ µ »» ÙÒ Ó Ö ØÓÖÒ ÙÑ Î ØÓÖ
A função operador+ da classe Vetor é quem está a cargo de sobrecarregar o operador de
adiçã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:
·
ºÓÔ Ö ÓÖ· ´ µ
Ainda naquele exemplo anterior, note também que incluímos o construtor vazio (sem parâme-
tros) e o definimos com um bloco vazio:
Î ØÓÖ ´µ ß
Isto é necessário, já que declaramos explicitamente outro construtor:
Î ØÓÖ ´ ÒØ¸ ÒØµ
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 aquele
nome, já que construtores devem ter o mesmo nome da classe. Não os confunda:
Î ØÓÖ ´ ÒØ¸ ÒØµ »» ÒÓÑ ÙÒ Ó Î ØÓÖ ´
ÓÒרÖÙØÓÖµ
Î ØÓÖ ÓÔ Ö ÓÖ· ´Î ØÓÖ µ »» ÙÒ Ó Ö ØÓÖÒ ÙÑ Î ØÓÖ
A função operador+ da classe Vetor é quem está a cargo de sobrecarregar o operador de
adiçã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
100.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
·
ºÓÔ Ö ÓÖ· ´ µ
Ainda naquele exemplo anterior, note também que incluímos o construtor vazio (sem parâme-
tros) e o definimos com um bloco vazio:
Î ØÓÖ ´µ ß
Isto é necessário, já que declaramos explicitamente outro construtor:
Î ØÓÖ ´ ÒØ¸ ÒØµ
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 objetos
deste tipo sem parâmetros. Senão, a declaração:
Î ØÓÖ
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 construtor
deixa x e y indefinidas. Para isso, uma definição mais aconselhável seria algo assim:
Î ØÓÖ ´µ ß Ü ¼ Ý ¼
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 mesmo
que 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 o
conteúdo inteiro dos dados membro do objeto passado como argumento (à direita do sinal) para
o do lado esquerdo.
Î ØÓÖ ´¾¸¿µ
Î ØÓÖ
»» ÓÔ Ö ÓÖ ØÖ Ù Ó
Ô
A função operador de atribuição cópia é a única função operador membro implementada por
default. Claro que podemos redefini-las para qualquer funcionalidade que queiramos, como por
exemplo, 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 ser
muito intuitivo se usarmos o operador + para subtrair duas classes ou operador== para preencher
com zeros uma classe, apesar de ser perfeitamente possível fazer isto.
99
101.
CDTC Centro deDifusã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 que
está do lado direito do operador como parâmetro para a função operador membro do objeto do
lado 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 @ pelo
operador 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: como
uma função membro e como uma função global. Seu uso é indistinto, todavia devo ressaltar que
funções que não são membros de uma classe não podem acessar membros private ou protected
daquela classe a menos que a função global seja seu friend (friendship será explicada na lição a
seguir).
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 fora
de uma mesma classe na qual são declaradas. Entretanto, esta regra não afeta friends. Se
quisermos declarar uma função externa a uma classe como friend, deste modo permitindo que
esta função acesse membros private e protected desta classe, declaramos um protótipo desta
função externa na classe, e a precedemos com a palavra chave friend, como a seguir:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ê Ø Ò ÙÐÓ ß
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ¸ ÒØµ
ÒØ Ö ´µ ßÖ ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ö Ò Ê Ø Ò ÙÐÓ
ÓÔ ´Ê Ø Ò ÙÐÓµ
ÚÓ Ê Ø Ò ÙÐÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ ß
ÓÑÔÖ Ñ ÒØÓ
ÐØÙÖ
100
102.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ê Ø Ò ÙÐÓ
ÓÔ ´Ê Ø Ò ÙÐÓ Ö Ø Ò Ô Ö Ñµ
ß
Ê Ø Ò ÙÐÓ Ö Ø Ò Ö ×
Ö Ø Ò Ö ×º
ÓÑÔÖ Ñ ÒØÓ Ö Ø Ò Ô Ö Ñº
ÓÑÔÖ Ñ ÒØÓ¶¾
Ö Ø Ò Ö ×º ÐØÙÖ Ö Ø Ò Ô Ö Ñº ÐØÙÖ ¶¾
Ö ØÙÖÒ ´Ö Ø Ò Ö ×µ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò ¸ Ö Ø Ò
Ö Ø Ò º× Ø Ú ÐÓÖ × ´¾¸¿µ
Ö Ø Ò
ÓÔ ´Ö Ø Ò µ
ÓÙØ Ö Ø Ò º Ö ´µ
Ö ØÙÖÒ ¼
, o que retorna o valor 24.
A função copia é friend de Retangulo. Daquela função, somos também capazes de acessar
os 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() consideramos
copia um membro da classe Retangulo. E não é. Simplesmente tem acesso a seus membros
private 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 sempre
que 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 primeira
tenha acesso sos membros protected e private da segunda.
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÖ
Ð ×× Ê Ø Ò ÙÐÓ ß
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÒØ Ö ´µ
ßÖ ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
ÚÓ
ÓÒÚ ÖØ ´ÈÖ
µ
101
103.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ð ×× ÈÖ
ß
ÔÖ Ú Ø
ÒØ Ð Ó
ÔÙ Ð
ÚÓ × Ø Ð Ó ´ ÒØ µ
ßÐ Ó
Ö Ò
Ð ×× Ê Ø Ò ÙÐÓ
ÚÓ Ê Ø Ò ÙÐÓ
ÓÒÚ ÖØ ´ÈÖ
µ ß
ÓÑÔÖ Ñ ÒØÓ ºÐ Ó
ÐØÙÖ ºÐ Ó
ÒØ Ñ Ò ´µ ß
ÈÖ
×Õ
Ê Ø Ò ÙÐÓ Ö Ø Ò
×Õº× Ø Ð Ó´ µ
Ö Ø Ò º
ÓÒÚ ÖØ ´×Õµ
ÓÙØ Ö Ø Ò º Ö ´µ
Ö ØÙÖÒ ¼
, 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 concretamente
Praca::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 em
converte()). 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. No
nosso 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 de
Praca, mas não o caminho contrário. Claro que poderíamos ter declarado também Praca como
friend 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 automaticamente
incluem 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
104.
CDTC Centro deDifusã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 podemos
derivar 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 Retangulo
e Triangulo seriam suas classes derivadas, que especificam funcionalidades que são diferentes
de 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, no
seguinte formato:
Ð ×× ÒÓÑ
Ð ×× Ö Ú ℄ ÔÙ Ð
ÒÓÑ
Ð ×× × ℄
ß »¶ººº¶»
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 membros
que são herdados da classe base.
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÓÐ ÓÒÓ ß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ » ¾µ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò
ÌÖ Ò ÙÐÓ ØÖ Ð
103
105.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ö Ø Ò º× Ø Ú ÐÓÖ × ´ ¸ µ
ØÖ Ðº× Ø Ú ÐÓÖ × ´ ¸ µ
ÓÙØ Ö Ø Ò º Ö ´µ Ò Ð
ÓÙØ ØÖ к Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que retorna:
¾¼
½¼
Os 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 é similar
ao private. A única diferença ocorre, na verdade, com a herança. Quando uma classe herda de
outra, os membros dal classe derivada podem acessar membros protected herdados da classe
base, 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 ao
invés de private.
Podemos resumir os diferentes tipos de acesso de acordo com quem pode acessá-los da se-
guinte maneira:
Acesso public protected private
membros da mesma classe sim sim sim
membros de classes derivadas sim sim não
não membros sim não não
Onde não membrosrepresentam qualquer acesso de fora da classe, como de main(), de
uma outra classe ou função. No nosso exemplo, os membros herdados por Retangulo e Triangulo
têm as mesmas permissões de acesso que tinham em sua classe base Poligono.
ÈÓÐ ÓÒÓ
ÓÑÔÖ Ñ ÒØÓ »»
××Ó ÔÖÓØ
Ø
Ê Ø Ò ÙÐÓ
ÓÑÔÖ Ñ ÒØÓ »»
××Ó ÔÖÓØ
Ø
ÈÓÐ ÓÒÓ × Ø Ú ÐÓÖ ×´µ »»
××Ó ÔÙ Ð
Ê Ø Ò ÙÐÓ × Ø Ú ÐÓÖ ×´µ »»
××Ó ÔÙ Ð
Por isso tivemos que usar a palavra-chave public para definir relação de herança a cada uma
das classes derivadas:
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß ººº
Esta palavra-chave depois dos dois-pontos ( : ) denota o nível de acesso máximo para todos
os membros herdados da classe que o segue (neste caso, Poligono). Como public é o nível mais
acessível, especificando esta palavra-chave a classe derivada herda todos os membros com os
mesmos 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
106.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
classe derivada. Também, se especificarmos o mais restrito dos níveis de acesso, private, todos
os membros da classe base são herdados como private.
Por exemplo, uma classe mae é definida como:
Ð ×× Ð ÔÖÓØ
Ø Ñ
, 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 public
em mae se tornarão protected em daughter. Claro que isto não restringiria filha de declarar seus
pró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 para
classes 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, seu
construtor 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 cada
definição de construtor da classe derivada:
ÒÓÑ Ó
ÓÒרÖÙØÓÖ Ö Ú Ó℄ ´Ô Ö Ñ ØÖÓ×µ ÒÓÑ Ó
ÓÒרÖÙØÓÖ × ℄´Ô Ö Ñ ØÖÓ×µ ߺºº
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ñ ß
ÔÙ Ð
Ñ ´µ
ß
ÓÙØ Å × Ñ Ô Ö Ñ ØÖÓ× Ò
Ñ ´ ÒØ µ
ß
ÓÙØ Å È Ö Ñ ØÖÓ ÒØ Ò
105
107.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ð ×× Ð ÔÙ Ð
Ñ ß
ÔÙ Ð
Ð ´ ÒØ µ
ß
ÓÙØ Ð È Ö Ñ ØÖÓ ÒØ Ò Ò
Ð ×× Ð Ó ÔÙ Ð
Ñ ß
ÔÙ Ð
Ð Ó ´ ÒØ µ Ñ ´ µ
ß
ÓÙØ Ð Ó È Ö Ñ ØÖÓ ÒØ Ò Ò
ÒØ Ñ Ò ´µ ß
Ð
ÝÒØ ´¼µ
Ð Ó Ò Ð´¼µ
Ö ØÙÖÒ ¼
, o que retorna:
Ñ ÒÓ Ô Ö Ñ Ø Ö×
Ð ÒØ Ô Ö Ñ Ø Ö
Ñ ÒØ Ô Ö Ñ Ø Ö
Ð Ó ÒØ Ô Ö Ñ Ø Ö
Note 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 construtor
de filha e filho:
Ð ´ ÒØ µ »» Ò ×Ô
Ó
Ñ Ô Ö Ó
Ð Ó ´ ÒØ µ Ñ ´ µ »»
ÓÒרÖÙØÓÖ ×Ô
Ó
Ñ ×Ø
11.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 classe
derivada. Por exemplo, se tivermos uma classe específica para imprimir na tela (COutput) e
quisermos que nossas classe Retangulo e Triangulo também herdem seus membros em adição
àqueles de Poligono, poderíamos escrever:
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ¸ ÔÙ Ð
ÇÙØÔÙØ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ¸ ÔÙ Ð
ÇÙØÔÙØ
, aqui temos um exemplo completo:
106
108.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÓÐ ÓÒÓ ß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
Ð ×× ÇÙØÔÙØ ß
ÔÙ Ð
ÚÓ × ´ ÒØ µ
ÚÓ ÇÙØÔÙØ × ´ ÒØ µ ß
ÓÙØ Ò Ð
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ¸ ÔÙ Ð
ÇÙØÔÙØ ß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ¸ ÔÙ Ð
ÇÙØÔÙØ ß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ » ¾µ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò
ÌÖ Ò ÙÐÓ ØÖ Ð
Ö Ø Ò º× Ø Ú ÐÓÖ × ´ ¸ µ
ØÖ Ðº× Ø Ú ÐÓÖ × ´ ¸ µ
Ö Ø ÒÒ º× ´Ö Ø Ò º Ö ´µµ
ØÖ кÓÙØÔÙØ ´ØÖ к Ö ´µµ
Ö ØÙÖÒ ¼
11.9 Polimorfismo
Ponteiros para classes base
Uma das funcionalidades principais de classes derivadas é que um ponteiro para uma classe
107
109.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
derivada é compatível tipamente com um ponteiro para esta classe base. Polimorfismo é a arte
de tirar vantagem dessa funcionalidade. Começaremos reescrevendo nosso programa sobre o
retângulo e o triângulo da seção anterior considerando esta propriedade de compatibilidade de
ponteiros:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÓÐ ÓÒÓ ß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ » ¾µ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò
ÌÖ Ò ÙÐÓ ØÖ Ð
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ½ ²Ö Ø Ò
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ¾ ²ØÖ Ð
ÔÓÐ ½¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ¾¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÓÙØ Ö Ø Ò º Ö ´µ Ò Ð
ÓÙØ ØÖ к Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que mostra na tela:
¾¼
½¼
Na 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ão
objetos de classes derivadas de Poligono, são atribuições válidas.
108
110.
CDTC Centro deDifusã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ão
do tipo Poligono* e assim apenas podemos usar estes ponteiros para nos referirmos a membros
que Retangulo e Triangulo herdam de Poligono. Por esta razão quando chamamos os membros
de area() no final do programa, temos que usar diretamente os objetos retang e trgl ao invés dos
ponteiros *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á-lo
na 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 é conhecido
como um membro virtual. Para declarar um membro de uma classe como virtual, devemos pre-
ceder sua declaração com a palavra-chave virtual:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÓÐ ÓÒÓ ß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
Ú ÖØÙ Ð ÒØ Ö ´µ
ß Ö ØÙÖÒ ´¼µ
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ » ¾µ
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò
ÌÖ Ò ÙÐÓ ØÖ Ð
ÈÓÐ ÓÒÓ ÔÓÐ
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ½ ²Ö Ø Ò
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ¾ ²ØÖ Ð
109
111.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ¿ ²ÔÓÐ
ÔÓÐ ½¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ¾¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ¿¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÓÙØ ÔÓÐ ½¹ Ö ´µ Ò Ð
ÓÙØ ÔÓÐ ¾¹ Ö ´µ Ò Ð
ÓÙØ ÔÓÐ ¿¹ Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que mostra na tela:
¾¼
½¼
¼
Agora 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 é redefinida
depois em cada classe derivada. Podemos verificar se removermos essa palavra-chave virtual
da 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() correspondente
para 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 com
o mesmo nome de um na classe base seja apropriadamente chamado a partir de um ponteiro, e
mais 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. Note
que apesar de sua virtualidade, também fomos capazes de declarar um objeto do tipo Poligono e
chamar 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, com
a diferença que neste definimos uma função area() válida com uma funcionalidade mínima para
objetos que eram da classe Poligono (como poli), onde em uma classe base abstrata poderíamos
deixar 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 algo
assim:
Ð ×× ÈÓÐ ÓÒÓ ß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
110
112.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ú ÖØÙ Ð ÒØ Ö ´µ ¼
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ém
no 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 criar
ponteiros para ela e tirar vantagem de todas suas habilidades polimórficas. Assim,
ÈÓÐ ÓÒÓ ÔÓÐ
não seria válida para a classe base abstrata que acabamos de declarar, pois tenta instanciar
um objeto. Apesar disto, os seguintes ponteiros seriam válidos:
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ½
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ¾
Isto é assim durante o tempo que Poligono inclui uma função virtual puta e com isso não é uma
classe base abstrata. No entanto, ponteiros para essa classe base abstrata podem ser usados
para apontar para objetos de classes derivadas. Exemplo completo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÓÐ ÓÒÓß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
Ú ÖØÙ Ð ÒØ Ö ´ÚÓ µ ¼
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´ÚÓ µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´ÚÓ µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ » ¾µ
111
113.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò
ÌÖ Ò ÙÐÓ ØÖ Ð
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ½ ²Ö Ø Ò
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ¾ ²ØÖ Ð
ÔÓÐ ½¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ¾¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÓÙØ ÔÓÐ ½¹ Ö ´µ Ò Ð
ÓÙØ ÔÓÐ ¾¹ Ö ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que mostra na tela:
¾¼
½¼
Se 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 Poligono
que é capaz de imprimir na tela o resultado da função area() mesmo que Poligono em si não
tenha nenhuma implementação para esta função:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÓÐ ÓÒÓ ß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
Ú ÖØÙ Ð ÒØ Ö ´ÚÓ µ ¼
ÚÓ ÑÔÖ Ñ Ö ´ÚÓ µ
ß
ÓÙØ Ø ×¹ Ö ´µ Ò Ð
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´ÚÓ µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´ÚÓ µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ » ¾µ
112
114.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÒØ Ñ Ò ´µ ß
Ê Ø Ò ÙÐÓ Ö Ø Ò
ÌÖ Ò ÙÐÓ ØÖ Ð
ÈÓÐ ÓÒÓ ¶ ÔÔÓÐݽ ²Ö Ø Ò
ÈÓÐ ÓÒÓ ¶ ÔÔÓÐݾ ²ØÖ Ð
ÔÓÐ ½¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ¾¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ½¹ ÑÔÖ Ñ Ö ´µ
ÔÓÐ ¾¹ ÑÔÖ Ñ Ö ´µ
Ö ØÙÖÒ ¼
, o que mostra na tela:
¾¼
½¼
Membros 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 simples
destas estruturas mas essas funcionalidades podem ser aplicadas a arrays de objetos ou objetos
dinamicamente alocados. Vamos finalizar POO com o mesmo exemplo, desta vez alocando os
objetos dinamicamente:
»» ÐÓ
Ó Ò Ñ
ÔÓÐ ÑÓÖ ×ÑÓ
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× ÈÓÐ ÓÒÓ ß
ÔÖÓØ
Ø
ÒØ
ÓÑÔÖ Ñ ÒØÓ¸ ÐØÙÖ
ÔÙ Ð
ÚÓ × Ø Ú ÐÓÖ × ´ ÒØ ¸ ÒØ µ
ß
ÓÑÔÖ Ñ ÒØÓ ÐØÙÖ
Ú ÖØÙ Ð ÒØ Ö ´ÚÓ µ ¼
ÚÓ ÑÔÖ Ñ Ö ´ÚÓ µ
ß
ÓÙØ Ø ×¹ Ö ´µ Ò Ð
Ð ×× Ê Ø Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´ÚÓ µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ µ
Ð ×× ÌÖ Ò ÙÐÓ ÔÙ Ð
ÈÓÐ ÓÒÓ ß
ÔÙ Ð
ÒØ Ö ´ÚÓ µ
ß Ö ØÙÖÒ ´
ÓÑÔÖ Ñ ÒØÓ ¶ ÐØÙÖ » ¾µ
113
115.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÒØ Ñ Ò ´µ ß
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ½ Ò Û Ê Ø Ò ÙÐÓ
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ¾ Ò Û ÌÖ Ò ÙÐÓ
ÔÓÐ ½¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ¾¹ × Ø Ú ÐÓÖ × ´ ¸ µ
ÔÓÐ ½¹ ÑÔÖ Ñ Ö ´µ
ÔÓÐ ¾¹ ÑÔÖ Ñ Ö ´µ
Ð Ø ÔÓÐ ½
Ð Ø ÔÓÐ ¾
Ö ØÙÖÒ ¼
, o que retorna na tela:
¾¼
½¼
Note que os ponteiros poli:
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ½ Ò Û Ê Ø Ò ÙÐÓ
ÈÓÐ ÓÒÓ ¶ ÔÓÐ ¾ Ò Û ÌÖ Ò ÙÐÓ
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
116.
Capítulo 12
Templates, Namespaces
12.1Templates
Funções Template
São funções especiais que podem operar com tipos genéricos. Isto nos permite criar uma função
template 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âmetro
template é 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 passar
valores para uma função, parâmetros template permite que passemos também tipos para uma
função. Estas funções templates podem usar estes parâmetros como se fossem qualquer outro
tipo comum. Seu formato é:
Ø ÑÔÐ Ø
Ð ×× ÒØ
ÓÖ
Ð Ö
Ó ÙÒ
Ó℄
Ø ÑÔÐ Ø ØÝÔ Ò Ñ ÒØ
ÓÖ
Ð Ö
Ó ÙÒ
Ó℄
OBS: A única diferença entre os dois protótipos é o uso tanto da palavra-chave class ou da
palavra-chave typename. Seu uso é indistinto, já que ambas as expressões têm exatamente o
mesmo significado e se comportam da mesma maneira.
Por exemplo, para criar uma função template que retorna o maior de dois objetos podemos usar:
Ø ÑÔÐ Ø
Ð ×× Ñ ÙÌ ÔÓ
Ñ ÙÌ ÔÓ ØÅ ÓÖ ´Ñ ÙÌ ÔÓ ¸ Ñ ÙÌ ÔÓ µ ß
Ö ØÙÖÒ ´ µ
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 se
ele fosse um tipo comum. Como podemos ver, a função template tMaior retorna o maior de dois
parâmetros deste tipo ainda indefinido.
Para usar esta função template, usamos o formato para a função de chamada:
ÒÓÑ ÙÒ
Ó℄ Ø ÔÓ ´Ô Ö Ñ ØÖÓ×µ
115
117.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Por exemplo, para chamarmos tMaior para comparar dois valores inteiros do tipo int, podemos
escrever:
ÒØ ܸÝ
ØÅ ÓÖ ÒØ ´Ü¸Ýµ
Quando o compilador encontra esta chamada à função template, ele usa o template para gerar
automaticamente uma função trocando cada apararição de meuTipo pelo tipo passado como o
atual 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:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ø ÑÔÐ Ø
Ð ×× Ì
Ì ØÅ ÓÖ ´Ì ¸ Ì µ ß
Ì Ö ×ÙÐØ Ó
Ö ×ÙÐØ Ó ´ µ
Ö ØÙÖÒ ´Ö ×ÙÐØ Óµ
ÒØ Ñ Ò ´µ ß
ÒØ ¸ ¸
ÐÓÒ Ð ½¼¸ Ñ ¸ Ò
ØÅ ÓÖ ÒØ ´ ¸ µ
Ò ØÅ ÓÖ ÐÓÒ ´Ð¸Ñµ
ÓÙØ Ò Ð
ÓÙØ Ò Ò Ð
Ö ØÙÖÒ ¼
, o que retorna na tela:
½¼
Neste 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 usar
qual 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 compilador
instanciou 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:
Ì Ö ×ÙÐØ Ó
116
118.
CDTC Centro deDifusã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ção
template é 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 tipo
de dado tem que instanciar sem ter que explicitamente especificar isso entre e . Poderíamos,
então, ter escrito no lugar:
ÒØ ¸
ØÅ ÓÖ ´ ¸ µ
Já que ambos i e j são do tipo int, e o compilador pode perceber automaticamente que o
parâmetro template pode ser apenas int. Este método implícito produz exatamente o mesmo
resultado:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ø ÑÔÐ Ø
Ð ×× Ì
Ì ØÅ ÓÖ ´Ì ¸ Ì µ ß
Ö ØÙÖÒ ´ µ
ÒØ Ñ Ò ´µ ß
ÒØ ¸ ¸
ÐÓÒ Ð ½¼¸ Ñ ¸ Ò
ØÅ ÓÖ´ ¸ µ
Ò ØÅ Óִиѵ
ÓÙØ Ò Ð
ÓÙØ Ò Ò Ð
Ö ØÙÖÒ ¼
, o que retorna na tela:
½¼
Note 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 cada
chamada. 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 dois
objetos de diferentes tipos como argumento:
ÒØ
ÐÓÒ Ð
ØÅ ÓÖ ´ ¸Ðµ
Isto seria incorreto, já que nossa função template tMaior espera dois argumentos do mesmo
tipo, 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
119.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ø ÑÔÐ Ø
Ð ×× Ì¸
Ð ×× Í
Ì ØÅ ÒÓÖ ´Ì ¸ Í µ ß
Ö ØÙÖÒ ´ µ
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 chamar
tMenor() com:
ÒØ ¸
ÐÓÒ Ð
ØÅ ÒÓÖ ÒØ¸ÐÓÒ ´ ¸Ðµ
ou simplesmente:
ØÅ ÒÓÖ ´ ¸Ðµ
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 que
usam parâmetros template como tipos. Por exemplo:
Ø ÑÔÐ Ø
Ð ×× Ì
Ð ×× ÑÈ Ö ß
Ì Ú ÐÓÖ × ¾℄
ÔÙ Ð
ÑÈ Ö ´Ì ÔÖ Ñ ÖÓ¸ Ì × ÙÒ Óµ
ß
Ú ÐÓÖ × ¼℄ ÔÖ Ñ ÖÓ Ú ÐÓÖ × ½℄ × ÙÒ Ó
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 valores
inteiros do tipo int com os valores 115 e 36, escreveríamos:
ÑÈ Ö ÒØ ÑÇ ØÓ ´½½ ¸ ¿ µ
Esta mesma classe também seria usada para criar um objeto para armazenar qualquer outro
tipo:
ÑÈ Ö ÓÙ Ð Ñ ÐÓ Ø× ´¿º¼¸ ¾º½ µ
A única função membro na a classe template anterior foi definida em linha com a declaração
da classe em si. No caso em que definimos uma função membro fora da declaração da classe
template, devemos sempre preceder aquela definição com o prefixo template ...
118
120.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ø ÑÔÐ Ø
Ð ×× Ì
Ð ×× ÑÈ Ö ß
Ì ¸
ÔÙ Ð
ÑÈ Ö ´Ì ÔÖ Ñ ÖÓ¸ Ì × ÙÒ Óµ
ß ÔÖ Ñ ÖÓ × ÙÒ Ó
Ì ØÑ ÓÖ´µ
Ø ÑÔÐ Ø
Ð ×× Ì
Ì ÑÈ Ö Ì ØÑ ÓÖ ´µ
ß
Ì Ö ØÚ Ð
Ö ØÚ Ð
Ö ØÙÖÒ Ö ØÚ Ð
ÒØ Ñ Ò ´µ ß
ÑÈ Ö ÒØ ÑÇ ØÓ ´½¼¼¸ µ
ÓÙØ ÑÇ ØÓºØÑ ÓÖ´µ
Ö ØÙÖÒ ¼
, o que retorna o valor 100.
Note que a sintaxe da definição da função membro 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 pela
função. E o terceiro, entre , também é um requerimento, e especifica que este parâmetro da
funçã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 pode
armazenar 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 ter
uma implementação completamente diferente, com uma função membro letramaiuscula, então
decidimos declarar uma especialização da classe template para aquele tipo:
»» ×Ô
Ð Þ Ó Ó Ø ÑÔÐ Ø
119
121.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
»»
Ð ×× Ø ÑÔÐ Ø
Ø ÑÔÐ Ø
Ð ×× Ì
Ð ×× Ñ
ÓÒØ Ò Ö ß
Ì Ð Ñ ÒØÓ
ÔÙ Ð
Ñ
ÓÒØ Ò Ö ´Ì Ö µ ß Ð Ñ ÒØÓ Ö
Ì Ò
Ö Ñ ÒØ ´µ ßÖ ØÙÖÒ ·· Ð Ñ ÒØÓ
»» ×Ô
Ð Þ
Ó
Ð ×× Ø ÑÔÐ Ø
Ø ÑÔÐ Ø
Ð ×× Ñ
ÓÒØ Ò Ö
Ö ß
Ö Ð Ñ ÒØÓ
ÔÙ Ð
Ñ
ÓÒØ Ò Ö ´
Ö Ö µ ß Ð Ñ ÒØÓ Ö
Ö Ð ØÖ Ñ Ù×
ÙÐ ´µ
ß
´´ Ð Ñ ÒØÓ ³ ³µ²²´ Ð Ñ ÒØÓ ³Þ³µµ
Ð Ñ ÒØÓ· ³ ³¹³ ³
Ö ØÙÖÒ Ð Ñ ÒØÓ
ÒØ Ñ Ò ´µ ß
Ñ
ÓÒØ Ò Ö ÒØ Ñ ÒØ ´ µ
Ñ
ÓÒØ Ò Ö
Ö Ñ
Ö ´³ ³µ
ÓÙØ Ñ ÒØº Ò
Ö Ñ ÒØ ´µ Ò Ð
ÓÙØ Ñ
ֺРØÖ Ñ Ù×
ÙÐ ´µ Ò Ð
Ö ØÙÖÒ ¼
, o que retorna na tela:
Â
Esta é a sintaxe usada na especialização da classe template:
Ø ÑÔÐ Ø
Ð ×× Ñ
ÓÒØ Ò Ö
Ö ß ººº
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 do
nome da classe template. Este parâmetro de especialização por si só identifica o tipo para o qual
declararemos uma especialização da classe template (char). Note as diferenças entre classes
template genéricas e a especialização, respectivamente:
120
122.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ø ÑÔÐ Ø
Ð ×× Ì
Ð ×× Ñ
ÓÒØ Ò Ö ß ººº
Ø ÑÔÐ Ø
Ð ×× Ñ
ÓÒØ Ò Ö
Ö ß ººº
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çade 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 é usada
para conter seqüências de elementos:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ø ÑÔÐ Ø
Ð ×× Ì¸ ÒØ Æ
Ð ×× Ñ× ÕÙ Ò
ß
Ì ÐÓ
ÓÑ Ñ Æ℄
ÔÙ Ð
ÚÓ × Ø Ñ Ñ ÖÓ ´ ÒØ ܸ Ì Ú ÐÓÖµ
Ì ØÑ Ñ ÖÓ ´ ÒØ ܵ
Ø ÑÔÐ Ø
Ð ×× Ì¸ ÒØ Æ
ÚÓ Ñ× ÕÙ Ò
Ì¸Æ × Ø Ñ Ñ ÖÓ ´ ÒØ ܸ Ì Ú ÐÓÖµ ß
ÐÓ
ÓÑ Ñ Ü℄ Ú ÐÓÖ
Ø ÑÔÐ Ø
Ð ×× Ì¸ ÒØ Æ
Ì Ñ× ÕÙ Ò
Ì¸Æ ØÑ Ñ ÖÓ ´ ÒØ ܵ ß
Ö ØÙÖÒ ÐÓ
ÓÑ Ñ Ü℄
ÒØ Ñ Ò ´µ ß
Ñ× ÕÙ Ò
ÒØ¸ Ñ ÒØ×
Ñ× ÕÙ Ò
ÓÙ Ð ¸ Ñ ÐÓ Ø×
Ñ ÒØ×º× Ø Ñ Ñ ÖÓ ´¼¸½¼¼µ
Ñ ÐÓ Ø×º× Ø Ñ Ñ ÖÓ ´¿¸¿º½ ½ µ
ÓÙØ Ñ ÒØ×ºØÑ Ñ ÖÓ´¼µ ³ Ò³
ÓÙØ Ñ ÐÓ Ø×ºØÑ Ñ ÖÓ´¿µ ³ Ò³
Ö ØÙÖÒ ¼
, o que retorna na tela:
½¼¼
¿º½ ½
121
123.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Também é possível setar valores ou tipos default para parâmetros de classe template. Por
exemplo, se a definição da classe template anterior fosse:
Ø ÑÔÐ Ø
Ð ×× Ì
Ö¸ ÒØ Æ ½¼
Ð ×× Ñ× ÕÙ Ò
᧧
poderíamos criar objetos usando os parâmetros template padrões declarando:
Ñ× ÕÙ Ò
Ñ× Õ
Que seria equivalente a:
Ñ× ÕÙ Ò
Ö¸½¼ Ñ× Õ
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é que
uma 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 aqueles
argumentos do template.
Quando projetos crescem é comum dividir o código de um programa em diferentes arquivos-fonte
de código. Nestes casos, a interface e a implementação são geralmente separadas. Tomando
como 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çalhocom 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 de
projeto múltiplos: a implementação (definição) de uma classe template ou função template deve
estar no mesmo arquivo que sua declaração. Isto significa que não podemos separar a interface
num arquivo de cabeçalho separado, e que devemos incluir ambas interface e implementação em
qualquer 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 template
com 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. O
formato é:
Ò Ñ ×Ô
ÒØ
ÓÖ
ß
ÒØ ×
122
124.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Por exemplo:
Ò Ñ ×Ô
Ñ ÙÆ×Ô
ß
ÒØ ¸
Para acessar as variáveis a e b de fora de meuNspace temos que usar o operador de escopo
( :: ). Por exemplo, podemos escrever:
Ñ ÙÆ×Ô
Ñ ÙÆ×Ô
A 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, causando
erros de redefinição. Por exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ò Ñ ×Ô
Ò×Ô
½
ß
ÒØ Ü
Ò Ñ ×Ô
Ò×Ô
¾
ß
ÓÙ Ð Ü ¿º½ ½
ÒØ Ñ Ò ´µ ß
ÓÙØ Ò×Ô
½ Ü Ò Ð
ÓÙØ Ò×Ô
¾ Ü Ò Ð
Ö ØÙÖÒ ¼
, o que retorna:
¿º½ ½
Neste 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ças
ao namespace.
Using
A palavra-chave using é usada para introduzir um nome de um namespace na região declara-
tiva atual. Por exemplo:
123
125.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ò Ñ ×Ô
Ò×Ô
½
ß
ÒØ Ü
ÒØ Ý ½¼
Ò Ñ ×Ô
Ò×Ô
¾
ß
ÓÙ Ð Ü ¿º½ ½
ÓÙ Ð Ý ¾º ½ ¿
ÒØ Ñ Ò ´µ ß
Ù× Ò Ò×Ô
½ Ü
Ù× Ò Ò×Ô
¾ Ý
ÓÙØ Ü Ò Ð
ÓÙØ Ý Ò Ð
ÓÙØ Ò×Ô
½ Ý Ò Ð
ÓÙØ Ò×Ô
¾ Ü Ò Ð
Ö ØÙÖÒ ¼
, o que retorna:
¾º ½ ¿
½¼
¿º½ ½
Note 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. Ainda
temos acesso a nspace1::y e nspace2::x usando seus nomes completos qualificados. A palavra
using também pode ser usada como uma diretiva para introduzir um namespace inteiro:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ò Ñ ×Ô
Ò×Ô
½
ß
ÒØ Ü
ÒØ Ý ½¼
Ò Ñ ×Ô
Ò×Ô
¾
ß
ÓÙ Ð Ü ¿º½ ½
124
126.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÓÙ Ð Ý ¾º ½ ¿
ÒØ Ñ Ò ´µ ß
Ù× Ò Ò Ñ ×Ô
Ò×Ô
½
ÓÙØ Ü Ò Ð
ÓÙØ Ý Ò Ð
ÓÙØ Ò×Ô
¾ Ü Ò Ð
ÓÙØ Ò×Ô
¾ Ý Ò Ð
Ö ØÙÖÒ ¼
, que retorna na tela:
½¼
¿º½ ½
¾º ½ ¿
Aqui, 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 namespace
nspace1.
Também, usinge using namespacetêm validade apenas no mesmo bloco em que eles são
firmados 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 aqueles
de outro namespace, poderíamos fazer algo assim:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ò Ñ ×Ô
Ò×Ô
½
ß
ÒØ Ü
Ò Ñ ×Ô
Ò×Ô
¾
ß
ÓÙ Ð Ü ¿º½ ½
ÒØ Ñ Ò ´µ ß
ß
Ù× Ò Ò Ñ ×Ô
Ò×Ô
½
ÓÙØ Ü Ò Ð
ß
Ù× Ò Ò Ñ ×Ô
Ò×Ô
¾
ÓÙØ Ü Ò Ð
125
127.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ö ØÙÖÒ ¼
, o que retorna:
¿º½ ½
Namespace alias
Podemos declarar nomes alternados para namespaces existentes de acordo com o formato:
Ò Ñ ×Ô
ÒÓÚÓ ÒÓÑ ÒÓÑ ØÙ Ð
Namespace std
Todos os arquivos na biblioteca padrão C++ declaram todas as suas entidades no namespace
std. Por isso temos geralmente incluído o using namespace std;em todos os programas que
usaram qualquer entidade definida em iostream.
126
128.
Capítulo 13
Exceptions eDiretivas
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 manipuladores
ou 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 uma
circunstância excepcional acontece no bloco, uma exceção é lançada, o que transfere o controle
para o handler. Se nenhuma exceção é lançada, o código continua normalmente e os handlers
sã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:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ ß
ØÖÝ
ß
Ø ÖÓÛ ¾¼
Ø
´ ÒØ µ
ß
ÓÙØ ÍÑ ÖÖÓ Ó
ÓÖÖ Ùº Ü
Ó ÆÙÑ ÖÓ Ò Ð
Ö ØÙÖÒ ¼
, o que mostrará na tela:
ÍÑ ÖÖÓ Ó
ÓÖÖ Ùº Ü
Ó ÆÙÑ ÖÓ ¾¼
Neste exemplo, o código simplesmente lança uma exceção:
Ø ÖÓÛ ¾¼
127
129.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Uma expressão throw aceita um parâmetro (neste caso um inteiro de valor 20), que é passado
como argumento para o handler.
Como podemos ver, o handler segue imediatamente as chaves depois do bloco try. O formato
do catch é similar a uma função normal que sempre tem no mínimo um parâmetro. O tipo deste
parâ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ão
throw é 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 usado
como handler padrão que captura todas as exceções não capturadas por outros handlers se for
especificado por útimo:
ØÖÝ ß
»»
Ó Ó
Ø
´ ÒØ Ô Ö Ñµ ß
ÓÙØ Ü
Ó ÒØ
Ø
´
Ö Ô Ö Ñµ ß
ÓÙØ Ü
Ó
Ö
Ø
´ºººµ ß
ÓÙØ Ü
Ó ÙÐØ
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ós
o 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:
ØÖÝ ß
ØÖÝ ß
»»
Ó Ó
Ø
´ ÒØ Òµ ß
Ø ÖÓÛ
Ø
´ºººµ ß
ÓÙØ ÖÖÓ Ç
ÓÖÖ Ù
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
130.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÐÓ Ø Ñ Ò ÙÒ
Ó ´
Ö Ô Ö Ñµ Ø ÖÓÛ ´ ÒØµ
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 tipo
int. Se lançar uma exceção com um tipo diferente, mesmo diretamente ou indiretamente, não
pode ser capturada por um handler de tipo int comum.
Se este especificador throw é deixado vazio sem tipo, significa que à função não é permitida
a lançar exceções. Funções sem especificador throw (funções normais) são permitidas de lançar
exceções com qualquer tipo:
ÒØ Ñ Ò ÙÒ
Ó ´ ÒØ Ô Ö Ñµ Ø ÖÓÛ´µ »» Ü
Ó × Ò Ó Ô ÖÑ Ø ×
ÒØ Ñ Ò ÙÒ
Ó ´ ÒØ Ô Ö Ñµ »» ØÓ × × Ü
Ó × Ô ÖÑ Ø ×
Exceções Padrão
A biblioteca padrão de C++ fornece uma classe base especificamente projetada para declarar
objetos para serem lançados como exceções. É chamado exception e é definido no arquivo de
cabeçalho exception sobre o namespace std. Esta classe tem o default usual e construtores
cópia, operadores e destrutores, e ainda uma função membro virtual adicional chamada what
que 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 das
exceções.
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ Ü
ÔØ ÓÒ
Ù× Ò Ò Ñ ×Ô
ר
Ð ×× Ñ Ò Ü
Ó ÔÙ Ð
Ü
ÔØ ÓÒ
ß
Ú ÖØÙ Ð
ÓÒר
Ö¶ Û Ø´µ
ÓÒר Ø ÖÓÛ´µ
ß
Ö ØÙÖÒ Å Ò Ü
Ó
ÓÒØ
Ù
Ñ Ü
ÒØ Ñ Ò ´µ ß
ØÖÝ
ß
Ø ÖÓÛ Ñ Ü
Ø
´ Ü
ÔØ ÓÒ² µ
ß
ÓÙØ ºÛ Ø´µ Ò Ð
Ö ØÙÖÒ ¼
, o que retorna na tela:
129
131.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Å Ò Ü
Ó
ÓÒØ
Ùº
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 Ñ Ü da classe mi-
nhaexcecao;
Todas as exceções lançadas por componentes da Biblioteca Padrão de C++ lançam exceções
derivadas desta classe ר Ü
ÔØ ÓÒ. São elas:
exceção descrição
bad_alloc lançada por new em falha de alocação
bad_cast lançada por dynamic_cast quando acontece falha com um
tipo de referência
bad_exception lançada quando um tipo de exceção não bate com nenhum catch
bad_typeid lançada por typeid
ios_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ção
do tipo bad_alloc é lançada:
ØÖÝ
ß
ÒØ ¶ Ú Ø Ò Û ÒØ ½¼¼¼℄
Ø
´ ÐÐÓ
²µ
ß
ÓÙØ ÖÖÓ ÐÓ
Ò Ó Ñ ÑÓÖ º Ò Ð
É recomendado incluir todas as alocações de memória com um bloco try catch que captura
este 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çar
uma exceção bad_alloc para vê-la em ação, você pode tentar alocar um array enorme; Talvez
tentar 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:
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ Ü
ÔØ ÓÒ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ ß
ØÖÝ
ß
ÒØ¶ Ú Ø Ò Û ÒØ ½¼¼¼℄
Ø
´ Ü
ÔØ ÓÒ² µ
ß
130
132.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
ÓÙØ Ü
Ó Ô Ö Ó ºÛ Ø´µ Ò Ð
Ö ØÙÖÒ ¼
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 precedidas
por 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 caracter
de nova linha é encontrado, o pré-processamento é considerado finalizado. Ponto-e-vírgula não
são necessários no final de uma diretiva. A única maneira que uma diretiva pré-processamento
pode se extender por mais de uma linha é precedendo o caracter de nova linha no fim da linha
por uma barra invertida.
Definições macro (#define, #undef)
Para definir macros pré-processamento podemos usar #define, cujo formato é:
Ò ÒØ
ÓÖ ØÖÓ
Quando 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, ou
simplesmente nada. O pré-processamento não entende C++, simplesmente troca qualquer ocor-
rência de identificador por troca.
Exemplo:
Ò Ì Å ÆÀÇ Ì Ä ½¼¼
ÒØ Ø Ð ½ Ì Å ÆÀÇ Ì Ä ℄
ÒØ Ø Ð ¾ Ì Å ÆÀÇ Ì Ä ℄
Após o pré-processamento ter trocado TAMANHO_TABELA, o código é equivalente a:
ÒØ Ø Ð ½ ½¼¼℄
ÒØ Ø Ð ¾ ½¼¼℄
Este uso de #define é comum, mas ele também pode funcionar com parâmetros para definir
funções macros:
Ò ØÅ ÓÖ´ ¸ µ
Fazzendo 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 exatamente
como experaríamos se fosse a função:
131
133.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
»» ÙÒ
Ó Ñ
ÖÓ
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
Ò ØÅ ÓÖ´ ¸ µ ´´ µ ´ µ ´ µ ´ µµ
ÒØ Ñ Ò´µ
ß
ÒØ Ü ¸ Ý
Ý ØÅ Óִܸ¾µ
ÓÙØ Ý Ò Ð
ÓÙØ ØÅ ÓÖ´ ¸Üµ Ò Ð
Ö ØÙÖÒ ¼
, o que retornaria na tela:
macros definidas não são afetadas pela estrutura do bloco. Uma macro dura até sua indefini-
ção com a diretiva #undef:
Ò Ì Å ÆÀÇ Ì Ä ½¼¼
ÒØ Ø Ð ½ Ì Å ÆÀÇ Ì Ä ℄
ÙÒ Ì Å ÆÀÇ Ì Ä
Ò Ì Å ÆÀÇ Ì Ä ¾¼¼
ÒØ Ø Ð ¾ Ì Å ÆÀÇ Ì Ä ℄
Isto geraria o mesmo que:
ÒØ Ø Ð ½ ½¼¼℄
ÒØ Ø Ð ¾ ¾¼¼℄
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, aquele
parâmetro é substituído por uma string literal (como se ela estivesse entre aspas duplas).
Ò ×ØÖ´Üµ Ü
ÓÙØ ×ØÖ´Ø ×Ø µ
Isto seria traduzido para:
ÓÙØ Ø ×Ø
O operador ## concatena dois argumentos, não deixando espaço em branco entre eles:
Ò ÙÒ
´ ¸ µ
ÙÒ
´
¸ÓÙØµ Ø ×Ø
132
134.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Isto também seria traduzido para:
ÓÙØ Ø ×Ø
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 obscuro
para outros programadores, já que a sintaxe que eles experam é, na maioria dos casos, diferente
de expressões comuns que programadores esperam em C++.
Inclusões condicionais (#ifdef, #ifndef, #if, #endif, #else and #elif)
São diretivas que permitem incluir ou descartar parte do código de um programa se uma certa
condição for encontrada.
Ì Å ÆÀÇ Ì Ä
ÒØ Ø Ð Ì Å ÆÀÇ Ì Ä ℄
Ò
#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 foi
definida, 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 é compilado
se o identificador especificado não foi definido previamente. Exemplo:
Ò Ì Å ÆÀÇ Ì Ä
Ò Ì Å ÆÀÇ Ì Ä ½¼¼
Ò
ÒØ Ø Ð Ì Å ÆÀÇ Ì Ä ℄
Neste caso, se quando chegarmos neste pedaço de código, a macro TAMANHO_TABELA
ainda não foi definida, seria definida com um valor de 100. Se já existia, manteria o valor anterior
já 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 ser
encontrada 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:
Ì Å ÆÀÇ Ì Ä ¾¼¼
ÙÒ Ì Å ÆÀÇ Ì Ä
Ò Ì Å ÆÀÇ Ì Ä ¾¼¼
Ð Ì Å ÆÀÇ Ì Ä ¼
ÙÒ Ì Å ÆÀÇ Ì Ä
Ò Ì Å ÆÀÇ Ì Ä ¼
133
135.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Ð×
ÙÒ Ì Å ÆÀÇ Ì Ä
Ò Ì Å ÆÀÇ Ì Ä ½¼¼
Ò
ÒØ Ø Ð Ì Å ÆÀÇ Ì Ä ℄
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:
Ò Ì Å ÆÀÇ Ì Ä
Ò Ì Å ÆÀÇ Ì Ä ½¼¼
Ð Ò Ì Å ÆÀÇ Î ÌÇÊ
Ò Ì Å ÆÀÇ Ì Ä Ì Å ÆÀÇ Î ÌÇÊ
ÒØ Ø Ð Ì Å ÆÀÇ Ì Ä ℄
Controle de Linha (#line)
Quando compilamos um programa e algum erro acontece durante este processo, o compilador
mostra uma mensagem de erro com referências ao nome do arquivo onde o erro aconteceu e o
nú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 de
código assim como o nome do arquivo que queremos que apareça quando um erro acontece.
Seu formato é:
Ð Ò ÒÙÑ ÖÓ ÒÓÑ Ó ÖÕÙ ÚÓ
, onde numero é o novo número da linha que será atribuído à próxima linha de código. Os
nú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:
Ð Ò ¾¼ ØÖ Ù Ò Ó Ú Ö Ú Ð
ÒØ
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ção
do erro que pode ser especificado como seu parâmetro:
Ò
ÔÐÙ×ÔÐÙ×
ÖÖÓÖ ÍÑ
ÓÑÔ Ð ÓÖ ·· × Þ Ò
×× Ö Ó
Ò
134
136.
CDTC Centro deDifusã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 um
arquivo especificado. Existem duas maneiras de especificar um arquivo a ser incluído:
Ò
ÐÙ ÖÕÙ ÚÓ
Ò
ÐÙ ÖÕÙ ÚÓ
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ão
normalmente 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ência
de 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 aaaacontendo a data em que
o processo de compilação se iniciou.
__TIME__ Uma string na forma hh:mm:sscontendo 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 de
acordo com o padrão C++, seu valor é igual ou maior que 199711L
dependendo da versão do padrão a que eles estão de acordo.
135
137.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
Exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò´µ
ß
ÓÙØ ר Ó Ò Ñ ÖÓ Ð Ò ÄÁÆ
ÓÙØ Ó ÖÕÙ ÚÓ ÁÄ º Ò
ÓÙØ
ÓÑÔ Ð
Ó
ÓÑ
ÓÙ Ñ Ì
ÓÙØ × ÌÁÅ º Ò
ÓÙØ Ç
ÓÑÔ Ð ÓÖ ÙÑ Ú ÐÓÖ
ÔÐÙ×ÔÐÙ×
ÔÐÙ×ÔÐÙ×
Ö ØÙÖÒ ¼
, o que retornaria:
ר Ó Ò Ñ ÖÓ Ð Ò Ó ÖÕÙ ÚÓ » ÓÑ » Ý»×Ø Ñ
ÖÓÒ Ñ ×º
ÔÔº
ÓÑÔ Ð
Ó
ÓÑ
ÓÙ Ñ ÆÓÚ ½ ¾¼¼ × ½¼ ½¾ ¾ º
Ç
ÓÑÔ Ð ÓÖ ÙÑ Ú ÐÓÖ
ÔÐÙ×ÔÐÙ× ½
136
138.
Capítulo 14
Entrada/Saída comArquivos
Temos à nossa disposição as seguintes classes em C++ para relizar operações de entrada e
saí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á usamos
objetos cujos tipos eram essas classes: cin é um objeto da classe istream e cout é um objeto da
classe 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 cin
e cout, com a diferença que temos que associar essas streams com arquivos físicos. Vejamos
um exemplo:
Ò
ÐÙ Ó×ØÖ Ñ
Ò
ÐÙ ×ØÖ Ñ
Ù× Ò Ò Ñ ×Ô
ר
ÒØ Ñ Ò ´µ ß
Ó ×ØÖ Ñ Ñ ÖÕÙ ÚÓ
Ñ ÖÕÙ ÚÓºÓÔ Ò ´ Ü ÑÔÐÓºØÜØ µ
Ñ ÖÕÙ ÚÓ ×
Ö Ú Ò Ó Ñ ÙÑ ÖÕÙ ÚÓº Ò
Ñ ÖÕÙ ÚÓº
ÐÓ× ´µ
Ö ØÙÖÒ ¼
, o que resulta numa escrita num arquivo:
Ð Ü ÑÔÐÓºØÜØ℄
×
Ö Ú Ò Ó Ñ ÙÑ ÖÕÙ ÚÓ
Este 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
139.
CDTC Centro deDifusão de Tecnologia e Conhecimento Brasília/DF
A primeira operação geralmente realizada em um objeto de uma dessas classes é associá-la
a 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():
ÓÔ Ò ´ÒÓÑ Ó ÖÕÙ ÚÓ¸ ÑÓ µ
, 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 opcional
com uma combinação das seguintes flags:
ios::in Open (Abrir) para operações de entrada
ios::out Open para operações de saída
ios::binary Open para modo binário
ios::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 em
streams Open para operações de saída.
ios::trunc Se o arquivo aberto para operações de saída já existirem antes, seu conteúdo
anterior é 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 seguinte
chamada à função membro open():
Ó ×ØÖ Ñ Ñ ÖÕÙ ÚÓ
Ñ ÖÕÙ ÚÓºÓÔ Ò ´ Ü ÑÔÐÓº Ò ¸ Ó× ÓÙØ Ó× ÔÔ Ó× Ò Öݵ
Cada uma das funções membro open() das classes ofstream, ifstream e fstream tem um modo
padrão que é usado se o arquivo é aberto sem um segundo argumento:
classe parâmetro mode padrão
ofstream ios::out
ifstream ios::in
fstream 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 a
funçã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 naquele
parâ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
140.
CDTC Centro deDifusã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 membro
open() e tem exatamente os mesmos parâmetros que este membro. Assim, poderíamos também
ter declarado o objeto marquivo anterior e conduzido a mesma operação de abertura no exemplo
fazendo:
Ó ×ØÖ Ñ Ñ ÖÕÙ ÚÓ ´ Ü ÑÔÐÓº Ò ¸ Ó× ÓÙØ Ó× ÔÔ Ó× Ò Öݵ
Combinando construção do objeto e abertura de stream em uma mesma expressão. Ambas
as 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 em
que realmente o objeto stream for associado com um arquivo aberto, ou false em caso contrário.
´Ñ ÖÕÙ ÚÓº × ÓÔ Ò´µµ ß »¶ Ó ¸ ÔÖÓ××
ÓÑ × ¶»
Fechando um arquivo
Quando finalizamos com nossas operações de entrada e saída em um arquivo, devemos fechá-lo
para que ses recursos se tornem disponíveis novamente. Para isso, temos que chamar a função
membro strem close(). Esta função membro não recebe parâmetros, e o que ela faz é esvaziar
os buffers e fechar o arquivo:
Ñ ÖÕÙ ÚÓº
ÐÓ× ´µ
uma vez que esta função membro é chamada, o objeto stream pode ser usado para abrir
um outro arquivo, e o arquivo está disponível para ser aberto por outros processos. No caso
em que um objeto é destruído enquanto ainda é associado a um arquivo aberto, o destrutor
automaticamente chama a função membro close().
139