Escolar Documentos
Profissional Documentos
Cultura Documentos
Apostila PDF
Apostila PDF
e Orientao a Objetos
PET Computao
Fbio Beltro, Felipe Chies, Lucas Zawacki, Marcos Cavinato e
Matheus Proena
2 Edio, 18 de Agosto de 2009
1 Edio por
Arthur Ribacki, Gabriel Portal, Leonardo Chatain e Roslia Galiazzi
Sumrio
1 Introduo ao C++
1.1 Histria do C++ . . . . . .
1.2 Primeiros Programas . . . .
1.3 Namespaces . . . . . . . . .
1.4 Variveis Locais e Globais .
1.5 Tipos de Dados . . . . . . .
1.6 Modificadores . . . . . . . .
1.7 Estruturas de Controle . . .
1.8 Funes . . . . . . . . . . .
1.8.1 Funes inline . . . .
1.8.2 Parmetros Default
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
4
4
5
5
6
6
8
8
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
13
14
14
16
17
18
21
21
22
23
3 Sobrecarga
3.1 Quando usar? . . . . . . . . . . . . . . . . .
3.2 Modificador friend . . . . . . . . . . . . . .
3.3 Fundamentos de Sobrecarga de Operadores
3.4 Funes Friend . . . . . . . . . . . . . . . .
3.4.1 Sintaxe . . . . . . . . . . . . . . . .
3.5 Sobrecarga de Operadores Unrios . . . . .
3.6 Sobrecarga de Operadores Binrios . . . . .
3.7 Sobrecarga dos Operadores de Streams . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
25
25
26
28
29
29
30
30
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
SUMRIO
3.8
3.9
31
32
32
4 Herana
4.1 Classe base e Classes Derivadas: . . . . . . . . . . . . . . . .
4.2 Membros Protected . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1 Sintaxe . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.2 Exemplos de Herana . . . . . . . . . . . . . . . . . .
4.3 Coero de ponteiros entre classes bases e classes derivadas .
4.4 Sobrescrevendo membros da classe base em uma classe derivada
4.4.1 Output . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5 Tipos de Herana . . . . . . . . . . . . . . . . . . . . . . . . .
4.6 Herana Mltipla . . . . . . . . . . . . . . . . . . . . . . . . .
4.6.1 Output . . . . . . . . . . . . . . . . . . . . . . . . . .
33
33
35
35
35
37
39
41
41
42
42
.
.
.
.
.
.
45
45
47
47
47
49
49
.
.
.
.
.
.
.
.
.
.
51
51
51
52
52
52
53
53
53
55
57
.
.
.
.
59
59
60
60
62
6 Templates e Excees
6.1 Templates para Funes
6.1.1 Sintaxe . . . . .
6.1.2 Exemplo . . . . .
6.2 Template de Classe . . .
6.2.1 Sintaxe . . . . .
6.2.2 Exemplo . . . . .
6.3 Introduo a Excees .
6.4 Try, Throw e Catch . .
6.4.1 Exemplo . . . . .
6.4.2 Exerccio . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7 Processamento de Arquivos
7.0.3 Arquivos em C++ .
7.0.4 Arquivo Seqencial .
7.0.5 Modos de Abertura
7.1 Arquivo Aleatrio . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
SUMRIO
8 Standard Template Library
63
8.1 Conhecendo a STL . . . . . . . . . . . . . . . . . . . . . . . . 63
8.2 Continers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
8.3 Funes Membro Comuns . . . . . . . . . . . . . . . . . . . . 64
8.4 Funes Membro Especficas . . . . . . . . . . . . . . . . . . . 65
8.4.1 Arquivos de Cabealho . . . . . . . . . . . . . . . . . . 65
8.5 Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
8.5.1 Teste de Aprendizado . . . . . . . . . . . . . . . . . . 66
8.6 Como lidar com capacidade ilimitada, ou como o Vector no
mgico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
8.6.1 Observao . . . . . . . . . . . . . . . . . . . . . . . . 69
8.7 List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
8.8 Outros Containers . . . . . . . . . . . . . . . . . . . . . . . . 70
8.9 Iteradores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
8.10 Algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
8.10.1 Usando o Algoritmo Sort para qualquer Ordenao . . 75
8.11 Usando a STL com Classes Prprias . . . . . . . . . . . . . . 75
8.11.1 Teste de Aprendizado . . . . . . . . . . . . . . . . . . 78
8.12 ltimas Consideraes . . . . . . . . . . . . . . . . . . . . . . 78
Captulo 1
Introduo ao C++
Antes de comearmos o estudo da linguagem, necessrio que se entenda
por que to importante aprender C++. Existe, atualmente, uma demanda
muito grande por software, que deve ser construdo rpida, correta e economicamente. A orientao a objetos surge com o objetivo de ajudar a suprir essa
demanda. Fortemente baseada no princpio de reutilizao de componentes e estreitamente ligada engenharia de software, permite uma reduo do tempo de
implementao bastante significativa. Alm disso, atravs de uma organizao
modular e independente, melhora a manutenabilidade e aumenta a confiabilidade dos programas.
1.1
Histria do C++
Introduo ao C++
1.2
Primeiros Programas
Pode se observar que a primeira linha precedida por //. Essa a sintaxe
do comentrio de uma linha do C++. O compilador deve ignorar tudo aquilo
que estiver direita de duas barras invertidas, mesmo que no no comeo,
como se pode ver algumas linhas depois. Vale observar que os comentrios do
C (iniciados por /* e terminados por */ ) t ambm so utilizados em C++,
principalmente para fazer comentrios de vrias linhas. A diretiva #include
conhecida para os programadores de C, bastando observar que a biblioteca no
a mesma e que, para bibliotecas padro, no includo o .h do arquivo header.
As funes std::cout e std::endl, substituem, respectivamente, a funo
printf e o caractere \n do C. S para relembrar, isso significa que std::cout escrever na tela, enquanto std::endl adicionar uma nova linha. Uma das grandes
vantagens desse mtodo a segurana de tipos, ou seja, o fato de que a funo
sabe qual o tipo do dado que est sendo passado a ela, e responde de acordo.
Por exemplo, o cdigo 1.2 imprime a frase Meu nome Lucas, tenho 18 anos..
A entrada em C++ to simples quanto a sada, trocando apenas o nome
da varivel para std::cin e a direo dos operadores, para . O tipo da varivel
e o significado dos operadores e sero discutidos em captulos posteriores,
por enquanto basta aprender seu funcionamento. O programa 1.3, que l duas
variveis da tela e imprime sua soma, trivial e tem por objetivo fixar a sintaxe,
de modo que no ser detalhado.
c o u t << "Meu nome eh " << nome << " , tenho " << i d a d e <<
" anos . " << e n d l ;
Introduo ao C++
1.3
Namespaces
1.4
Em C++, todo bloco de comandos deve estar entre chaves ({ }). Segundo
as regras de hierarquia de escopo, qualquer varivel declarada dentro de um
bloco visvel apenas dentro do mesmo (inclua-se qualquer sub-bloco), sendo
destruda assim que o bloco finalizado. Essas so chamadas variveis locais, em
contraponto s variveis declaradas fora de qualquer bloco, chamadas variveis
globais.
Foi introduzido na linguagem um novo operador: o operador de escopo,
representado por ::. Este operador utilizado para se acessar uma varivel de
escopo superior cujo nome seja o mesmo de uma varivel local (neste caso, a
varivel de escopo superior estaria inacessvel). Exemplificando: caso se tenha
uma varivel com o nome x num escopo global e declare-se uma varivel x num
escopo local, teoricamente a varivel x global ficaria inacessvel no respectivo
bloco. Contudo, referenciando-se ::x possvel acessar o x global.
Cdigo 1.4: Escopos
#include <i o s t r e a m >
using namespace s t d ;
// demonstrando os d i f e r e n t e s e s c o p o s
int i = 1 2 ;
i n t main ( )
{
int i ;
// uso do o p e r a d o r : :
f o r ( i =0 ; i < : : i ; i ++)
{
c o u t << i << e n d l ;
}
}
1.5
Tipos de Dados
1.6
Modificadores
Modificadores so utilizados para especificar determinados tipos de tratamento s variveis. Os dois tipos mais comuns so const e static. Const declara
uma varivel (ou funo, como veremos posteriormente) como sendo constante,
Introduo ao C++
de modo que o compilador previne erros do programador (caso seja feita uma
tentativa errnea de alterao do valor). Alm disso, o compilador faz algumas otimizaes quando sabe que o valor de uma varivel no ser alterado.
A palavra-chave static usada principalmente dentro de funes (tambm
usada em classes, mas isso ser discutido no momento adequado). Ela serve
pra dizer que o valor da varivel no deve ser descartado no final na execuo,
como seria normal a uma varivel local, mas guardado para uso posterior. O
cdigo 1.6 demonstra isso.
Cdigo 1.6: Modificadores
// Demonstrando o m o d i f i c a d o r s t a t i c
#include <i o s t r e a m >
void i n c r e m e n t a ( )
{
s t a t i c in t c = 0 ;
c++;
s t d : : c o u t << c << s t d : : e n d l ;
}
i n t main ( )
{
incrementa ( ) ;
incrementa ( ) ;
}
return 0 ;
1.7
Estruturas de Controle
1.8
Funes
1.8 Funes
Introduo ao C++
1.8.1
Funes inline
1.8.2
Parmetros Default
1.8 Funes
10
Introduo ao C++
s t d : : c o u t << v a l o r << s t d : : e n d l ;
1.8 Funes
11
isso fazendo uma atribuio para cada parmetro default dentro da declarao
da funo. Contudo, para o compilador no se confundir, sempre que um
parmetro omitido todos parmetros esquerda devem ter um valor default
tambm e devero ser omitidos.
Cdigo 1.13: Parmetros Default
#include <i o s t r e a m >
using namespace s t d ;
i n t cubo ( i n t x = 3 ) { return xxx ; }
i n t main ( )
{
c o u t << cubo ( 5 ) << e n d l ;
c o u t << cubo ( ) << e n d l ;
}
Captulo 2
Introduo a Orientao a
Objetos
Nessa seo, sero introduzidos os alicerces da programao orientada a
objetos, um dos principais recursos exclusivos de C++ em relao a C. O total
entendimento dos conceitos a seguir imprescindvel para a continuao do
curso. Para entender a Orientao a Objetos, preciso inicialmente que se
entenda a que nos referimos quando falamos de objeto. O conceito de objeto
na programao bastante similar ao usual. Um objeto possui caractersticas e
realiza determinadas aes.
2.1
14
2.2
2.2.1
Classes
Encapsulamento
2.2 Classes
15
};
private :
int cor ;
int a c e l e r a c a o ;
16
2.2.2
No exemplo acima, so aceitas apenas 256 cores diferentes. Ainda que isso
seja informado ao usurio, no se pode garantir que ele realmente siga essa
recomendao. Torna-se ento clara a utilidade dos membros privados (e das
funes set, como so chamadas geralmente as funes de atribuio). Caso
cor fosse um membro pblico, a verificao teria de ser feita pelo programador
fora da classe, ou se permitiria que fossem atribudos dados invlidos varivel.
A possibilidade de realizar a validao dos dados internamente, torna a
classe auto-contida, tornando-a mais robusta e confivel, e contribuindo para a
organizao e reutilizao do cdigo.
2.2 Classes
2.2.3
17
Construtores e Destrutores
Alm da diviso dos dados entre pblicos e privados, outro detalhe estranho
chama diretamente nossa ateno quando olhamos pela primeira vez a implementao de uma classe. Existem duas funes com o nome da classe, e sem
qualquer tipo. No nosso exemplo, Carro() e Carro(). A primeira funo,
Carro(), o construtor da classe.
Construtores so os responsveis pela alocao de memria e inicializao
de dados, sendo sempre chamados automaticamente na declarao um novo
objeto. O uso de construtores elimina o problema de ter que manualmente
inicializar os dados sempre que declarados, o que pode ser esquecido e levar a
erros.
Cdigo 2.3: Construtor
#include " c a r r o . h "
Carro : : Carro ( )
{
cor = 0;
}
18
2.2.4
Diviso de Arquivos
Antes de comear a implementar classes em C++, preciso que se observe um detalhe importante das boas prticas de programao. Quando se
cria uma classe, no raro pretender que ela seja utilizada por outras pessoas
posteriormente. No necessrio compartilhar com cada usurio como foi feita
a implementao da classe. Para esconder o cdigo, separamos a definio
e a implementao, utilizando, respectivamente, arquivos header (.h) e source
(.cpp).
Nos arquivos header, coloca-se idealmente apenas aquilo que define como
uma classe deve ser utilizada, basicamente seus atributos e os cabealhos de suas
funes, sem qualquer referncia a como as funes so implementadas. Diz-se
idealmente, pois nem sempre recomendado, por questes de desempenho, que
se faa isso. A disputa organizao/desempenho, porm, no possui resposta
correta, devendo cada um fazer seu prprio julgamento sobre o que mais
importante. As bases para tal discusso sero dadas mais tarde.
Um exemplo de definio de classe pode ser visto no cdigo 2.2.4.
Observe que no incio do arquivo existem um #ifndef e o nome da classe.
Para explicar a necessidade dessa linha, ser usado um exemplo: Suponhamos
que existam duas classes de um mesmo programa, por exemplo, Imagem e
Boto, e as duas classes possuam um objeto da classe Vetor2D para indicar
sua posio na tela. As duas classes devem ento, incluir o arquivo da classe
2.2 Classes
19
#i f n d e f __VETOR2D_H
#define __VETOR2D_H
c l a s s Vetor2D {
public :
Vetor2D ( ) ;
~Vetor2D ( ) ;
i n t getX ( ) ;
i n t getY ( ) ;
void setX ( i n t newX) ;
void setY ( i n t newY) ;
private :
int x , y ;
#endif
Vetor2D. O problema que uma classe no pode ser includa mais de uma vez,
j que, se isso acontece, uma varivel redeclarada, e o compilador acusa um
erro de Nome-davarivel redefined. Para que isso no ocorra, criamos uma
flag que testa se o arquivo j foi includo.
20
2.3 Composio
2.3
21
Composio
2.4
Objetos Constantes
s vezes, interessante informarmos ao compilador que um objeto constante. Isso porque o compilador consegue realizar algumas otimizaes significativas quando usamos constantes. Alm disso, caso seja feita uma tentativa
de modificar uma constante, o compilador avisa e gera um erro sinttico, muito
mais facilmente corrigvel que um erro de lgica.
Para tornar um objeto constante, basta adicionar antes dele a palavra-chave
const como mostrado no cdigo 2.9. Existem vrios usos para essa possibilidade,
sendo o mais simples deles a passagem de parmetros constantes em funes,
de modo que a funo no possa alterlos em seu interior.
Cdigo 2.9: Argumentos Constantes
#include " c a r r o . h "
void Carro : : s e t C o r ( const i n t novaCor )
{
c o r = novaCor ;
}
22
2.5
23
2.6
Ponteiro this
Captulo 3
Sobrecarga
Sobrecarga, pode ser encarada como uma prtica utilizada na programao,
que visa associar a um mesmo nome (ou smbolo) mais de um comportamento.
Para entender o conceito vamos comear com um tipo simples de sobrecarga, a
sobrecarga de funes. Entende-se por isso, definir vrias funes com o mesmo
nome. Em C++ esta prtica possvel, desde que o conjunto de parmetros
de todas seja diferente. O compilador consegue definir qual funo chamar de
acordo com a lista de parmetros da funo chamada. Neste captulo sero
abordadas tcnicas e possibilidades de sobrecarga na linguagem C++.
3.1
Quando usar?
3.2
Modificador friend
26
Sobrecarga
objetos. Para declarar uma funo como friend de outra classe deve-se preceder
o prottipo da funo na definio da classe com a palavra-chave friend.
Uma classe friend funciona da mesma forma que uma funo friend, isto ,
tem acesso tanto a membros private como protected da classe da qual friend.
Para declarar uma classe como friend de outra, deve-se colocar na declarao
da segunda friend.
Exemplos da sintaxe de friend podem ser vistos nos cdigos 3.2, 3.3.
3.3
int a , b , c ;
void f (X a l g o )
{
algo . a + algo . b + algo . c ;
}
i n t main ( )
{
X alguem ;
f ( alguem ) ; // okay
}
};
...
};
27
28
Sobrecarga
criada pelo usurio, o compilador no saberia como proceder diante da seguinte
expresso: vetor1 = vetor2 + vetor3;
Visto que os operadores de adio e atribuio esto definidos apenas para
os tipos primitivos de dados. Para resolver este pequeno problema, precisamos
utilizar o recurso de sobrecarga de operadores disponibilizado pelo C++. A
prpria linguagem utiliza este recurso internamente. O operador de adio,
por exemplo, trabalha diferentemente com ints, floats e doubles, entretanto,
utiliza-se o mesmo operador para realizar tais operaes aritmticas.
Os seguintes operadores da linguagem C++ podem ser sobrecarregados:
3.4
Funes Friend
3.4.1
Sintaxe
3.5
A sobrecarga de operadores unrios pode ser realizada de duas formas diferentes, como foi visto anteriormente. Se escolhermos que a funo de sobrecarga
deve ser uma funo membro da classe, ento ser uma funo sem parmetros, visto que o nico operando ser o prprio objeto da classe que realiza a
chamada do operador, como podemos ver no exemplo 3.5.
Cdigo 3.5: Operadores Unrios
// c l a s s e de numeros c o m p l e x o s
c l a s s Complexo
{
public :
bool operator ! ( ) ;
/ v e r i f i c a s e os termos r e a i s e i m a g i n a r i o s do numero
complexo sao 0 /
};
29
30
Sobrecarga
3.6
3.7
3.7.1
Agora, declare estas funes como friend da sua classe Complexo. Insira
o cdigo das funes no arquivo .cpp e teste o funcionamento delas em um
programa teste.
31
32
Sobrecarga
3.8
Atravs deste artficio, possvel realizar uma converso de uma classe para
outra classe ou de uma classe para um tipo primitivo. O prottipo de funo
para um operador de cast o seguinte:
3.9
Sobrecarregando ++ e - -
Os operadores de incremento e decremento tambm podem ser sobrecarregados, contudo estes tm certa peculiaridade devido ao fato de que podem
ser pr/ps incremento/decremento. Na verdade, o nico cuidado que deve
ser tomado o de diferenciar as funes para que o compilador saiba quando
deve chamar cada funo.
A verso de prefixo, isto o pr-incremento e o pr-decremento, so implementadas da mesma forma que as funes de sobrecarga que vimos at
agora, sem nenhuma mudana. A diferenciao vem na outra verso, a de
ps-incremento e psdecremento, pois agora preciso diferenci-la da anterior.
Para isso, foi adotada uma conveno em que este tipo de funo deve ter um
parmetro fantasma inteiro, com o valor de 0.
Cdigo 3.10: Sobrecarga do ++
Complexo operator++() ;
// f u n c a o de prei n c r e m e n t o
Complexo operator++(i n t x ) ;
// f u n c a o de posi n c r e m e n t o
Captulo 4
Herana
Nesta aula iremos estudar um dos recursos mais importantes da programao
orientada a objetos: a herana. Ela nos permite reutilizao de software de
qualidade reconhecida, reduo da quantidade de cdigo repetido e nos auxilia
na manuteno do software.
No decorrer da aula mostraremos exemplos de cada uma destas utilizaes.
Antes de comearmos a codificar a herana em C++ vamos entender seu significado no mundo dos objetos. Segundo o site www.direitonet.com.br, herana:
o patrimnio deixado pela pessoa falecida aos seus herdeiros, ou seja, a
totalidade dos direitos e obrigaes de uma pessoa no momento em que vem a
falecer.
No mundo dos objetos, herana possui um sentido muito parecido com
o exposto acima com duas diferenas: que no necessrio que uma classe
morra para que outra possa herdar seus atributos e funes membros, nem a
classe que herdada perde seus atributos e funes membros para a classe
que a herdou; feita uma cpia deles. Vamos comear definindo melhor os
conceitos apresentados acima:
4.1
Classe base e Classes Derivadas: Uma relao entre objetos j vista foi a
tem um, onde um objeto continha como membros objetos de uma classe distinta da sua. Por exemplo, um carro tem um passageiro. A herana introduz um
relacionamento do tipo um, onde um objeto de uma classe um objeto
de outra classe tambm. Podemos dizer que um retngulo um quadriltero
(assim como um losango e um paralelogramo tambm o so). Assim, dizemos que a classe Retangulo herda da classe Quadrilatero. Dizemos ento que
Quadrilatero a classe base enquanto Retangulo a classe derivada.
Um dos exemplos mais clssicos de herana a classificao taxonmica
dos seres vivos. Mostramos a seguir um exemplo que mostra bem a estrutura
de rvore apresentada pela herana:
34
Herana
Vemos que a classe base para todas a classe Carnivora, que poderia apresentar uma funo membro void comerCarne(); (pode-ser argumentar que
nem todos carnvoros comero carne da mesma maneira. Mais tarde veremos
que isso pode ser resolvido atravs da sobrescrita dessas funes). Seguindo,
vemos que a classe Canidae base para Canis e Vulpes, e que Felidae base
para Felis e Panthera.
Tendo todas essas classes definidas facil criarmos vrias classes novas:
podemos ter um Cachorro, um Lobo e um Coiote sem termos que escrever muito
cdigo, pois herdamos as caractersticas comuns da classe Canis. Tambm,
podemos ter um Leao, um Tigre e uma Pantera como classes derivadas de
Panthera, sem nos preocupar com suas caractersticas mais comuns (pois estas
j esto escritas). Ou seja, o que fizemos foi juntar as partes comuns as classes
que queremos definir.
Esse um exemplo da reduo de cdigo repetido. Temos tudo pronto.
Agora, no entanto, descobrimos que existe um algortimo de alimentao mais
eficiente, e queremos implement-lo em nossos animais. Se no estivssemos
usando herana, seria necessrio escrever a nova funo em cada uma das classes
(quanto mais escrevermos, maiores as chances de erros). Mas, graas a herana,
modificamos a funo em nossa classe base e todos animais estaro comendo
dessa maneira (excetuando as classes onde sobrescrevemos a funo).
Esse um exemplo da facilidade de manuteno de software que a herana
proporciona. Vamos supor que o objetivo dessas classes era o de implementar
uma simulao de zoolgico. O software terminado, testado e passa-se a
us-lo.
Alguns bugs vo aparecendo e sendo corrigidos e depois de um tempo o
software se torna razoavelmente estvel. Aps alguns meses, chegam novos
animais, um Leopardo por exemplo. J temos nossa classe Panthera com a
qualidade reconhecida. Ao criarmos a classe Leopardo, ser fcil e teremos que
nos concentrar em corrigir erros de um cdigo muito menor (apenas a parte
especfica do Leopardo). Esse um exemplo da reutilizao do cdigo.
4.2
Membros Protected
4.2.1
Sintaxe
4.2.2
Exemplos de Herana
35
36
Herana
};
#endif
4.3
37
38
Herana
// Temos um Canis . . .
// Pode s e r um c a c h o r r o . . . s e r a ?
dogPtr>l e v a r _ p a s s e a r ( ) ;
f o r ( i = 0 ; i < q u a n t i d a d e ; i ++)
{
i f ( F e l i s P t r = dynamic_cast<Gato >( l i s t a F e l i n o s [ i ] ) )
{
// Trata os F e l i n o s a t r a v e s de F e l i s P t r .
}
e l s e i f ( Panthera = dynamic_cast<Gato >( l i s t a F e l i n o s [
i ]) )
{
// Trata os P a n t h e r a s a t r a v e s de P a n t h e r a P t r .
}
else
{
// Tratas e os o u t r a s c a s o s .
}
}
4.4
40
Herana
};
#endif // Implementacao da c l a s s e Cachorro .
4.4.1
Output
4.5
Tipos de Herana
41
42
Herana
Especificador de Acesso
public
protected
private
4.6
Tipo de Herana
public
protected private
public
protected
private
protected protected
private
oculto
oculto
oculto
Herana Mltipla
4.6.1
Output
43
};
protected :
char name ;
#endif
44
Herana
Captulo 5
Funes Virtuais e
Polimorfismo
O polimorfismo a capacidade de alguns ponteiros apontarem para diferentes tipos de dados. Essa idia no trivial e est muito conectada ao conceito
de herana entre classes, de modo que se faz necessrio um entendimento profundo dos captulos anteriores e uma dedicao especial ao estudo deste.
5.1
Funes Virtuais
46
};
private :
int x , y , z ;
};
public : T r i a n g u l o ( ) ;
~Triangulo () ;
v i r t u a l void desenha ( ) const ;
private :
i n t lado1 , lado2 , l a d o 3 ;
5.1.1
Teste de Aprendizado
Construa trs classes: uma classe base Empregado e duas classes derivadas
Contratado e Comissionado. As classes devem possuir a funo imprimeSalario,
que no caso do Contratado, deve ser um valor fixo, e no caso do Comissionado
deve ser um valor relativo quantidade de produtos vendidos.
Implemente um programa que escreva o salrio de cada comissionado a partir de um ponteiro polimorfo da classe base. Obs: No perca tempo com o
clculo do salrio, imprima um valor constante (Ex: O contratado recebe 600
reais/ O comissionado recebe 25% do lucro gerado). O objetivo do exerccio
testar o entendimento do polimorfismo, no da matemtica.
Obs2: No declare as funes como virtual no .cpp, apenas no .h.
5.2
s vezes, desejamos criar uma funo genrica para tratar inmeras classes
de uma mesma hierarquia. Um caso em que essa tcnica til, por exemplo,
caso desejemos derivar nossa classe de uma classe cujo cdigo no nos
acessvel. Isso possvel usando um parmetro polimorfo. Como exemplo,
utilizemos as classes j declaradas, FormaGeometrica, Triangulo e Quadrado.
Caso desejemos, por exemplo, criar uma funo Move, para os dois tipos de
forma geomtrica, necessrio passar como parmetro algo genrico, ou seja,
um ponteiro para a classe base. Como descrito no cdigo 5.4.
5.2.1
Teste de Aprendizado
47
48
form = &quad ;
Move ( form , 1 0 , 10 , 0 ) ;
form = &t r i ;
Move ( form , 2 0 , 2 0 , 2 0 ) ;
s t d : : c o u t << " x do quadrado :
s t d : : c o u t << " y do quadrado :
s t d : : c o u t << " z do quadrado :
s t d : : c o u t << " x do t r i a n g u l o
s t d : : c o u t << " y do t r i a n g u l o
s t d : : c o u t << " z do t r i a n g u l o
return 0 ;
<<
<<
<<
<<
<<
<<
std
std
std
std
std
std
::
::
::
::
::
::
endl ;
endl ;
endl ;
endl ;
endl ;
endl ;
5.3
5.3.1
Teste de Aprendizado
49
Captulo 6
Templates e Excees
Templates um dos recursos mais poderosos da linguagem C++. E ser
este o foco do estudo nesta parte do captulo. O conceito consiste, basicamente,
em escrever um modelo de cdigo a partir do qual o compilador ser capaz de
produzir uma srie de cdigo automaticamente. Existem dois tipos de templates
diferentes: de funo e de classe.
6.1
Atravs de templates de funo, possvel especificar, com apenas um segmento de cdigo, uma srie de funes correlacionadas, que na verdade so
sobrecarregadas. Na verdade, o template um molde para funes, contudo
no se especifica um tipo para a mesma (o tipo deixado genericamente).
Quando ela chamada, o compilador analisa o tipo chamado e escreve pelo
usurio a funo como deveria ser com o tipo especificado.
Parece mgica, mas to simples quanto parece. Imagine uma funo que
soma dois inteiros. Facilmente implementvel, com certeza. Agora, preciso
somar dois floats: sem dvida uma funo semelhante. Assim, Somar dois
doubles no deve apresentar maiores dificuldades. E somar dois vetores (tipo
criado pelo usurio)...
Todas essas so tarefas semelhantes, que exigem a escrita de cdigo duplicado. Utilizando templates possvel escrever uma nica funo que some o
que voc quiser. Deve ser observado que, para tipos criados pelo usurio, os
operadores utilizados devem ter sido corretamente sobrecarregados.
6.1.1
Sintaxe
A sintaxe para uso de funes template trivial. Comece pela palavrachave template seguido da lista de tipos definidos pelo usurio entre os sinais
de menor e maior. No cdigo 6.1, a declarao normal da funo, referindo ao
tipo genrico especificado quando necessrio.
52
Templates e Excees
6.1.2
Exemplo
Cdigo 6.1: Template de Funes
Exerccio:
1. Escreva um template de funo que ordene quaisquer tipos. Teste com
os tipos primitivos int e float.
2. Agora crie uma classe Funcionario bem simples que tenha um atributo
int idade. E teste sua funo template para essa classe ordenando os funcionrios por idade (para funcionar provvel que necessite sobrecarregar
alguns operadores).
6.2
Template de Classe
6.2.1
Sintaxe
6.2.2
6.3
Exemplo
Introduo a Excees
6.4
53
54
Templates e Excees
6.4.1
Exemplo
Note que o comando throw chama o construtor da classe DivideByZeroException criando, dessa forma, um objeto dessa classe. Este objeto ser lanado
pelo comando throw, e quando o erro for detectado pelo bloco try o comando
catch capturar este objeto e ir tratar adequadamente a exceo. O comando
throw pode lanar objetos, ou mesmo tipos primitivos. E ser este tipo que
definir qual bloco catch tratar da exceo em questo.
55
56
Templates e Excees
catch ( i n t x )
{ ... }
c a t c h ( double y )
{ ... }
Estes so blocos sintaticamente corretos, contudo, costuma-se escolher objetos, pois estes podem transportar alguma informao til para o tratamento da
exceo. Caso se deseje capturar todas as excees, de qualquer tipo, utiliza-se
reticncias entre os parnteses que sucedem o catch:
c a t c h ( . . . ) {}
6.4.2
Exerccio
57
Captulo 7
Processamento de Arquivos
As variveis de programas so temporrias, isto , sero armazenadas na
memria do seu computador e, assim que seu programa finalizar, elas sero
perdidas. Contudo, existem diversas situaes em que pode ser bem interessante guardar algumas informaes para a prxima vez que o programa executar
(imagine no poder salvar seu jogo no meio e continu-lo depois), ou mesmo
para utilizar estas informaes de alguma outra forma.
Para fazer isto utilizamos arquivos, que so armazenados em dispositivos
secundrios de armazenamento, como o disco rgido do seu computador, e, desta
forma, torna-se bem mais difcil perder os dados. E neste captulo examinaremos
a manipulao de arquivos em C++.
7.0.3
Arquivos em C++
60
Processamento de Arquivos
7.0.4
Arquivo Seqencial
7.0.5
Modos de Abertura
61
return 0;
62
Processamento de Arquivos
e modo de abertura do arquivo. Em seguida, basta ler os valores do arquivo
do mesmo modo que se faz com a entrada de dados padro, trocando cin pelo
objeto criado.
objeto criado variveis que armazenaro os valores lidos do arquivo
Exerccio:
Primeiramente, utilize o cdigo dado para criar um arquivo seqencial de
filmes. Em seguida, faa um programa que leia deste arquivo seqencial e
escreva na tela apenas o nome dos filmes com nota acima de 6.
7.1
Arquivo Aleatrio
Captulo 8
8.1
Conhecendo a STL
64
Categoria
Sequencial
List
Deque
Sequencial
Sequencial
String
Set
Multiset
Map
Sequencial
Associativo
Associativo
Associativo
Multimap
Associativo
Stack
Queue
Priority Queue
Adaptador
Adaptador
Adaptador
Descrio
Inseres/Retiradas rpidas, apenas no fim.
Acesso direto a qualquer elemento.
Inseres/Retiradas rpidas.
Inseres/Retiradas rpidas, no incio e no fim.
Acesso direto a qualquer elemento.
Vetor de caracters tpico.
Pesquisa rpida. Duplicatas no permitidas.
Pesquisa rpida. Duplicatas permitidas.
Mapeamento um para um.
Pesquisa rpida usando chaves.
Duplicatas no permitidas.
Mapeamento um para um.
Pesquisa rpida usando chaves.
Duplicatas permitidas.
Primeiro a entrar, ltimo a sair (FILO)
Primeiro a entrar, primeiro a sair (FIFO)
Mais alta prioridade, primeiro a sair
junto, tambm com uma linha de cdigo. Uma caracterstica interessante dos
algoritmos STL que eles so genricos. Por exemplo, o algoritmo sort, que implementa ordenao de listas, verstil o suficiente para ordenar quase qualquer
vetor de elementos arbitrrios. Este quase deve ser levado em considerao.
Para que o sort funcione, a classe dos elementos internos ao vetor deve prover
um operador < bem definido. Alm disso, no existem restries, o que implica
que o sort pode ordenar elementos de qualquer classe, desde que o predicado
de ordem seja especificado para esta classe!
8.2
Continers
Continers so inseridos, de acordo com suas caractersticas, em trs categorias: seqenciais, associativos e adaptadores de containers. A justificativa para
essa separao provm do uso de cada um dos grupos de containers. Abaixo,
uma lista com os principais containers, alocados em seus respectivos grupos,
seguidos de uma descrio breve de sua utilizao.
8.3
65
#include
<vector>
<list>
<deque>
<string>
<set>
<map>
<stack>
<queue>
::size() retorna um size type (convertvel para unsigned int) que representa o
nmero de elementos do container
::empty() retorna um valor booleano dizendo se o container est vazio
::begin() retorna um iterador para o incio do container
::end() retorna um iterador para um elemento alm do final do container
::rbegin() retorna um iterador reverso para o incio reverso do container (ou
seja, o ltimo elemento do container)
::rend() retorna um iterador reverso para um elemento antes do incio do
container
Alm destes, os operadores tpicos de comparao != e == tambm esto
implementados para continers, bem como construtores de cpia.
8.4
8.4.1
Arquivos de Cabealho
66
8.5
Vector
};
private :
v e c t o r <int> n o t a s ;
8.5.1
Teste de Aprendizado
O que acontece?
Obs.: Utilize vector::size() para pegar o nmero de notas j adicionadas, e,
conseqentemente, o ndice da prxima varivel a ser adicionada.
8.6
67
68
return 0 ;
8.7 List
8.6.1
69
Observao
Ao testar no Dev-C++, que usa o gcc 3.4.2, o cdigo acima s gerou erro ao
acessar o elemento 5000. Porm, ao executar compilando com o g++ no Linux,
um acesso ao item de ndice 4 suficiente para gerar um erro de execuo. Dessa
forma, esse tipo de acesso gera comportamento indefinido, que suficiente para
que seu uso no seja recomendado.
8.7
List
70
return 0 ;
8.8
Outros Containers
A seguir, faremos um breve resumo sobre os outros containers mais especficos da STL, e ainda sobre um tipo de dados especfico, o pair.
Deque Um deque funcionalmente semelhante a um vector. Observe que
deque significa double-ended queue, mas isto no quer dizer que um deque
seja implementado como uma lista encadeada. De fato, deques so implementados como espaos contguos na memria, de forma que inseres
no meio levam tempo linear, mas acesso ao meio leva tempo constante.
A principal diferena entre um vector e um deque que o deque possui os mtodos push front e pop front, que fazem papis anlogos ao
push back e pop back, mas atuam na frente da lista. Da mesma forma
que os vectors, estes mtodos so implementados com uma tcnica de
tempo constante amortizado.
String Strings implementam um vetor de caracteres, para possibilitar formas
de entrada e sada mais alto-nvel do que null-terminated chars em C.
Uma string possui complexidades semelhantes ao vector, de forma que
tambm mantida como rea contgua de memria, mas o tipo de seus
elementos char. Existe uma variante interessante de strings, que so as
wstrings, que permitem trabalhar com chars de 16 bits. Normalmente isto
acontece quando a interface com algum outro programa exige a utilizao
de wide characters, ou seja, caracteres de 16 bits
Set Um set , primeiramente, um container associativo. Isto significa que
8.9 Iteradores
acesso randmico aos seus elementos no possvel. Entretanto, insero
e remoo so executados em tempo O(log n). importante notar que
para containers associativos, no possvel especificar o local onde o elemento ser adicionado, pois estes containers so implementados como
rvores binrias balanceadas. Isto significa, adicionalmente, que os elementos so automaticamente guardados em ordem dentro do container.
Observe que sets no permitem elementos duplicados. As funes nicas
mais importantes de sets so insert, remove e find, que inserem, removem,
e localizam, respectivamente, um elemento no set.
Multiset Muito semelhante ao set, a principal diferena entre eles que enquanto o set no permite colocao de elementos duplicados, um multiset
permite.
Map Um Map um container mais interessante, no sentido de que ele permite
buscas do tipo chave-informao. Dessa forma, os elementos de um map
so pares (std::pair) onde o primeiro elemento representa a chave de busca
e o segundo o valor desejado. O map implementado tambm como uma
rvore binria balanceada onde a ordenao feita com respeito s chaves.
Dessa forma, possvel buscar um valor informando somente uma chave,
com complexidade O(log n). No permitem duplicatas
Multimap Multimaps so anlogos a multisets, no sentido de que so maps
que permitem multiplicidade de elementos.
Modificadores de containeres Stacks, Queues e Priority Queues no so
containeres propriamente ditos, mas sim modificadores que atuam sobre
containeres. Dessa forma, para especificarmos uma stack, por exemplo,
primeiramente temos que definir um container normal (um vector, por exemplo), e depois construir a stack informando este vector. O que acontece
que os mtodos acessados pelo objeto stack sero limitados a acesso e
escrita ao primeiro elemento da pilha, como desejamos. O mesmo acontece para queues e priority queues.
Pair Um Pair no um container. Ao invs disso, um pair uma estrutura de
dados declarada pela STL que permite formarmos pares de tipos genricos. Para especificar um par inteiro-string, por exemplo, devemos fazer
o seguinte: pair<int,string> foo. Os tipos de dados que podem formar
pares so arbitrrios, e para acessarmos elementos do pair, existem os
atributos .first e .second.
8.9
Iteradores
A definio mais simples de iteradores razoavelmente bvia: iteradores iteram sobre o contedo de containers STL. Ou seja, iteradores so tipos de dados
71
72
8.9 Iteradores
73
rvores binrias), o operador++ est bem definido. Finalmente, devemos observar o significado dos comandos foo.begin() e foo.end() no exemplo acima.
foo.begin() um iterador especfico que aponta para o primeiro elemento do
container trabalhado. O foo.end(), entretanto, no aponta para o ltimo elemento, e sim para um elemento alm do ltimo, seguindo de certa forma
o conceito de que ndices em C variam de 0 at n-1, e no at n. Abaixo,
mostramos os tipos principais de iteradores e suas utilidades:
::iterator Este tipo de iterador declara os iteradores mais comuns, que acessam
elementos do container de forma seqencial da esquerda para a direita e
que podem modificar os elementos apontados por eles
::reverse iterator Este tipo de iterador serve para varrer containers de forma
reversa. Como o operador no est declarado para iteradores normais,
no seria possvel iterar reversamente por um container sem este iterador
especial. Observe que o operador++ est definido para este tipo de iterador da mesma forma que para ::iterators, mas para ::reverse iterators
a varredura feita em ordem reversa!
::const iterator Semelhante ao ::iterator, mas com a restrio de que os
elementos s podem ser acessados, e no modificados, utilizando este
iterador. O uso deste iterador existe para podermos varrer containers que
foram declarados const. Se tentarmos varrer um const vector<int> com
um ::iteretor normal, encontraremos um erro de compilao.
::const reverse iterator Anlogo ao ::const iterator, mas se aplica a varredura
reversa do container. Alm disso, cada container tem definido quatro iteradores especiais que servem para limitar laos for, entre outros usos.
Iremos assumir, para os exemplos abaixo, a existncia de um vector<int>
chamado foo, mas de fato estes iteradores esto definidos para qualquer container de qualquer tipo.
foo.begin() este iterador do tipo ::iterator, e aponta para o primeiro elemento do container
foo.end() iterador do tipo ::iterator, aponta para um elemento alm do ltimo elemento do container. Acesso a (*foo.end()) gera comportamento
indefinido.
foo.rbegin() iterador do tipo ::reverse iterator, e aponta para o ltimo elemento do container.
foo.rend() iterador do tipo ::reverse iterator que aponta para um elemento
antes do primeiro elemento do container. Acesso a (*foo.rend()) gera
comportamento indefinido.
74
8.10
Algoritmos
Algoritmos tambm so uma parte bastante importante da Standard Template Library, j que implementam funes usadas muito freqentemente de
forma eficiente, facilitando muito o trabalho do programador. Um exemplo de
algoritmo extremamente utilizado o de ordenao. Atravs desse algoritmo,
fica fcil organizar um vetor (ou algum outro tipo de estrutura) usando qualquer
tipo de relao de ordem. No exemplo 8.6, usaremos a funo sort para ordenar
inteiros de forma crescente.
Cdigo 8.6: STL Sort
#include <a l g o r i t h m >
i n t main ( )
{
v e c t o r <int> numeros ;
f o r ( i n t i = 0 ; i < 6 ; ++i )
{
numeros . push_back ( 5 0 10 i ) ;
}
c o u t << " Imp ri mir f o r a de ordem " << e n d l ;
f o r ( i n t i = 0 ; i < 6 ; ++i )
{
c o u t << numeros [ i ] << e n d l ;
}
s t d : : s o r t ( numeros . b e g i n ( ) , numeros . end ( ) ) ;
c o u t << " Imp ri mir em ordem " << e n d l ;
f o r ( i n t i = 0 ; i < 6 ; ++i )
{
c o u t << numeros [ i ] << e n d l ;
}
O algoritmo sort normalmente o algoritmo mais utilizado da STL e, portanto, merece alguma ateno especial. Internamente, o padro STL dita que
o algoritmo utilizado para ordenamento o algoritmo introsort. Basicamente,
o introsort ordena os elementos inicialmente utilizando um quicksort, e quando
o nvel de recurso atinge um determinado limite, o algoritmo passa a executar
um heapsort.
A vantagem desta abordagem que a complexidade deste algoritmo garantidamente O(n log n). Outro detalhe importante que o algoritmo utilizado
pela STL no um algoritmo de ordenamento estvel. Para um algoritmo estvel, utilize a alternativa stable sort. Abaixo, mostramos alguns algoritmos
comuns que a STL implementa, com uma breve descrio de sua utilidade:
75
8.10.1
O algoritmo sort extremamente amplo, de modo que no se limita a ordenaes crescentes e decrescentes de inteiros. Nessa seo, veremos como utilizar
funes prprias para ordenar estruturas atravs do sort. Para a demonstrao,
ser usado o exemplo 8.7, que coloca os inteiros em ordem decrescente.
8.11
A biblioteca padro do C++ tem como alicerce, em sua construo, a facilidade de extenso do seu uso. A partir disso, redundante dizer que as estruturas
criadas podem ser utilizadas no s com os tipos bsicos da linguagem, mas
tambm com classes criadas pelo programador. No exemplo 8.8, ordenaremos
nossos Livros pelo ano de publicao (o maior antes), e em caso de igualdade,
pelo ttulo do livro.
Como se pode ver, basta declarar um operador do tipo <, que determina
qual ser o critrio utilizado para definir se um objeto Livro ou no menor
do que o outro. Depois, s usar a funo sort no vetor. O C++ ordena
automaticamente o vetor utilizando o critrio definido pelo operador.
76
77
78
8.11.1
Teste de Aprendizado
1. Crie o operador < na classe Aluno, e ordene os alunos pela mdia das
notas
2. Crie uma classe Time, com nmero de vitrias, empates e derrotas, e
organize n times em uma tabela de classificao usando: Maior nmero
de pontos(vitrias*3 + empates), menos nmero de jogos, maior nmero
de vitrias
8.12
ltimas Consideraes
O exemplo que foi mostrado usa somente vector, mas este raciocnio vale
para qualquer container STL.
Prefira vectors e strings a vetores dinamicamente alocados[13]; Ao utilizar
vetores dinamicamente alocados, o programador deve se responsabilizar
inteiramente pelo gerenciamento de memria dinmica feito. Para programas simples, isto pode parecer trivial, mas para um projeto mais complexo,
gerenciamento de memria dinmica um problema bastante custoso.
O programador deve garantir, em seu cdigo, que existe exatamente uma
chamada delete para cada chamada new correspondente. Se esta chamada
delete no estiver presente, haver com certeza vazamento de memria.
Se, por outro lado, a chamada for feita duplicada, o comportamento,
de acordo com a definio C++ , novamente, indefinido. Com estes
problemas, no parece fazer sentido adotar vetores dinmicos ao invs de
vectors ou strings, que fazem todo este gerenciamento automaticamente
e de forma segura.
Garanta que operadores para continers associativos retornam falso para
valores iguais[21]; bastante comum, como vimos em um exemplo acima,
declarar operadores booleanos para poder implementar continers associativos (como sets, multisets, etc.) de classes arbitrrias. Dessa forma,
implementaremos um operator< dentro de uma classe arbitrria qualquer. Em princpio, a STL permite que o comparador utilizado em um
set no seja necessariamente o operator<, mas sim qualquer funo que
79
80