You are on page 1of 119

1 - 03/06/14

C++ COMO UMA LINGUAGEM DE PROGRAMAO ORIENTADA A OBJETOS


PROGRAMAO ORIENTADA A OBJETOS
Este tutorial se prope a ensinar programao orientada a objetos em C++. A maioria dos livros no
apresenta a linguagem nesse contexto, dando uma ateno maior para os recursos de C++ do que para a
metodologia de programao. recomendvel que o leitor tenha acesso a um desses livros visto que no
ensinaremos aqui aspectos considerados bsicos que so em geral quase todos que permitem usar C++ como
um C melhorado. Voc pode usar C++, como uma linguagem procedural com recursos avanados, mais uma
vez no isso que pretendemos ensinar neste texto.
Na prtica de programao orientada a objetos estaremos atentos em nossos programas para pontos como:
-Compatibilidade, portabilidade.
-Segurana.
-Reusabilidade.
-Facilidade de integrao.
-Facilidade de extenso.
-Eficincia.
Os tpicos seguintes nos guiaro nesses objetivos, mostrando numa curva de aprendizado suave,
como programar usando orientao a objetos em C++.
1. CLASSES E OBJETOS
Uma classe um tipo definido pelo usurio que contm o molde, a especificao para os objetos, assim
como o tipo inteiro contm o molde para as variveis declaradas como inteiros. A classe envolve, associa,
funes e dados, controlando o acesso a estes, defin-la implica em especificar os seus atributos (dados) e suas
funes membro (cdigo).
Um programa que utiliza uma interface controladora de um motor eltrico provavelmente definiria a
classe motor. Os atributos desta classe seriam: temperatura, velocidade, tenso aplicada. Estes provavelmente
seriam representados na classe por tipos como float ou long . As funes membro desta classe seriam funes
para alterar a velocidade, ler a temperatura, etc.
Um programa editor de textos definiria a classe pargrafo que teria como um de seus atributos uma
string ou um vetor de strings, e como funes membro, funes que operam sobre estas strings. Quando um
novo pargrafo digitado no texto, o editor cria a partir da classe pargrafo um objeto contendo as informaes
particulares do novo texto. sto se chama instanciao ou criao do objeto.
Classes podem ser declaradas usando a palavra reservada struct ou a palavra reservada class, nos
exemplos posteriores entraremos em mais detalhes. As classes do prximo tpico 1.2 so declaradas com
struct por razes didticas. Quando chegarmos em encapsulamento 1.3 mostraremos como declarar classes
com class e no usaremos mais struct no tutorial.
1.1. ESPECIFICANDO UMA CLASSE
Suponha um programa que controla um motor eltrico atravs de uma sada serial. A velocidade do
motor proporcional a tenso aplicada, e esta proporcional aos bits que vo para sada serial e passando por
um conversor digital analgico.
Vamos abstrair todos estes detalhes por enquanto e modelar somente a interface do motor como uma
classe, a pergunta que funes e que dados membro deve ter nossa classe, e que argumentos e valores de
retorno devem ter essas funes membro:
Representao da velocidade:
A velocidade do motor ser representada por um atributo, ou dado membro, inteiro (int). Usaremos a
faixa de bits que precisarmos, caso o valor de bits necessrio no possa ser fornecido pelo tipo , usaremos
ento o tipo long , isto depende do conversor digital analgico utilizado e do compilador.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
2 - 03/06/14
Representao da sada serial:
O motor precisa conhecer a sua sada serial, a sua ligao com o "motor do mundo real". Suponha uma
representao em hexadecimal do atributo endereo de porta serial, um possvel nome para o atributo:
enderecomotor. No se preocupe em saber como usar a representao hexadecimal.
Alterao do valor da velocidade:
nternamente o usurio da classe motor pode desejar alterar a velocidade, cria-se ento o mtodo ( em
C++ funo membro): void altera_velocidade(int novav); . O cdigo anterior corresponde ao cabealho da
funo membro, ela definida junto com a classe motor, associada a ela. O valor de retorno da funo void
(valor vazio), poderia ser criado um valor de retorno (int) que indicasse se o valor de velocidade era permitido e
foi alterado ou no era permitido e portanto no foi alterado.
No faz sentido usar, chamar, esta funo membro separada de uma varivel do tipo motor, mas ento
porque na lista de argumentos no se encontra um motor? Este pensamento reflete a maneira de associar
dados e cdigo (funes) das linguagens procedurais. Em linguagens orientadas a objetos o cdigo e os dados
so ligados de forma diferente, a prpria declarao de um tipo definido pelo usurio j engloba as declaraes
das funes inerentes a este tipo, isto ser explicado em 1.2.2.
Note que no fornecemos o cdigo da funo, isto no importante, por hora a preocupao com a
interface definida pela classe: suas funes membro e dados membro. Apenas pense que sua interface deve
ser flexvel de modo a no apresentar entraves para a criao do cdigo que seria feita numa outra etapa.
Nesta etapa teramos que imaginar que o valor numrico da velocidade deve ir para o conversor onde ir se
transformar numa diferena de potencial a ser aplicada nos terminais do motor, etc.
1.2. STRUCT EM C++
Objetos so instncias de uma classe. Quando um objeto criado ele precisa ser inicializado, ou seja
para uma nica classe : Estudante de graduao podemos ter vrios objetos num programa: Estudante de
graduao Carlos, dentificao 941218, Curso Computao; Estudante de graduao Luiza , dentificao
943249, Curso Engenharia Civil... A classe representa somente o molde para a criao dos objetos, estes sim
contm informao, veja tpico classes e objetos.
1.2.1. ATRIBUTOS OU DADOS MEMBRO.
Este exemplo declara uma struct e em seguida cria um objeto deste tipo em main alterando o
contedo desta varivel. Uma struct parecida com um record de Pascal, a nossa representa um crculo
com os atributos raio, posio x , posio y, que so coordenadas cartesianas. Note que este objeto no possui
funes membro ainda.
#include <iostream.h>
struct circulo
//struct que representa um circulo.
{
float raio;
float x;
//posicoes em coordenadas cartesianas
float y;
};
void main()
{
circulo ac;
//criacao de variavel ve!a comentarios.
ac.raio"#$.$;
//modificacao de conteudo (atri%utos) da struct
ac.x"#.$;
//colocando o circulo em uma posicao determinada
ac.y"#.$;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
3 - 03/06/14
//colocando o circulo em uma posicao determinada
cout << &'aio(&<<ac.raio <<endl;
//verificacao dos atri%utos alterados.
cout << &)(&<<ac.x << &*n&; // &*n&""endl
cout << &+(& <<ac.y<< endl;
}
Resulta! ! "#!$#a%a&
Raio:10
X:1
Y:1
C!%e't(#)!s&
struct circulo
//struct que representa um circulo.
{
float raio;
float x;
//posicoes em coordenadas cartesianas
float y;
};
Este cdigo a declarao da classe crculo, entre chaves vem os dados membro e as funes
membro que no foram apresentadas ainda.
A sintaxe para criao de objetos da classe crculo (circulo ac;) , por enquanto no difere da sintaxe
para a criao de variveis do tipo int.
O acesso aos dados membro deve ser feito usando o nome do objeto e o nome do dado membro,
separados por um ponto: ac.raio"#$.$; . Note que raio sozinho no faz sentido no programa, precisa-se
especificar de que objeto se deseja acessar o raio.
A!s *ue "#!$#a%a% e% C&
Os programadores C podem notar algo interessante: "C++ no requer a palavra struct na declarao da
varivel, ela se comporta como um tipo qualquer: int , float ...". Outros programadores que no haviam usado
struct previamente em C no se preocupem, faam apenas os exerccios deste exemplo e estaro aptos a
prosseguir.
1.2.2. M+TODOS OU FUN,ES MEMBRO.
C++ permite que se acrescente funes de manipulao da struct em sua declarao, juntando tudo
numa s entidade que uma classe. Essas funes membro podem ter sua declarao (cabealho) e
implementao (cdigo) dentro da struct ou s o cabealho (assinatura) na struct e a implementao, cdigo,
fora. Este exemplo apresenta a primeira verso, o prximo a segunda verso (implementao fora da classe).
Essas funes compem a interface da classe. A terminologia usada para design-las bastante
variada: funes membro, mtodos, etc. Quando uma funo membro chamada, se diz que o objeto est
recebendo uma mensagem (para executar uma ao).
Um programa simples para testes sobre funes membro seria o seguinte:
#include <iostream.h>
struct contador
//conta ocorrencias de al,o
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
4 - 03/06/14
int num;
//numero do contador
void incrementa(void){num"num-#;};
//incrementa contador
void comeca(void){num"$;};
//comeca a contar
};
void main()
//teste do contador
{
contador umcontador;
umcontador.comeca();
//nao esqueca dos parenteses e uma funcao mem%ro e nao atri%uto.
cout << umcontador.num << endl;
umcontador.incrementa();
cout << umcontador.num << endl;
}
Resulta! ! "#!$#a%a&
0
1
C!%e't(#)!s&
O programa define um objeto que serve como contador, a implementao representa a contagem no
atributo num que um nmero inteiro. As funes membro so simples: incrementa adiciona um ao contador
em qualquer estado e comeca inicializa a contagem em zero.
S)'ta-e&
A sintaxe para declarao de funes membro dentro de uma classe a mesma sintaxe de declarao
de funes comuns : tipoderetorno nomedafuncao(lista_de_argumentos) { /*codigo */ }. A diferena que como
a funo membro est definida na classe, ela ganho acesso direto aos dados membros, sem precisar usar o
"ponto", exemplo um_objeto.dadomembro; . Lembre-se que as chamadas de funes membro j se referem a
um objeto especfico, embora elas sejam definidas de uma forma geral para toda a classe.
A sintaxe de chamada ou acesso funes membro semelhante a sintaxe de acesso aos dados
membro com exceo dos parnteses que contm a lista de argumentos da funo, mesmo que a lista seja
vazia eles devem estar presentes: umcontador.incrementa();. Primeiro insere-se o nome do objeto e depois a
chamada da funo, estes so separados por um ponto. Cuidado para no esquecer os parnteses nas
chamadas de funes membro em programas futuros, este um erro bastante comum.
Agora o programa mais complicado, porm baseado no exemplo 1.2.1:
#include <iostream.h> //para cout
struct circulo
{
float raio;
float x;
//atri%uto coordenada cartesiana x
float y;
//atri%uto coordenada cartesiana y
void move(float dxfloat dy)
//fun/0o mem%ro ou fun/0o mem%ro move
{
x-"dx;
//equivale a x"x-dx;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
5 - 03/06/14
y-"dy;
}
void mostra(void) //fun/0o mem%ro ou fun/0o mem%ro mostra
{
cout << &'aio(&<<raio <<endl;
cout << &)(&<<x << endl;
cout << &+(& <<y<< endl;
}
};
void main()
{
circulo ac;
// 1 instancia/0o de um o%!eto circulo (criacao)
ac.x"$.$;
ac.y"$.$;
ac.raio"#$.$;
ac.mostra();
ac.move(#.$#.$);
ac.mostra();
ac.x"#$$.$;
ac.mostra();
}
Resulta! ! "#!$#a%a&
Raio:10
X:0
Y:0
Raio:10
X:1
Y:1
Raio:10
X:100
Y:1
C!%e't(#)!s&
A funo membro move altera as coordenadas do objeto. O objeto tem suas coordenadas x e y
somadas com os argumentos dessa funo membro. Note que esta funo membro representa uma maneira
mais segura, clara, elegante de alterar as coordenadas do objeto do que acess-las diretamente da seguinte
forma: ac.x-"dx;. ac.y-"dy;. Lembre-se que ac.x-"dx uma abreviao para ac.x"ac.x-dx; .
C!%! .u'/)!'a% '! /!%")la!# as /0a%aas e .u'12es %e%3#!&
possvel imaginar que as definies de funes membro ocupam um grande espao na representao interna
dos objetos, mas lembre-se que elas so todas iguais para uma classe ento basta manter para cada classe
uma tabela de funes membro que consultada no momento da chamada . Os
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
6 - 03/06/14
1.2.4. FUN,ES MEMBRO 5UE RETORNAM 6ALORES.
At agora s tnhamos visto funes membro com valor de retorno igual a void. Uma funo membro,
assim como uma funo comum, pode retornar qualquer tipo, inclusive os definidos pelo usurio. Sendo assim,
sua chamada no programa se aplica a qualquer lugar onde se espera um tipo igual ou equivalente ao tipo do
seu valor de retorno, seja numa lista de argumentos de outra funo , numa atribuio ou num operador como o
cout << variavel;
#include <iostream.h>
struct contador
//conta ocorrencias de al,o
{
int num;
//numero posicao do contador
void incrementa(void){num"num-#;};
//incrementa contador
void comeca(void){num"$;};
//comeca a contar &reset&
int retorna2num(void) {return num;};
};
void main()
//teste do contador
{
contador umcontador;
umcontador.comeca();
//nao esqueca dos parenteses e uma funcao mem%ro nao dado.
cout << umcontador.retorna2num() << endl;
umcontador.incrementa();
cout << umcontador.retorna2num() << endl;
}
Resulta! ! "#!$#a%a&
0
1
1.2.7. FUN,ES DECLARADAS E8TERNAS A CLASSE 9 FUN,ES MEMBRO C:AMAMANDO FUN,ES
MEMBRO.
Este exemplo apresenta a implementao, definio, das funes fora da declarao da struct. Alm
disso introduz uma nova funo chamada "inicializa" e funes float retorna2raio(void); e void
altera2raio(float a). nicializa coloca o ponto nas coordenadas passadas como seus argumentos.
ntroduzimos esta funo membro aqui para preparar a explicao sobre construtores dada no prximo
exemplo: 1.2.6.
C!%e't(#)!s&
Em uma declarao de uma classe normalmente se coloca a declarao das funes membro depois
da declarao dos atributos, porm podemos fazer intercalaes ou adotar qualquer ordem que nos convenha.
O programador no obrigado a implementar as funes membro dentro da declarao da classe,
basta defini-las e apresentar a implementao em separado segundo a sintaxe (compilvel) descrita a seguir:
#include <iostream.h>
struct teste
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
7 - 03/06/14
{
int x;
void altera2x(int v);
//somente definicao implementacao vem depois fora da classe
};
void teste((altera2x(int v) { x"v;}
//esta !a e a implementacao codi,o
void main()
{
teste a;
//instaciacao de um o%!eto
a.altera2x(#$);
//chamada da funcao mem%ro com valor #$ que sera impresso a se,uir
cout << a.x;
//imprimindo o dado mem%ro
}
Resulta! ! "#!$#a%a a'te#)!#&
10
Programa exemplo crculo, mais complexo baseado no exemplo de 1.2.2&
#include <iostream.h>
//para cout
struct circulo
{
float raio;
float x;
float y;
void iniciali3a(float axfloat %yfloat cr);
void altera2raio(float a);
float retorna2raio(void);
void move(float dxfloat dy);
void mostra(void);
};
void circulo((iniciali3a(float axfloat %yfloat cr)
{
x"ax;
y"%y;
raio"cr;
}
void circulo((altera2raio(float a)
{
raio"a;
}
float circulo((retorna2raio(void)
{
return raio;
}
void circulo((move(float dxfloat dy)
{
x-"dx;
y-"dy;
}
void circulo((mostra(void)
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
8 - 03/06/14
cout << &'aio(&<< retorna2raio() <<endl;
cout << &)(&<<x << endl;
cout << &+(& <<y<< endl;
}
void main()
{
circulo ac;
ac.iniciali3a($.$$.$#$.$);
ac.mostra();
ac.move(#.$#.$);
ac.mostra();
ac.x"#$$.$;
ac.altera2raio(#4.$);
ac.mostra();
}
C!%e't(#)!s&
Observe que a funo membro mostra chama a funo membro float retorna2raio(void) que
da mesma classe. Fica implcito da definio de mostra que retorna2raio() se aplica ao mesmo objeto
instanciado que recebeu a chamada de mostra, ou seja, no necessrio usar o . na chamada de
retorna2raio(). Em programas maiores, chamadas aninhadas de funes membro so bastante comuns.
P#!$#a%a1;! !#)e'taa a !3<et!s e )'te#.a/es $#(.)/as /!% ! usu(#)!&
Existem "libraries" de classes que permitem o programador C++ desenvolver aplicaes para ambientes
como o Microsoft Windowsreg. de uma maneira bastante abstrata, este um exemplo claro de reuso de cdigo,
afinal o programador no precisa saber de detalhes da interface para programar nela.
Resulta! ! "#!$#a%a&
Raio:10
X:0
Y:0
Raio:10
X:1
Y:1
Raio:12.0
X:100.0
Y:1
1.2.=. ALGO PARECIDO EM UMA LINGUAGEM PROCEDURAL
Este tpico apresenta uma comparao entre C++ e Pascal, para tal implementou-se dois programas
semelhantes. O programa C++ o programa crculo do tpico anterior: 1.2.4. O programa em Pascal vem a
seguir:
5'67'89 :omparacao;
{:6958'8:86 :69 ;9 5'67'898 :--}
<+5= :irculo"'=:6'>
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
9 - 03/06/14
x(real;
{:66'>=?8>8@ ) = +}
y(real;
r(real;
{somente dados}
=?>;
var ac(circulo;
leitura(inte,er;
5'6:=>;'= Aniciali3a(var altereme(:irculo;ax%ycr(real);
{:6B6:8 6 :A':;B6 =9 >=<='9A?8>8 56@A:86}
C=7A?
altereme.x("ax;
altereme.y("%y;
altereme.r("cr;
=?>;
5'6:=>;'= 8ltera2'aio(var altereme(:irculo;ar(real);
{8B<='8 6 '8A6 >6 :A':;B6}
C=7A?
altereme.r("ar;
=?>;
D;?:<A6? 'etorna2'aio(copieme(:irculo)(real;
C=7A?
'etorna2'aio("copieme.r;
=?>;
5'6:=>;'= 9ove(var altereme(:irculo;dxdy(real);
{96>= 8@ :66'>=?8>8@ ) = + 8:'=@:=?<8?>6 >) = >+}
C=7A?
altereme.x("altereme.x-dx;
altereme.y("altereme.y-dy;
=?>;
5'6:=>;'= 9ostra(copieme(:irculo);
{96@<'8 6 :A':;B6 ?8 <=B8}
C=7A?
Eriteln(F)(Fcopieme.xF +(Fcopieme.yF '(Fcopieme.r);
=?>;
C=7A?
{<=@<=@}
Aniciali3a(ac$.$$.$#$.$);
9ostra(ac);
9ove(ac#.$#.$);
9ostra(ac);
ac.x("#$$.$;
8ltera2'aio(ac#4.$);
9ostra(ac);
read(leitura);
=?>.
Resulta! ! "#!$#a%a&
X: 0.0000000000E+00 Y: 0.0000000000E+00 R: 1.0000000000E+01
X: 1.0000000000E+00 Y: 1.0000000000E+00 R: 1.0000000000E+01
X: 1.0000000000E+02 Y: 1.0000000000E+00 R: 1.2000000000E+01
C!%e't(#)!s&
C++&
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
10 - 03/06/14
As classes em C++ englobam os dados membros e as funes membros. Para executar uma ao
sobre o objeto ou relativa a este basta chamar uma funo membro para este: ac.mostra();
A funo membro no precisa de muitos argumentos, porque prpria da classe e portanto ganha
acesso aos dados membro do objeto para ao qual ela foi associada:
float circulo((retorna2raio(void)
{ return raio; //tenho acesso direto a raio. }
Pas/al&
Em Pascal os procedimentos e os dados so criados de forma separada, mesmo que s tenham
sentido juntos.
A juno entre os dados e procedimentos se d atravs de passagem de parmetros. No caso de uma
linguagem procedural como Pascal, o que normalmente feito se assemelha ao cdigo seguinte:
9ove(ac#.$#.$); . Ac nesse caso um "record", mas sem funes membro, algo semelhante ao
struct de C (no C++). 9ove acessa os dados do "record" alterando os campos. O parmetro passado
por referncia e o procedimento definido a parte do registro, embora s sirva para aceitar argumentos do tipo
:irculo e mover suas coordenadas.
Se$u#a'1a&
Em ambos programas (Pascal, C++) o programador pode acessar diretamente os dados do tipo definido
pelo usurio: ac.x&=100.0; (Pascal) ou ac.x=100.0; (C++).
Veremos em 1.3 ENCAPSULAMENTO maneiras de proibir em C++ este tipo de acesso direto ao dado
membro, deixando este ser modificado somente pelas funes membro. sto nos garante maior segurana e
liberdade pois podemos permitir ou no o acesso para cada dado membro de acordo com nossa vontade.
E.)/)>'/)a&
Algum pode argumentar que programas que usam bastante chamadas de funes podem se tornar
pouco eficientes e que poderia ser melhor acessar diretamente os dados de um tipo definido pelo usurio ao
envs de passar por todo o trabalho de cpia de argumentos, insero da funo no pilha, etc.
Em verdade no se perde muito em eficincia, e alm disso muitas vezes no se deseja permitir
sempre o acesso direto aos dados de um tipo definido pelo usurio por razes de segurana. Nesse sentido C+
+ oferece um recurso que permite ganhos em segurana sem perder muito em eficincia, veja: 1.5.2.
1.2.?. CONSTRUTORES
Construtores so funes membro especiais chamadas pelo sistema no momento da criao de um
objeto. Elas no possuem valor de retorno, porque voc no pode chamar um construtor para um objeto.
Contrutores representam uma oportunidade de inicializar de forma organizada os objetos, imagine se voc
esquece de inicializar corretamente ou o faz duas vezes, etc.
Um construtor tem sempre o mesmo nome da classe e no pode ser chamado pelo usurio desta. Para
uma classe string o construtor teria a forma strin,(char1 a); com o argumento char1 especificado pelo
programador. Ele seria chamado automaticamente no momento da criao, declarao de uma string:
strin, a(&<exto&);
//alocacao estatica implica na chamada do construtor
a.mostra();
//chamada de metodos estatica.
Existem variaes sobre o tema que veremos mais tarde: Sobrecarga de construtor, "copy constructor",
como conseguir construtores virtuais (avanado, no apresentado neste texto) , construtor de corpo vazio.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
11 - 03/06/14
O exemplo a seguir simples, semelhante aos anteriores, preste ateno na funo membro com o
mesmo nome que a classe (struct) , este o construtor:
#include <iostream.h>
struct ponto
{
float x;
float y;
pu%lic(
ponto(float afloat %);
//esse e o contrutor note a ausencia do valor de retorno
void mostra(void);
void move(float dxfloat dy);
};
ponto((ponto(float afloat %)
//construtor tem sempre o nome da classe.
{
x"a;
//inciali3ando atri%utos da classe
y"%;
//colocando a casa em ordem
}
void ponto((mostra(void)
{cout << &)(& << x << & +(& << y << endl;}
void ponto((move(float dxfloat dy)
{
x-"dx;
y-"dy;
}
void main()
{
ponto ap($.$$.$);
ap.mostra();
ap.move(#.$#.$);
ap.mostra();
}
Resulta! ! "#!$#a%a&
X:0 , Y:0
X:1 , Y:1
C!%e't(#)!s&
Deixaremos para nos aprofundarmos em alocao dinmica e construtores em 1.5.3. Por hora voc
pode se ater ao uso esttico de objetos.
Note que com a definio do construtor, voc obrigado a passar os argumentos deste no momento da
criao do objeto. Se voc precisa ter a opo de no passar esses valores, as possveis solues sero dadas
em 3.
1.2.@. CONSTRUTORES E AGREGAO
O programa exemplo deste tpico cria uma classe reta com dois dados membro da classe ponto este
exemplo o resultado do exerccio anterior, com um recurso a mais de C++. C++ permite que no construtor da
classe reta, voc chame os construtores dos atributos da classe ponto se voc no o fizer o compilador
acusar um erro, pois os atributos ponto possuem construtores e eles precisam ser chamados para que a
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
12 - 03/06/14
inicializao se complete de modo correto para o conjunto. Observe o cdigo do construtor da classe reta
usado no exemplo:
reta(float x#float y#float x4float y4)(p#(x#y#)p4(x4y4)
{
//nada mais a fa3er os construtores de p# e p4 !a foram chamados
}
p1(x1,y1) e p2(x2,y2) so as chamadas dos construtores da classe ponto, elas devem ficar fora do corpo {} do
construtor, nesta lista separada por vrgulas voc deve inicializar todos os atributos. Os tipos bsicos como int,
float, etc "!e% ser inicializados nessa lista.
Por exemplo se a classe reta tivesse um atributo inteiro de nome identificao, a lista poderia ser da
seguinte forma:
reta(float x#float y#float x4float y4)(p#(x#y#)p4(x4y4)identificacao(#$)
{
//nada mais a fa3er os construtores de p# e p4 !a foram chamados
}
seria como se identificao tivesse um construtor que tem como argumento seu valor.
ou
reta(float x#float y#float x4float y4)(p#(x#y#)p4(x4y4)
{
identificacao"#$;
//tam%em pode porque tipos %Gsicos (int) em :-- n0o s0o o%!etos
// portanto nao tem construtores
}
Uma outra alternativa seria usar alocao dinmica para os atributos pontos que passariam a ser agora
ponteiros para pontos, deixaremos para discutir este tpico mais tarde em 1.5.3, mas saiba que nesse caso o
construtor da classe reta no precisaria criar os pontos.
Vamos ao exemplo, que novamente semelhante aos anteriores, para que o leitor preste ateno
somente nas mudanas, que so os conceitos novos, sem ter que se esforar muito para entender o programa:
#include <iostream.h>
struct ponto
{
float x;
float y;
//coordenadas
ponto(float afloat %)
{
x"a;
y"%;
}
//construtor
void move(float dxfloat dy)
{ x-"dx; y-"dy; }
//funcao mem%ro comum
void iniciali3a(float afloat %)
{ x"a; y"%; }
void mostra(void)
{cout << &)(& << x << & +(& << y << endl;}
};
struct reta
{
ponto p#;
ponto p4;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
13 - 03/06/14
reta(float x#float y#float x4float y4)(p#(x#y#)p4(x4y4)
{
//nada mais a fa3er os contrutores de p# e p4 !a foram chamados
}
void mostra(void);
};
void reta((mostra(void)
{
p#.mostra();
p4.mostra();
}
void main()
{
reta r#(#.$#.$#$.$#$.$); //instanciacao da reta r#
r#.mostra();
}
Resulta! ! "#!$#a%a&
X:1 , Y:1
X:10 , Y
1.2.A. DESTRUTORES.
Anlogos aos construtores, os destrutores tambm so funes membro chamadas pelo sistema, s
que elas so chamadas quando o objeto sai de escopo ou em alocao dinmica, tem seu ponteiro desalocado,
ambas (construtor e destrutor) no possuem valor de retorno.
Voc no pode chamar o destrutor, o que voc faz fornecer ao compilador o cdigo a ser executado
quando o objeto destrudo, apagado. Ao contrrio dos construtores, os destrutores no tem argumentos.
Os destrutores so muito teis para "limpar a casa" quando um objeto deixa de ser usado, no escopo
de uma funo em que foi criado, ou mesmo num bloco de cdigo. Quando usados em conjunto com alocao
dinmica eles fornecem uma maneira muito prtica e segura de organizar o uso do "heap". A importncia dos
destrutores em C++ aumentada pela ausncia de "garbage collection" ou coleta automtica de lixo.
A sintaxe do destrutor simples, ele tambm tem o mesmo nome da classe s que precedido por H ,
ele no possui valor de retorno e seu argumento void sempre:
Hnomedaclasse(void) { /1 :odi,o do destrutor 1/ }
O exemplo a seguir simples, porque melhorias e extenses sobre o tema destrutores sero
apresentadas ao longo do texto:
//destrutor de uma classe
#include <iostream.h>
struct contador{
int num;
contador(int n) {num"n;}
//construtor
void incrementa(void) {num-"#;}
//funcao mem%ro comum pode ser chamada pelo usuario
Hcontador(void)
{cout << &:ontador destruido valor(& << num <<endl;}
//destrutor
};
void main()
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
14 - 03/06/14
contador minutos($);
minutos.incrementa();
cout << minutos.num << endl;
{
//inicio de novo %loco de codi,o
contador se,undos(#$);
se,undos.incrementa();
cout << se,undos.num <<endl;
//fim de novo %loco de codi,o
}
minutos.incrementa();
}
Resulta! ! "#!$#a%a&
1
11
Contador destruido, valor:11
Contador destruido, valor:2
C!%e't(#)!s&
No escopo de main criado o contador minutos com valor inicial==0.
Minutos incrementado, agora minutos.num==1.
O valor de num em minutos impresso na tela.
Um novo bloco de cdigo criado.
Segundos criado, instanciado como uma varivel deste bloco de cdigo, o valor inicial de se,undos 10,
para no confundir com o objeto j criado.
Segundos incrementado atingindo o valor 11.
O valor de segundos impresso na tela.
Finalizamos o bloco de cdigo em que foi criado segundos, agora ele sai de escopo, apagado, mas antes o
sistema chama automaticamente o destrutor.
Voltando ao bloco de cdigo de main(), minutos novamente incrementado.
Finalizamos main(), agora, todas as variveis declaradas em main()saem de escopo, mas antes o sistema
chama os destrutores daquelas que os possuem.
1.4. ENCAPSULAMENTO COM BCLASSB
Encapsulamento, "data hiding". Neste tpico vamos falar das maneiras de restringir o acesso as declaraes de
uma classe, isto feito em C++ atravs do uso das palavras reservadas public, private e protected. Friends
tambm restringe o acesso a uma classe e apresentado em 4.1.
Consideraes sobre C++:CONSIDERAES C++:1.5, apresenta tambm um recurso de C++ para declarar
objetos constantes e proteger argumentos de chamadas de mtodos que possam modific-los, usando const
1.5.1.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
15 - 03/06/14
No mais apresentaremos exemplos de classes declaradas com struct. Tudo que foi feito at agora pode ser
feito com a palavra class ao envs de struct, incluindo pequenas modificaes. Mas porque usar s class nesse
tutorial? A diferena que os dados membro e funes membro de uma struct so acessveis por "default" fora
da struct enquanto que os atributos e mtodos de uma classe no so, acessveis fora dela (main) por "default".
Voc nem deve ter se preocupado com isso porque usando struct da forma como usvamos, tudo ficava
acessvel.
Ento como controlar o acesso de atributos e mtodos em uma classe? Simples, atravs das palavras
reservadas private pu%lic e protected.
Protected ser explicada em 2.1 pois est relacionada com herana, por hora vamos focalizar nossa ateno
em private e public que qualificam os dados membro e funes membro de uma classe quanto ao tipo de
acesso (onde eles so visveis) . Public, private e protected podem ser vistos como qualificadores, "specifiers".
Para facilitar a explicao suponha a seguintes declaraes e*u)Cale'tes de classes:
1)
class ponto {
float x;
//dados mem%ro
float y;
public:
//qualificador
void iniciali3a(float a float %) {x"a; y"%;};
//funcao mem%ro
void move(float dx float dy) {x-"dx; y-"dy; };
};
a declarao 1 equivale totalmente :
2)
class ponto {
private:
float x;
float y;
public:
//qualificador
void iniciali3a(float a float %) {x"a;
y"%;};
void move(float dx float dy) {x-"dx;
y-"dy; };
};
que equivale totalmente :
3)
struct ponto {
private:
//se eu nao colocar private eu perco o encapsulamento em struct.
float x;
float y;
public:
//qualificador
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
16 - 03/06/14
void iniciali3a(float a float %) {x"a;
y"%;};
void move(float dx float dy) {x-"dx; y-"dy;
};
};
Fica fcil entender essas declaraes se voc pensar no seguinte: esses qualificadores se aplicam aos
mtodos e atributos que vem aps eles, se houver ento um outro qualificador, teremos agora um novo tipo de
acesso para os mtodos declarados posteriormente.
Mas ento porque as declaraes so equivalentes? porque o qualificador private "default" para class, ou
seja se voc no especificar nada , at que se insira um qualificador, tudo o que for declarado numa classe
private. J em struct, o que default o qualificador public.
Agora vamos entender o que private e o que public:
Vamos supor que voc instanciou (criou) um objeto do tipo ponto em seu programa:
ponto meu; //instanciacao
Segundo o uso de qualquer uma das definies da classe ponto dadas acima voc ';! pode escrever no seu
programa:
meu.x"I.$; //erro !
,como fazamos nos exemplos de 1.2 , a no ser que x fosse declarado depois de public na definio da classe
o que no ocorre aqui. Mas voc pode escrever x=5.0; na implementao (dentro) de um mtodo porque
enquanto no for feito uso de herana, porque uma funo membro tem acesso a tudo que de sua classe,
veja o programa seguinte.
Voc pode escrever: meu.move(5.0,5.0); ,porque sua declarao (move) est na parte public da classe. Aqui o
leitor j percebe que podem existir funes membro private tambm, e estas s so acessveis dentro do cdigo
da classe (outras funes membro).
Visibilidade das declaraes de uma classe, fora dela e de sua hierarquia. Veja que s a parte public visvel
neste caso:
Visibilidade das declaraes de uma classe, dentro dela mesma:
1.4.1. ATRIBUTOS PRIVATE, FUN,ES MEMBRO PUBLIC
8plicando encapsulamento a classe ponto definida anteriormente.
#include <iostream.h>
class ponto
{
private(
//nao precisaria por private em class e default
float x;
//sao ocultos por default
float y;
//sao ocultos por default
pu%lic(
//daqui em diante tudo e acessivel.
void iniciali3a(float afloat %)
{ x"a; y"%; }
//as funcoes de uma classe podem acessar os atri%utos private dela mesma.
void mostra(void)
{cout << &)(& << x << & +(& << y << endl;}
};
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
17 - 03/06/14
void main()
{
ponto ap; //instanciacao
ap.iniciali3a($.$$.$); //metodos pu%lic
ap.mostra(); //metodos pu%lic
}
Resulta! ! "#!$#a%a&
X:0 , Y:0
C!%e't(#)!s&
Este programa no deixa voc tirar o ponto de (0,0) a no ser que seja chamada inicializa novamente. Fica
claro que agora, encapsulando x e y precisamos de mais mtodos para que a classe no tenha sua
funcionalidade limitada.
Novamente: escrever ap.x=10; em main um erro! Pois x est qualificada como private. Leia os exerccios.
1.4.2. UM DADO MEMBRO + PUBLIC
Este programa uma variante do anterior, a nica diferena que Y colocado na parte public da definio da
classe e acessado diretamente. Alm disso fornecemos aqui a funo membro move, para que voc possa
tirar o ponto do lugar.
#include <iostream.h>
class ponto
{
float x;
//sao ocultos por default
pu%lic(
//daqui em diante tudo e acessivel.
ponto(float afloat %);
//construtor tam%em pode ser inline ou nao
void mostra(void);
void move(float dxfloat dy);
float y;
//1 + nao eF mais ocultado
};
ponto((ponto(float afloat %)
{
x"a;
y"%;
}
void ponto((mostra(void)
{cout << &)(& << x << & +(& << y << endl;}
void ponto((move(float dxfloat dy)
{
x-"dx;
y-"dy;
}
void main()
{
ponto ap($.$$.$);
ap.mostra();
ap.move(#.$#.$);
ap.mostra();
ap.y"#$$.$;
ap.mostra();
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
18 - 03/06/14
}
Resulta! ! "#!$#a%a&
X:0 , Y:0
X:1 , Y:1
X:1 , Y:100
C!%e't(#)!s&
Observe que agora nada impede que voc acesse diretamente y: ap.y=100.0, porm ap.x=10.00 um erro.
Observe em que parte (rea) da classe cada um desses dados membro foi declarado.
1.4.4. COMPILANDO UM PROGRAMA COM 6DRIOS AR5UI6OS.
Compilando um programa dividido em vrios arquivos. Normalmente os programas C++ so divididos em
arquivos para melhor organizao e encapsulamento, porm nada impede que o programador faa seu
programa em um s arquivo. O programa exemplo da classe ponto de 1.3.1 poderia ser dividido da seguinte
forma:
//8rquivo # ponto.h definicao para a classe ponto.
class ponto
{
pu%lic(
//daqui em diante tudo e acessivel.
void iniciali3a(float afloat %);
void mostra(void);
private(
float x;
//sao ocultos por default
float y;
//sao ocultos por default
};
//8rquivo 4 ponto.cpp implementacao para a classe ponto.
#include <iostream.h>
#include &ponto.h&
void ponto((iniciali3a(float afloat %)
{ x"a; y"%; }
//as funcoes de uma classe podem acessar os atri%utos private dela mesma.
void ponto((mostra(void)
{cout << &)(& << x << & +(& << y << endl;}
//8rquivo J . 5ro,rama principal( princ.cpp
#include &ponto.h&
void main()
{
ponto ap;
//instanciacao
ap.iniciali3a($.$$.$);
//metodos pu%lic
ap.mostra();
//metodos pu%lic
}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
19 - 03/06/14
Os arquivos com extenso .h indicam header files. costume deixar nesses arquivos somente a interface das
classes e funes para que o usurio possa olh-lo, como numa "library". Note que a parte public da classe foi
colocada antes da parte private, isto porque normalmente essa parte da definio da classe que interessa
para o leitor.
No nosso caso o nico arquivo `header' (.h) que temos o "ponto.h" que define a classe ponto. Caso as
dimenses de seu programa permitam, opte por separar cada classe em um `header file', ou cada grupo de
entidades (funes, classes) relacionadas.
O arquivo 2 "ponto.cpp" um arquivo de implementao. Ele tem o mesmo nome do arquivo "ponto.h" , embora
isto no seja obrigatrio. mais organizado ir formando pares de arquivos "header / implementation".
Este arquivo fornece o cdigo para as operaes da classe ponto, da a declarao: #include "ponto.h". As
aspas indicam que se trata de um arquivo criado pelo usurio e no uma "library" da linguagem como
<iostream.h>, portanto o diretrio onde se deve encontrar o arquivo diferente do diretrio onde se encontra
<iostream.h>.
O arquivo 3 "princ.cpp" o arquivo principal do programa, no costume relacionar seu nome com nomes de
outros arquivos como no caso do arquivo 2 e o arquivo 1.
Observe que o arquivo 3 tambm declara #include "ponto.h", isto porque ele faz uso das dos tipos definidos em
"ponto.h" , porm "princ.cpp" no precisa declarar #include <iostream.h> porque este no usa diretamente as
definies de iostream em nenhum momento, caso "princ.cpp" o fizesse, o include <iostream> seria necessrio.
O leitor encontrar em alguns dos exemplos seguintes as diretivas de compilao. Quando da elaborao de
uma library para ser usada por outros programadores, no se esquea de us-las:
#ifndef 9BA@<K2K
#define 9BA@<K2K
//:odi,o
#endif
#ifndef 9BA@<K2K
#define 9BA@<K2K
//defina aqui seu header file.
//perce%a que &?omearq.h& e escrito na diretiva como ?69=8'L2K
#endif
Essas diretivas servem para evitar que um header file seja includo mais de uma vez no mesmo projeto. O seu
uso se d da seguinte forma:
Saber compilar programas divididos em vrios arquivos muito importante. sto requer um certo esforo por
parte do programador, porque os mtodos podem variar de plataforma para plataforma. Pergunte para um
programador experiente de seu grupo.
Se o seu compilador de linha de comando, provavelmente voc poder compilar programas divididos em
vrios arquivos usando makefiles. J se seu compilador opera num ambiente grfico, esta tarefa pode envolver
a criao de um projeto.
1.7. TIPO ABSTRATO DE DADOS
Tipo abstrato de dados, TAD, se preocupa em proporcionar uma abstrao sobre uma estrutura de dados em
termos de uma interface bem definida. So importantes os aspectos de encapsulamento, que mantm a
integridade do objeto evitando acessos inesperados, e o fato de o cdigo estar armazenado em um s lugar o
que cria um programa modificvel, legvel, coeso.
Uma classe implementa um tipo abstrato de dados.
So exemplos de tipos abstratos de dados:
1) Uma rvore binria com as operaes usuais de insero, remoo, busca ...
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
20 - 03/06/14
2)Uma representao para nmeros racionais (numerador, denominador) que possua as operaes aritmticas
bsicas e outras de converso de tipos.
3)Uma representao para ngulos na forma (Graus, Minutos, Segundos). Tambm com as operaes
relacionadas, bem como as operaes para converter para radianos, entre outras.
Tipo abstrato de dados um conceito muito importante em programao orientada a objeto e por este motivo
logo apresentado neste tutorial. Os exemplos seguintes so simples devido ao fato de no podermos usar todos
os recursos C++ por razes didticas. Devido a esta importncia, a medida em que formos introduzindo novos
recursos exemplificaremos tambm com aplicaes na implementao tipos abstratos de dados.
1.7.1. TAD FRAO
Tipo abstrato de dados frao. Baseado no conceito de nmero racional do campo da matemtica. Algumas
operaes no foram implementadas por serem semelhantes s existentes. O exemplo mais completo se
encontra em 4.1.2. Por hora no podemos fazer uso de recursos avanados como sobrecarga de operador e
templates.
Resumo das operaes matemticas envolvidas:
Simplificao de frao: (a/b)=( (a/mdc(a,b)) / (b/mdc(a,b)) )
Onde mdc(a,b) retorna o mximo divisor comum de ab.
Soma de frao: (a/b)+(c/d)=( (a.d+c.b) / b.d ) simplificada.
Multiplicao de frao: (a/b) * (c/d)= ( (a*c) / (b*d) ) simplificada.
gualdade: (a/b)== (c/d) se a*d == b*c.
No igualdade: (a/b) != (c/d) se a*d b*c
Maior ou igual que: (a/b)(c/d) se a*d b*c
TE")/!s a3!#a!s&
Construtores em geral, destrutores, tipo lon, criando mtodos de converso de tipos, mtodos chamando
mtodos do mesmo objeto, operador % que retorna o resto da diviso de dois inteiros.
//header file para o <8> fracao.
//Dile easyfra.h
lon, mdc(lon, nlon, d);
//maximo divisor comum metodo de =uclides.
class fracao {
private(
lon, num;
//numerador
lon, den;
//denominador
pu%lic(
fracao(lon, tlon, m);
//construtor comum
void simplifica(void);
//divisao pelo mdc
Hfracao() { /1 nao fa3 nada1/ }
//?ao e preciso fa3er nada.
//operacoes matematicas %asicas
fracao soma (fracao !);
fracao multiplicacao(fracao !);
//operacoes de comparacao
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
21 - 03/06/14
int i,ual(fracao t);
int diferente(fracao t);
int maioroui,ual(fracao t);
//operacoes de input output
void mostra(void);
//exi%e fracao no video
void cria(void);
//per,unta ao usuario o valor da fracao
//operacoes de conversao de tipos
dou%le converted%l(void);
//converte para dou%le
lon, converteln,(void);
//converte para lon,
};
//implementacao para a classe fracao.
#include <iostream.h>
#include &easyfra.h&
lon, mdc(lon, nlon, d)
//maximo divisor comum
//metodo de =uclides -M J$$ anos 8:.
{
if (n<$) n"Mn;
if (d<$) d"Md;
Ehile (d."$) {
lon, r"n N d;
//N"96>"'esto da divisao inteira.
n"d;
d"r;
}
return n;
}
void fracao((simplifica(void)
{
lon, commd;
commd"mdc(numden);
//divisor comum
num"num/commd;
den"den/commd;
if (den<$) { den"Mden; num"Mnum;};
//move sinal para cima
}
fracao((fracao(lon, tlon, m)
{
num"(t);
den"(m);
simplifica(); //chamada para o mesmo o%!eto.
}
fracao fracao((soma(fracao !)
{
fracao ,((num1!.den)-(!.num1den)den1!.den);
return ,;
}
fracao fracao((multiplicacao(fracao !)
{
fracao ,(num1!.numden1!.den);
return ,;
}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
22 - 03/06/14
int fracao((i,ual(fracao t)
{
return ((num1t.den)""(den1t.num));
//funciona %em mesmo para nao simplificada
}
int fracao((diferente(fracao t)
{
return ((num1t.den)."(den1t.num));
}
int fracao((maioroui,ual(fracao t)
{
return ((num1t.den)>"(t.num1den));
}
void fracao((mostra(void)
{
cout << &(& << num << &/& << den << &)&;
}
void fracao((cria(void)
{
cout << &?umerador(&;
cin >> num;
cout << &>enominador(&;
cin >> den;
simplifica();
}
dou%le fracao((converted%l(void)
{
dou%le d%l;
d%l"(dou%le(num)/dou%le(den));
return d%l;
}
//conversao para lon,
lon, fracao((converteln,(void)
{
lon, ln,;
ln,"num/den;
return ln,;
}
#include <iostream.h>
#include &easyfra.h&
//nossa definicao da classe
#include <stdio.h>
main()
{
fracao a($#)%($#);
cout << & =ntre com fracao a( &;
a.cria();
a.mostra();
cout << & =ntre com fracao %( &;
%.cria();
%.mostra();
fracao c(a.soma(%));
//c(a-%)
cout << endl << &c de a-%(&;
c.mostra();
cout << endl << &a1%&;
c"a.multiplicacao(%);
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
23 - 03/06/14
c.mostra();
cout << endl << &a-%&;
c"a.soma(%);
c.mostra();
cout << endl << &a>"%&;
cout << a.maioroui,ual(%);
cout << endl << &a""%&;
cout << a.i,ual(%);
cout << endl << &a."%&;
cout << a.diferente(%);
cout << endl << &lon,(a) &;
cout << a.converteln,();
cout << endl << &dou%le(a) &;
cout << a.converted%l();
return $;
}
C!%e't(#)!s&
Observe o seguinte cdigo usado no programa: fracao c(a.soma(b));. O resultado de a.soma(b) uma frao,
mas no criamos um construtor que recebe uma frao como argumento, como isso foi possvel no programa?
Simples, a linguagem oferece para as classes que voc cria a cpia bit a bit. Cuidado com o uso dessa cpia
em conjunto com alocao dinmica, objetos podero ter cpias iguais de ponteiros, ou seja compartilhar uso
de posies na memria. De qualquer forma, em 0 explicaremos como redefinir esta cpia de modo a evitar
situaes indesejveis como a cpia de ponteiros e em 1.5.3 explicaremos melhor os perigos de usar este tipo
de cpia em conjunto com alocao dinmica.
Resulta! ! "#!$#a%a&
Entre com fracao a: Numerador:4
Denominador:2
(2/1) Entre com fracao b: Numerador:5
Denominador:3
(5/3)
c de a+b:(11/3)
a*b(10/3)
a+b(11/3)
a>=b1
a==b0
a!=b1
long(a) 2
double(a) 2
1.=. CONSIDERA,ES C++&
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
24 - 03/06/14
Neste tpico iremos explicar recursos mais particulares de C++, porm no menos importantes para a
programao orientada a objetos na linguagem. Alguns recursos como const que est relacionado com
encapsulamento podero ser retirados deste tpico em novas verses do tutorial.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
25 - 03/06/14
1.=.1. CONST
Este exemplo mostra o uso de funes const e sua importncia para o encapsulamento. Const pode qualificar
um parmetro de funo (assegurando que este no ser modificado), uma funo membro (assegurando que
esta no modifica os dados membro de sua classe), ou uma instncia de objeto/tipo (assegurando que este no
ser modificado.)
Os modos de qualificao descritos atuam em conjunto, para assegurar que um objeto const no ser
modificado, C++ s permite que sejam chamados para este objeto funes membro qualificadas como const.
:onst tambm um qualificador, "specifier".
#include <iostream.h>
#include <math.h>
//dou%le sqrt(dou%le x); de math.h retorna rai3 quadrada do numero
//dou%le poE(dou%le x dou%le y); de math.h calcula x a potencia de y
const float O='6"$.$;
class ponto
{
private(
float x;
//sao ocultos por default nao precisaria private mas eF %om
float y;
//sao ocultos por default
pu%lic(
//daqui em diante tudo e acessivel em main.
ponto(float afloat %)
{ x"a; y"%; }
void mostra(void) const
{cout << &)(& << x << & +(& << y << endl;}
float distancia(const ponto hi) const
{
return
float(
sqrt(
(
poE(dou%le(hi.xMx)4.$)
-
poE(dou%le(hi.yMy)4.$)
)
)
);
//teorema de 5ita,oras
}
};
void main()
{
ponto ap(J.$P.$);
//instanciacao
ap.mostra();
//funcoes mem%ro pu%lic
const ponto ori,em(O='6O='6);
//defino o%!eto constante
ori,em.mostra();
cout << &>istancia da ori,em(& << ori,em.distancia(ap);
}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
26 - 03/06/14
Resulta! ! "#!$#a%a&
X:3 , Y:4
X:0 , Y:0
Distancia da origem:5
C!%e't(#)!s&
Const qualificando instncias de objetos/tipos:
const ponto origem(ZERO,ZERO);
const float ZERO=0.0;
Const qualificando funes:
float distancia(const ponto hi) /!'st;
Const qualificando argumentos:
float distancia(/!'st ponto hi) const;
1.=.2. FUN,ES INLINE
Re*u)s)t!s:
Saber como um programa se comporta na memria, em termos de chamadas de funo e gerenciamento da
pilha, "stack".
O que so funes inline: magine uma chamada de uma funo membro void altera_raio(float a) da classe
circulo j apresentada, ac.altera_raio(a). Esta chamada envolve a passagem de parmetros, insero da funo
na pilha (stack), retorno de um valor (void), tudo isso representa uma diminuio da velocidade do programa
com relao a um simples: ac.raio=a; que nesse caso funcionaria muito bem.
Ocorre que ns desejamos usar chamadas de mtodos, vimos inclusive meios de esconder, encapsular o
atributo raio para que a nica alternativa para alterar seu valor seja atravs da chamada de altera_raio(a).
Porque programar desta forma? Porque mais seguro, mais prximo dos princpios de orientao a objetos.
Em verdade POO se caracteriza por muitas chamadas de mtodos e uso do "heap", rea de memria usada
pela alocao dinmica.
O que as funes declaradas como inline fazem traduzir a chamada do mtodo em tempo de compilao em
um equivalente ac.raio=17.0. evitando todo o contratempo descrito. Essa traduo do mtodo colocada na
sequncia de cdigo do programa, voc pode ter vrios trechos que chamariam funes, desviariam o fluxo do
programa at o retorno desta, convertidos em instrues simples. Como desvantagem temos o aumento do
tamanho do programa, visto que passaro a existir vrias cpias diferentes da funo no programa (uma para
cada argumento) ao envs de um s prottipo de funo que era colocado na pilha no momento da chamada e
ento tinha os argumentos substitudos.
Nos programa anteriores sobre a classe crculo, se a funo membro mostra fosse inline haveria uma
converso da chamada interna (dentro de mostra) de retorna_raio()em simplesmente ac.raio. Pode haver
converso de vrias funes inline aninhadas, estas converses so seguras, porque so feitas pelo
compilador.
Normalmente vantajoso usar inline para funes pequenas que no aumentem muito o tamanho do programa
ou funes onde velocidade crucial. Aqui vale a conhecida regra 80:20, oitenta porcento do tempo do
programa gasto em vinte por cento dos mtodos. Porm o programador no precisa se preocupar muito com
funes inline na fase de desenvolvimento, este um recurso C++ para aumento de eficincia que pode muito
bem ser deixado para o final do projeto. Saiba porm que as diferenas de tempo decorrentes de seu uso so
sensveis.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
27 - 03/06/14
Este exemplo explora as possibilidades que temos para declarar funes membro e como declar-las para que
sejam do tipo inline(
#include <iostream.h>
struct ponto
{
float x;
float y;
void iniciali3a(float afloat %)
{ x"a; y"%; } //8pesar de nao especificado compilador tenta
//expandir chamada da funcao como inline porque esta dentro da definicao da classe.
void mostra(void); //com certe3a nao eF inline externa a classe e sem
qualificador.
inline void move(float dxfloat dy); //eF inline prototipo definicao
};
void ponto((mostra(void)
{cout << &)(& << x << & +(& << y << endl;}
inline void ponto((move(float dxfloat dy) //implementacao codi,o
{
x-"dx;
y-"dy;
}
void main()
{
ponto ap;
ap.iniciali3a($.$$.$);
ap.mostra();
ap.move(#.$#.$);
ap.mostra();
ap.x"#$$.$;
ap.mostra();
}
C!%e't(#)!s:
O compilador tenta converter a funo inicializa em inline, embora no esteja especificado com a palavra
reservada inline que isto para ser feito. Esta uma regra, sempre que a funo estiver definida na prpria
classe (struct{}) o compilador tentar convert-la em inline. Foi dito que o compilador tenta porque isto pode
variar de compilador para compilador, se ele no consegue converter em inline , devido a complexidade da
funo, voc normalmente avisado, tendo que trocar o lugar da definio da funo membro.
Note que se a funo membro implementada fora da classe, tanto o prottipo da funo membro, quanto a
implementao devem vir especificados com inline para que a converso ocorra.
Resulta! ! "#!$#a%a&
X:0 , Y:0
X:1 , Y:1
X:100 , Y:1
1.=.4. ALOCAO DINFMICA COM NEG E DELETE.
Neste tpico sero apresentados os recursos de C++ para alocao dinmica de variveis de tipos simples e
objetos, ou seja, estudaremos a alocao de estruturas em tempo de execuo.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
28 - 03/06/14
1.=.4.1. PONTEIROS9 BPOINTERSB
Este exemplo mostra como trabalhar com ponteiros para variveis de tipos pr-definidos (no definidos pelo
usurio) usando new e delete.
O programa a seguir cria um ponteiro para uma varivel inteira, aloca memria para esta varivel e imprime seu
valor.
#include <iostream.h>
void main()
{
int1 a;
//declara um ponteiro para endereco de variavel inteira
a"neE int(J);
//aloca memoria para o apontado por a ,ravando neste o valor J
cout << (1a) << endl ;
//imprime o valor do apontado por a
delete a;
//desaloca memoria
}
Resulta! ! "#!$#a%a&
3
Diagrama das variveis na memria:
C!%e't(#)!s&
Se a fosse uma struct ou class e tivesse um dado membro chamado dd, poderamos obter o valor de dd
atravs de (1a).dd que pode ser todo abreviado em aM>dd onde M> uma seta, ou flecha que voc pode ler
como "o apontado" novamente. Os parnteses em (1a).dd so necessrios devido a precedncia do
operador . com relao ao 1. Esta sintaxe abreviada ser bastante usada quando alocarmos dinamicamente
objetos.
O3se#Ca1;!&
int1 a;
a"neE int(J);
pode ser a%reviado por(
int1 a"neE int(J);
1.=.4.2. 6ETORES CRIADOS ESTATICAMENTE
O exemplo a seguir aloca estaticamente, em tempo de compilao, um vetor de inteiros com trs posies. Em
seguida, gravamos as trs posies e as mostramos na tela:
#include <iostream.h>
void main()
{
int aQJR;
//aloca o vetor de tamanho J estaticamente
aQ$R"#;
//atri%ui a posicao indice $ do vetor
aQ#R"4;
//atri%ui 4 a posicao indice # do vetor
aQ4R"J;
//atri%ui J a posicao indice 4 do vetor
cout << aQ$R << & & << aQ#R << & & << aQ4R << endl;
//mostra o vetor
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
29 - 03/06/14
}
Resulta! ! "#!$#a%a&
1 2 3
Resu%! a s)'ta-e e Cet!#es&
int aQJR; //cria um vetor de inteiros a com tres posicoes indices uteis de $ ate 4
float %QSR; //cria um vetor de float % com nove posicoes indices uteis de $ ate T
%QTR"J.#P#IU4SI; //,rava J.#P#I... na ultima posicao do vetor %
if (%QIR""4.#V) { /1acao1/} ; //teste de i,ualdade
D)a$#a%a ! Cet!#&
Perceba que a faixa til do vetor vai de 0 at (n-1) onde n o valor dado como tamanho do vetor no momento
de sua criao, no nosso caso 3.
Nada impede que voc grave ou leia ndices fora dessa rea til, isso muito perigoso, porque fora dessa rea,
o que voc tem so outras variveis de memria e no o espao reservado para seu vetor. perfeitamente
aceitvel, embora desastroso escrever em nosso programa aQPR"J;. O compilador calcula o endereo de
memria da posio 4 com base na posio inicial do vetor e o tamanho do tipo alocado. Aps calculado o
endereo da posio 4 o valor 3 copiado, apagando o contedo anterior!
C!%e't(#)!s&
Note que no estamos usando ponteiros neste exemplo e por isso que o vetor alocado estaticamente, em
tempo de compilao, tambm por este motivo que o argumento que vai no lugar do 3 no cdigo int a[3]; deve
ser uma expresso constante e no uma varivel.
1.=.4.4. COPIA DE OBJETOS COM 6ETORES ALOCADOS ESTATICAMENTE.
No primeiro exemplo do TAD frao vimos que o compilador fornece cpia bit a bit para objetos, alertamos
tambm sobre o perigo de usar este tipo de cpia em conjunto com alocao dinmica. O exemplo seguinte
mostra um caso onde esta cpia oferecida pelo compilador segura, o tpico seguinte 1.5.3.4 mostra um caso
onde esta cpia no segura, leia ambos para ter uma viso geral do assunto:
#include <iostream.h>
class vetor2tres
{
pu%lic(
int vetQJR;
//vetor alocado estaticamente numa classe.
vetor2tres(int aint %int c)
{ vetQ$R"a; vetQ#R"%; vetQ4R"c; }
//construtor do vetor
void mostra(void)
{ cout << vetQ$R << & & << vetQ#R << & & << vetQ4R << endl;}
//funcao mem%ro para mostrar o conteudo do vetor
};
void main()
{
vetor2tres v#(#4J);
//criacao de um o%!eto vetor.
vetor2tres v4(#I#U#V);
//criacao de um o%!eto vetor.
v#.mostra();
//mostrando o conteudo de v#.
v4.mostra();
//mostrando o conteudo de v4.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
30 - 03/06/14
v4"v#;
//atri%uindo o%!eto v# ao o%!eto v4.
v4.mostra();
//mostrando v4 alterado.
v#.vetQ$R"PP;
v#.mostra();
//mostrando o conteudo de v#.
v4.mostra();
//mostrando o conteudo de v4.
}
Resulta! ! "#!$#a%a&
1 2 3
15 16 17
1 2 3
44 2 3
1 2 3
C!%e't(#)!s&
Perceba que no caso de alocao esttica, quando o tamanho do vetor conhecido em tempo de compilao a
cpia segura. Por cpia segura entenda: as posies do vetor so copiadas uma a uma e os objetos no
ficam fazendo referncia a um mesmo vetor, isto pode ser visto no resultado do programa, quando alteramos a
cpia de v1, v1 no se altera.
1.=.4.7. 6ETORES CRIADOS DINAMICAMENTE
O exemplo a seguir anlogo ao de 1.5.3.2, mas os vetores so alocados dinamicamente, ou seja, voc
determina em tempo de execuo qual o tamanho do vetor, Pascal no permite isso.
#include <iostream.h>
void main()
{
int tamanho;
//arma3ena o tamanho do vetor a criar.
int1 vet;
//ponteiro para inteiro ou vetor de inteiro ainda nao criado
cout << &=ntre com o tamanho do vetor a criar&;
cin >> tamanho;
vet"neE intQtamanhoR;
//alocando vetor de &tamanho& posicoes comecando em aQ$R
for (int i"$;i<tamanho;i--)
{
cout << &=ntre com o valor da posicao & << i << &(&;
cin >> vetQiR;
cout << endl;
}
//loop de leitura no vetor
for (int !"$;!<tamanho;!--)
{
cout << &5osicao & << ! << &(& << vetQ!R<<endl;
}
//loop de impressao do vetor
}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
31 - 03/06/14
Resulta! ! "#!$#a%a&
Entre com o tamanho do vetor a criar3
Entre com o valor da posicao 0:1
Entre com o valor da posicao 1:2
Entre com o valor da posicao 2:3
Posicao 0:1
Posicao 1:2
Posicao 2:3
C!%e't(#)!s&
int* a;
Declara um ponteiro para inteiro.
a=new int[10];
Diferente de neE int(#$); os colchetes indicam que para ser criado um vetor de tamanho 10 e no uma
varivel de valor 10 como em 1.5.3.1. Ao contrrio de alocao esttica, o parmetro que vai no lugar do valor
10 no precisa ser uma expresso constante.
int* a;
a=new int[10];
equivale a forma abreviada:
int* a=new int[10];
A faixa de ndices teis do vetor novamente vai de 0 at (10-1) ou (n-1).
1.=.4.=. COPIA DE OBJETOS COM 6ETORES ALOCADOS DINAMICAMENTE.
Essa determinao do tamanho do vetor em tempo de execuo vai tornar a cpia de objetos feita pelo
compilador diferente, ele vai copiar o ponteiro para o vetor, ou seja os objetos passam a compartilhar a
estrutura na memria, o que nem sempre pode ser desejvel! Existem maneiras de redefinir esta cpia feita
pelo compilador o que veremos em 0.
#include <iostream.h>
class vetor2tres
{
pu%lic(
int1 vet;
//vetor alocado estaticamente numa classe.
vetor2tres(int aint %int c)
{
vet"neE intQJR;
vetQ$R"a;
vetQ#R"%;
vetQ4R"c;
}
//construtor do vetor
void mostra(void)
{ cout << vetQ$R << & & << vetQ#R << & & << vetQ4R << endl;}
//funcao mem%ro para mostrar o conteudo do vetor
};
void main()
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
32 - 03/06/14
{
vetor2tres v#(#4J);
//criacao de um o%!eto vetor.
vetor2tres v4(#I#U#V);
//criacao de um o%!eto vetor.
v#.mostra();
//mostrando o conteudo de v#.
v4.mostra();
//mostrando o conteudo de v4.
v4"v#;
//atri%uindo o%!eto v# ao o%!eto v4.
v4.mostra();
//mostrando v4 alterado.
v#.vetQ$R"PP;
v#.mostra();
//mostrando o conteudo de v#.
v4.mostra();
//mostrando o conteudo de v4.
}
Resulta! ! "#!$#a%a&
1 2 3
15 16 17
1 2 3
44 2 3
44 2 3
C!%e't(#)!s&
Note que quando alteramos a cpia de v1, v1 se altera. sto ocorre porque o vetor no copiado casa a casa
como em 1.5.3.3, s se copia o ponteiro para a posio inicial do vetor, a partir do qual se calcula os endereos
das posies seguintes v[3]==*(v+3).
Sobre o texto acima: "a partir do qual se calcula os endereos das posies seguintes", veja o programa
exemplo:
#include <iostream.h>
void main()
{
int1 v;
v"neE intQJR;
cout << 1(v-#)<<endl;
//imprime o lixo contido na memoria de vQ#R
cout << vQ#R <<endl;
//imprime o lixo contido na memoria de vQ#R
//1(v)""vQ$R W uma expressao sempre verdadeira
}
Resulta! ! "#!$#a%a&
152
152
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
33 - 03/06/14
C!%e't(#)!s&
O que importante deste exerccio que s se armazena a posio inicial do vetor, as outras posies so
calculadas com base no tamanho do tipo alocado e regras de aritmtica de ponteiros. No podemos nos
estender muito neste tema, leia sobre aritmtica de ponteiros, porm para este tutorial, basta usar os vetores de
forma que esta aritmtica fique por conta da linguagem.
Vetores alocados dinamicamente e ponteiros so a mesma coisa, isto pode ser visto nesse programa exemplo
que mistura a sintaxe de vetores e de ponteiros.
1.=.4.?. TAD E ALOCAO DINFMICA.
Tipo abstrato de dados vetor.
Um dos grandes problemas de trabalhar com vetores comuns de C++ ( int * a; a=new int[10]; a[22]=3; ) que
freqentemente lemos ndices invlidos, ou pior gravamos encima deles.
Gravar encima de um ndice fora dos limites de um vetor um erro freqente em programao C++. Saiba que
fazendo isso voc pode estar apagando instrues de outros programas na memria e outras informaes
importantes! Em alguns casos quando isso ocorre obtm-se inclusive mensagens do sistema operacional
avisando que algo est errado e que necessrio reinicializar a mquina.
Cu#)!s)ae:
Houve um caso de vrus na internet que se baseava no acesso a ndices fora de um vetor para gravar por cima
de instrues do sistema operacional, cdigo que garantisse a sua multiplicao.
Algumas linguagens de programao como Pascal e Mdula-3 checam os ndices para que no se acesse
reas invlidas de um vetor. Mdula-3 fornece inclusive os limites dos vetores simples da linguagem atravs de
chamadas last(vetor) ou first(vetor) . Em C++ tal tipo de checagem pode ser implementada pelo
programador como faremos neste exemplo.
D)/a e P#!$#a%a1;!&
Lembre-se: seu sucesso em programao vai depender em muito de sua disciplina e organizao tenha sempre
em mente que C++ uma linguagem poderosa e que se no usada corretamente pode criar transtornos e erros
no perceptveis em testes do programa.
No checar os ndices de um vetor em programas grandes como instalar uma bomba relgio em seu cdigo,
muito provvel que em algum instante voc ou at mesmo outra pessoa usando seu programa se distraia e
acabe por escrever uma rotina que acessa um ndice invlido de um vetor, fazendo na maioria das vezes o
programa falhar.
A proposta deste exemplo criar um tipo abstrato de dados vetor com uma interface flexvel que sirva para
vrias aplicaes e possa ser facilmente estendida. Este exemplo simples e vai ser reapresentado com muitas
melhorias no decorrer do tutorial, dentre elas: "templates" 4.3, "exception handling" 4.5, e a criao de uma
classe iterador para o vetor4.1 . A primeira vista voc pode achar que este programa no oferece muito mais
que o uso comum de vetores em C++, mas com as melhorias que apresentaremos, certamente voc vai preferir
representar vetores como tipos abstratos de dados ou TAD's.
//file exvet#.h
//header file para classe vetor
const int inicio"$;
class vetor{
private(
int1 v;
//este eF o vetor
int tamanho;
//tamanho maximo do vetor
pu%lic(
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
34 - 03/06/14
vetor (int tam);
//construtor aloca memXria para o vetor.
void atri%ui(int indexint valor);
//altera uma posicao do vetor
int conteudo(int index);
//retorna conteudo de posicao do vetor
int maximo(void);
//retorna o maior elemento do vetor
int primeiro(void);
//primeiro indice do vetor
int ultimo(void);
//ultimo indice do vetor
Hvetor() {delete v;}
//inline function ou use delete vQR;
};
//codi,o implementacao para o header file
#include <iostream.h>
#include <stdli%.h>
#include &exvet#.h&
vetor((vetor (int tam)
{v"neE intQtamR; tamanho"tam;}
void vetor((atri%ui(int indexint valor)
{
if (index<tamanho YY index>"inicio)
vQindexR"valor;
}
int vetor((conteudo(int index)
{
if (index>"tamanho ZZ index<inicio) {cerr << &Dora dos limites&; exit(#);}
return vQindexR;
}
int vetor((primeiro(void)
{ return inicio;}
int vetor((ultimo(void)
{ return tamanhoM#;}
int vetor(( maximo(void)
{int candidato"inicio; //candidato ao maximo
for (int i"inicio;i<tamanho;i--)
if (vQiR>vQcandidatoR) candidato"i;
return vQcandidatoR;}
//pro,rama pricipal
#include <iostream.h>
#include &exvet#.h&
main()
{
int aux;
//para ler valor a atri%uir
vetor meu(I);
for (int i"meu.primeiro();i<"meu.ultimo();i--)
{
cout << &=ntre com valor da posicao(& << i << &*n&;
cin >> aux;
meu.atri%ui(iaux);
}
for (int !"meu.primeiro();!<"meu.ultimo();!--) cout<< meu.conteudo(!)<< & &;
cout <<endl << &9aximo(& << meu.maximo();
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
35 - 03/06/14
return $;
}
C!%e't(#)!s&
O mtodo
~vetor() {delete v;} //use delete []v;depende do compilador
um destrutor, assim como o construtor ele no tem valor de retorno porque chamado pelo sistema
operacional quando o objeto sai de escopo ou quando voc desaloca memria de um ponteiro para o objeto. A
nica ao do destrutor liberar a memria ocupada pelo atributo vetor de inteiros (int * v) da classe vetor. De
um modo geral os destrutores servem para "arrumar a casa" quando objetos so desalocados ou saem de
escopo. A sintaxe dos mtodos para deleo de vetores delete v; ou delete []v; podem variar de compilador
para compilador, o usurio deve checar que sintaxe seu compilador suporta.
Note que quando no dispnhamos do destrutor o programador era obrigado a deletar passo a passo todas as
estruturas dinmicas dos objetos que saiam de escopo, existem tcnicas avanadas para obter coleta
automtica de lixo em C++ baseadas neste ponto.
Resulta! ! "#!$#a%a&
Entre com valor da posicao:0
4
Entre com valor da posicao:1
5
Entre com valor da posicao:2
9
Entre com valor da posicao:3
2
Entre com valor da posicao:4
1
4 5 9 2 1
Maximo:9
D)/a e "#!$#a%a1;!&
Saiba que uma prtica bastante til na fase de testes de um programa introduzir mensagens informativas em
pontos convenientes. Quando trabalhando com objetos tal prtica pode ser usada de vrios modos, por
exemplo pode-se inserir uma mensagem no destrutor de uma classe para verificar quando os objetos so
eliminados e se so eliminados corretamente.
1.=.4.@. ALOCANDO OBJETOS
Pula, em Modula-3 j so alocados.
Este exemplo mostra como trabalhar com ponteiros para objetos, new e delete, como alocar memria e chamar
corretamente os construtores.
C!%e't(#)!s&
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
36 - 03/06/14
Perceba que agora no estamos alocando um vetor de inteiros com trs posies (new int[3]), mas um inteiro
que contm o valor 3. Voc pode ler o cdigo (*a) como: "O apontado de a".
Se a fosse uma struct ou class e tivesse um dado membro chamado dd, poderamos obter o valor de dd atravs
de (*a).dd que pode ser todo abreviado em a->dd onde -> uma seta, ou flecha que voc pode ler como "o
apontado" novamente.
Os parnteses em (*a).dd so necessrios devido a precedncia do operador . com relao ao *.
1.=.7. REFERHNCIA I
Aqui vou ensinar passagem por referncia, lembre-se que objetos so passados por referncia, porque eles so
referncia, ponteiros.
Este tpico vai explicar como usar o operador &, tambm chamado de operador "endereo de...". Este operador
fornece o endereo, a posio na memria de uma varivel, de um argumento, etc. Sua utilizao muito
simples, se a uma varivel inteira, &a retorna um ponteiro para a.
O programa a seguir ilustra a sintaxe do operador:
#include <iostream.h>
void main()
{
int a;
a"#$;
int1 p;
p"Y a;
(1p)"#J;
cout << a;
}
E-"l)/a'! ! "#!$#a%a "ass! a "ass!&
int a;
Declara uma varivel inteira com nome a.
a=10;
atribui valor 10 a varivel a.
int* p;
Declara um ponteiro de varivel inteira , o nome do ponteiro p.
p=& a;
Atribui o "endereo de a" , &Y a& ao ponteiro p.
(*p)=13;
Atribui 13 ao "apontado de p", "(1p) ", mas como p aponta para a, a passa de valor 10 para valor treze atravs
de p. 5 um "alias" para a.
cout << a;
mprime o valor esperado que treze.
O programa a seguir usa o operador "endereo de" para modificar argumentos, parmetros de uma funo, ou
seja utiliza passagem por referncia, equivalente ao VAR de Pascal. Lembre-se que at agora os argumentos
das nossas funes s eram passados por valor.
#include <iostream.h>
void incrementa(intY a)
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
37 - 03/06/14
a--;
}
//primeira funcao que usa passa,em por referencia
void troca(intY aintY %)
{
int aux"a;
a"%;
%"aux;
}
//se,unda funcao que usa passa,em por referencia
void main()
{
int i#"#$;
int i4"4$;
incrementa(i#);
cout << i# << endl;
troca(i#i4);
cout << i# << endl;
}
Resulta! ! "#!$#a%a&
11
20
E-"l)/a'! "ass! a "ass!&
As funes criadas no programa, so como dissemos, capazes de alterar seus parmetros, incrementa ,
incrementa seu nico parmetro e troca, troca os dois parmetros inteiros.
1.?. RECAPITULANDO
Neste tpico apresentaremos programas que revisam todos conceitos j vistos e acrescentam mais alguns
detalhes da linguagem.
1.?.1. ARGUMENTOS DE LIN:A DE COMANDO.
Neste tpico vamos apresentar um exemplo que usa tudo o que foi aprendido at agora e introduz mais alguns
outros conceitos. Este exemplo um jogo de quebra cabea. Provavelmente voc j viu um quebra cabea
deste tipo, ele chamado quebra cabea de tijolos deslizantes. composto de um tabuleiro (matriz) quadrado
preenchido com peas de 0 at (lado^2-1) onde lado a dimenso de um lado do tabuleiro. A representao no
programa numrica, mas normalmente esses quebra cabeas so vendidos com desenhos pintados sobre as
pecas. No lugar onde deveria estar a ltima pea deixa-se um espao vazio para que se possa mover as peas
do tabuleiro. O objetivo colocar todos os tijolos em ordem.
O que um quebra cabea tem a ver com encapsulamento? Simples o jogador obrigado a seguir as regras do
jogo, portanto no pode conhecer todas as operaes que se aplicam ao quebra cabea, e tambm no pode
acessar sua representao interna. Vamos ver como isso feito usando as palavras reservadas private e public
, conceitos de agregao e reuso de cdigo de uma classe matriz. Alm disso usamos const para garantir a
integridade da matriz do quebra-cabea.
Veja tambm que estamos abordando o tpico representao, no raro voc ter que modelar objetos que
representem algo do mundo real como motor, quebra-cabea, conta bancria, circuito eltrico e assim por
diante. Outros objetos podem ser mais abstratos, exemplo: rvore binria.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
38 - 03/06/14
Ma)s s!3#e as #e$#as&
Voc concorda que dada uma situao onde o espao vazio se encontra no meio do quebra-cabea dado como
exemplo o usurio s tem 4 opes? So elas: mover para cima (funo membro movecima), mover para
baixo , mover para a esquerda ou ento para a direita. Note que essas funes membro s trocam peas
vizinhas, isso importante pois provado matematicamente que algumas trocas de peas distantes ("Odd
permutations") podem tornar o quebra-cabea insolvel. sto facil de ser verificado para um quebra cabea
2x2.
Garantimos a soluo do quebra-cabea pelo caminho inverso do embaralhamento das peas, que parte do
quebra-cabea solucionado e aplica aleatoriamente sequncias de movimentos iguais aos que o usurio usa
para solucionar o jogo.
A matriz bidimensional representada linearmente (vetor) e as funes membro de converso de ndice linear
para colunas e/ou linhas e atribuies so fornecidas, mas somente as necessrias para o jogo .
Re/u#s!s ut)l)Ja!s&
Argumentos de linha de comando, funes de converso da stdli% representao linear de uma matriz,
const.
A#$u%e't!s e l)'0a e /!%a'!&
Voc pode fazer programas que aceitem argumentos de linha de comandos, resultando em algo equivalente a:
dir /w //dos
format A: //dos
ou ls -la //unix
Esses argumentos podem ficar disponveis na chamada da funo main de seu programa como os parmetros
"argument counter" e "argument values", veja trecho de programa abaixo.
void main(int argc, char *argv[]) {.../*use argv e argc*/ ...}
argc um inteiro
argv um vetor de char1 contendo os argumentos passados. (/w ...)
argv [0] o nome do programa chamado.
A faixa til de argvalues : argv[1]...argv[argc-1]
Portanto se ar,c""4, temos um nico argumento de linha de comando, disponvel como string em ar,vQ#R .
Faa alguns testes com o mesma main usada no programa abaixo e alguns coutFs imprimindo os argumentos
para entender melhor o assunto.
C!'st&
J exemplificado em 1.5.1
Re"#ese'ta1;! l)'ea# e u%a %at#)J&
Pode-se representar uma matriz de qualquer dimenso em um vetor. Veja o exemplo de uma matriz
bidimensional de inteiros mostrada no formato indicelinear:valor armazenado
Vantagem da representao linear (vetor): para referenciar uma posio gasta-se somente um inteiro contra
dois da representao matriz (linha,coluna). Podemos agora considerar posies que apontam para outras
posies, basta interpretar o contedo do vetor como um ndice linear.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
39 - 03/06/14
Desvantagem da representao linear (vetor): necessrio criar funes de converso de ndice na forma
(linha,coluna) para (ndice linear) e de (ndice linear) para (coluna) ou (linha). Veja as funes lin e col e
linear do exemplo seguinte.
Fu'12es e /!'Ce#s;! a Stl)3&
A funo int atoi(char1 a) converte uma string para um inteiro.
#include <stdli%.h>
class matri3 //que%ra ca%eca de ti!olos desli3antes
{
private(
int linhas; //numero de linhas da matri3
int colunas; //numero de colunas na matri3
int tam; //"linhas1colunas
int 1lc; //vetor de tamanho linha1colunas representando matri3($..(tamM#)
pu%lic(
matri3(const int lconst int c); //cria matri3 Bx:
//qualquer uma das funcoes a%aixo retorna nil se nao conse,uiu
int1 linear(const int linconst int col)const ; //ind linear a partir de linha e
coluna
int1 col(const int indlin)const ;//coluna a partir do indice linear
int1 lin(const int indlin)const ; //linha a partir do indice linear
int trocaindlin(const int iconst int !); //ar,umentos( 4 indices lineares
//retorna # conse,uiu $ nao conse,uiu
int atri%uiindlin(const int iconst int v); //atri%ui v ao indice i
//retorna # conse,uiu $ nao conse,uiu
int1 retornaindlin(const int i); //retorna conteudo do indice i
//retorna nil se nao conse,uiu
int ,etl(void); //retorna numero de linhas
int ,etc(void); //retorna numero de colunas
int ,ett(void); //retorna tamanho " linhas1colunas
Hmatri3();
};
#include &matri3.h&
matri3((matri3(const int lconst int c) //cria matri3
{
lc"neE intQl1cR; //lc dimensoes ; lc vetorQl1cR
linhas"l;
colunas"c;
tam"linhas1colunas;
}
int1 matri3((linear(const int alinconst int acol) const
//ind linear a partir de linha e coluna
{
int1 result"neE int; //valor de retorno
if ( ($<alin) YY (alin<"linhas) YY ($<acol) YY (acol<"colunas) )
{
(1result)"(alinM#)1colunas-acol;
return result;
}
else
return ?;BB;
}
int1 matri3((col(const int indlin)const //coluna a partir do indice linear
{
int1 result"neE int;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
40 - 03/06/14
if ( ($<indlin) YY (indlin<"tam) )
{
(1result)"(indlin N colunas);
if ((1result)""$) (1result)"colunas;
return result;
}
else
return ?;BB;
}
int1 matri3((lin(const int indlin)const //linha a partir do indice linear
{
int1 result"neE int;
if ( ($<indlin) YY (indlin<"tam) )
{
(1result)"(int((indlinM#) / colunas)-#);
return result;
}
else
return ?;BB;
}
int matri3((trocaindlin(const int iconst int !) //ar,umentos( 4 indices lineares
//retorna # conse,uiu $ nao conse,uiu
{
int aux;
if ( ($<i) YY (i<"tam) YY ($<!) YY (!<"tam) )
{ aux"lcQiM#R; //efetua a troca
lcQiM#R"lcQ!M#R; //em%ora para usuario a matri3 vai de # ate l1c
//para mim vai de o ate l1cM#
lcQ!M#R"aux;
return #; //sucesso
}
else return $; //falhou
}
int matri3((atri%uiindlin(const int iconst int v)
//retorna # conse,uiu $ nao conse,uiu
{
if ( ($<i) YY (i<"tam) )
{
lcQiM#R"v; //efetua a atri%uicao
return #;
}
else return $; //falhou
}
int1 matri3((retornaindlin(const int indlin)
//retorna nil se nao conse,uiu
{
int1 result"neE int;
if ( ($<indlin) YY (indlin<"tam) )
{
1result"lcQindlinM#R;
return result;
}
else
return ?;BB;
}
int matri3((,etl(void) //retorna numero de linhas
{
return linhas;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
41 - 03/06/14
}
int matri3((,etc(void) //retorna numero de colunas
{
return colunas;
}
int matri3((,ett(void) //retorna tamanho
{
return tam;
}
matri3((Hmatri3()
{
delete lc;
}
//que%ra ca%ecas de ti!olos desli3antes
#include <iostream.h> //para cin cout
#include <iomanip.h> //formatar cout output com >> setEidth()
#include <stdli%.h> //uso rand() em em%aralha
#include <strin,.h> //atoi() para converter ar,umentos de linha de comando
#include &matri3.h&
const int min2lado"4; //minimo tamanho lateral do que%raca%.
const int tam2padrao"I; //tamanho padrao
class que%raca% //que%ra ca%eca de ti!olos desli3antes
{
private(
int va3io; //indice linear da casa va3ia
int mov; //numero de movimentos
matri31 mqc; //matri3 interna do que%ra ca%ecas
pu%lic(
que%raca%(const int ld"tam2padrao); //cria que%ra ca%eca ld"lado
void mostra() const; //mostra que%ra ca%eca
void movedir(); //move celula a esq de va3io para direita.
void moveesq(); //analo,o
void move%aixo(); //analo,o
void movecima(); //analo,o
void em%aralha(); //em%aralha que%raca%eca
int tstsolucao() const; //testa se que%raca%eca esta solucionado
int retorna2mov() { return mov; } //retorna numero de movimentos
Hque%raca%(); //destroi que%ra ca%ecas
};
que%raca%((que%raca%(const int ld) //ar,umento padrao desnessario !a declarado
{
int ldc"a%s(ld); //ld copia " valor positivo de ld
if (ldc<min2lado) ldc"min2lado;
mqc"neE matri3(ldcldc); //iniciali3a o%!eto matri3
for(int i"#;i<mqcM>,ett();i--)
mqcM>atri%uiindlin(ii); //initiali3a casas da matri3
mqcM>atri%uiindlin(mqcM>,ett()$);//atri%ui 3ero a posicao da celula va3ia
va3io"mqcM>,ett(); //define posicao da celula va3ia
mov"$; //sem nenhum movimento
em%aralha(); //em%aralha que%raca%eca
}
void que%raca%((mostra() const //mostra que%ra ca%eca
{
int i!; //linha e coluna
int1 ind; //valor atual
for(i"#;i<"mqcM>,etl();i--) //loop das linhas
{ //linhas
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
42 - 03/06/14
for(!"#;!<"mqcM>,etc();!--) //loop das colunas
{ //colunas
ind"mqcM>linear(i!); //resultado tam%em e ponteiro
if
((1ind)""va3io) cout << setE(P)<<& &; //va3io"espaco
else
cout << setE(P) << (1mqcM>retornaindlin(1ind)); //nao e o va3io mostra conteudo
} //colunas
cout << endl; //mudanca de linha
} //linhas
cout << endl;
}
void que%raca%((movedir() //move celula a esq de va3io para direita
//espaco move para esquerda
{
if ( (1(mqcM>col(va3io))) ."#) /1nao esta na %orda esquerda1/
{
mqcM>trocaindlin(va3iova3ioM#);
mov--;
va3io"va3ioM#;
}
}
void que%raca%((moveesq() //espaco move para direita
{
if ( (1(mqcM>col(va3io)))."mqcM>,etc() ) /1nao esta na %orda direita1/
{
mqcM>trocaindlin(va3iova3io-#);
mov--;
va3io"va3io-#;
}
}
void que%raca%((move%aixo() //espaco move para cima
{
if ((1(mqcM>lin(va3io)))."#) /1nao esta no topo1/
{
mqcM>trocaindlin(va3iova3ioM(mqcM>,etc())); //chama funcao private
mov--;
va3io"va3ioM(mqcM>,etc());
}
}
void que%raca%((movecima() //espaco move para %aixo
{
if ((1mqcM>lin(va3io))."mqcM>,etl()) /1nao esta em %aixo1/
{
mqcM>trocaindlin(va3iova3io-(mqcM>,etc()));
mov--;
va3io"va3io-(mqcM>,etc());
}
}
void que%raca%((em%aralha() //em%aralha que%raca%eca
{
int i!; //loop principal loop secundario
int r; //r times
for(!"$;!<mqcM>,ett();!--)
{
r"(rand()N mqcM>,etc());
for(i"$;i<r;i--) {thisM>movedir();} //move r ve3es
r"(rand()N mqcM>,etl());
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
43 - 03/06/14
for(i"$;i<r;i--) {thisM>move%aixo();}
r"(rand()N mqcM>,etc());
for(i"$;i<r;i--) {thisM>moveesq();}
r"(rand()N mqcM>,etl());
for(i"$;i<r;i--) {thisM>movecima();}
}
mov"$; //iniciali3a movimentos
}
int que%raca%((tstsolucao() const //testa se que%raca%eca esta solucionado
{
int i"#cont"#;
Ehile( cont YY (i< (mqcM>,ett()) ) )
{
if ((1(mqcM>retornaindlin(i)))""(i)) cont"#; else cont"$;
i--;
}
return (cont); //i"qctam esta solucionado # 4 J... 4P $
}
que%raca%((Hque%raca%()
{if (mqc."?;BB) delete mqc; cout << & Lue%ra ca%eca destruido.*n&;} //destroi
que%raca%
main(int ar,cchar 1ar,vQR) //ar,umentos sao declarados aqui
{ //main
int ladocomp;
char opcao; //usada em menu como variavel de opcao
if (ar,c>#) ladocomp"atoi(ar,vQ#R);
//convertendo ar,umento de linha de comando para inteiro
else ladocomp"tam2padrao; //valor default
que%raca% aque%raca%(ladocomp); //criando que%raca%
do {
aque%raca%.mostra();
cout <<&*n&; //menu de opcoes
cout <<& 9ovimentos(& << aque%raca%.retorna2mov()<< &*n&;
cout <<& P<M UM> T:ima 4Caixo @@air =em%aralha *n&;
cout <<& 'econhece sequencias de comandos( 4UTU4P <=nter>*n&;
cout <<& 8ceita ar,umento de linha de comando( que%raca% P (cria que%raca%eca P x
P)*n&;
cout <<& =ntre comando(&;
cin >> opcao; //le opcao do usuario
cout <<&*n&;
sEitch(opcao) //executa opcao do usuario
{
case F=F(
case FeF(
aque%raca%.em%aralha();
%rea[;
case FTF( aque%raca%.movecima();
%rea[;
case F4F( aque%raca%.move%aixo();
%rea[;
case FPF( aque%raca%.moveesq();
%rea[;
case FUF( aque%raca%.movedir();
%rea[;
default( ;
} //fim do %loco de codi,o do sEitchMcase
if (aque%raca%.tstsolucao()) opcao"FsF; //sai do loop de menu
} Ehile ((opcao."F@F) YY (opcao."FsF)); //loop menu
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
44 - 03/06/14
if (aque%raca%.tstsolucao()) {aque%raca%.mostra(); cout << & 5ara%ens.*n&;}
else cout << & Lue%ra ca%eca nao solucionado. <ente novamente.*n&;
return $;
} //%loco de codi,o principal
C!%e't(#)!s&
delete []qc; Este destrutor adota uma tcnica diferente para deleo de vetores, cheque que tcnicas seu
compilador suporta.
2. :ERANA
2.1. :IERAR5UIAS DE TIPOS
Neste tpico mostraremos como construir hierarquias de tipo por generalizao / especializao.
2.1.1. UMA :IERAR5UIA SIMPLES.
Construiremos uma hierarquia de tipos simples para demonstrar herana pblica em C++.
C!%e't(#)!s&
O diagrama representa a hierarquia de classes implementada e foi obtido a partir da janela de edio de uma
ferramenta case para programao orientada a objetos.
A classe ponto que est no topo da hierarquia chamada de classe base, enquanto que as classes
ponto_reflete e ponto_move so chamadas classes filhas ou herdeiras. As classes da hierarquia so simples,
ponto_move apresenta a funo membro move, j vista neste tutorial em 1.2.6, ponto_reflete apresenta a
funo membro (reflete) que inverte o sinal das coordenadas.
Dada a simplicidade das classes o leitor poderia se perguntar, porque no juntar
as trs em uma s . A pergunta faz sentido, mas e se quisssemos criar uma classe ponto que no se
movesse, apenas refletisse e outra que s se movesse? E se quisssemos projetar nosso programa segundo
uma hierarquia de especializao / generalizao da classe ponto? O exemplo mostra como faz-lo.
:e#a'1a PK3l)/a&
Na herana pblica as classes filhas passam a ter as mesmas funes membro public da classe pai, as classes
filhas podem acrescentar funes membro, dados membro e at redefinir funes membro herdadas (veremos
mais tarde). Os atributos da classe pai no so acessveis diretamente na classe filha a no ser que sejam
qualificados como protected, veja 2.1.2. Por isso que se diz que as classes filhas garantem pelo menos o
comportamento "behaviour" da classe pai, podendo acrescentar mais caractersticas.
Diagrama de acesso, visibilidade, de dados membro e funes membro de uma classe pai para uma classe filha
ou herdeira por herana pblica.
C!'st#ut!#es e 0e#a'1a&
No construtor de uma classe filha o programador pode incluir a chamada do construtor da classe pai.
Dest#ut!#es e 0e#a'1a&
Quando um objeto da classe derivada destrudo, o destrutor da classe pai tambm chamado dando a
oportunidade de liberar a memria ocupada pelos atributos private da classe pai.
//header file
class ponto
{
private(
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
45 - 03/06/14
float x; //sao ocultos por default
float y; //sao ocultos por default
pu%lic( //daqui em diante tudo e acessivel.
ponto(float afloat %);
void iniciali3a(float afloat %);
float retorna2x(void);
float retorna2y(void);
void altera2x(float a);
void altera2y(float %);
void mostra(void);
};
class ponto2reflete(pu%lic ponto //classe filha
{
private( //se voce quer adicionar atri%utos...
pu%lic(
ponto2reflete(float a float %);
void reflete(void);
};
class ponto2move(pu%lic ponto
{
pu%lic(
ponto2move(float afloat %);
void move(float dxfloat dy);
};
//implementation file
#include <iostream.h>
#include &pontos.h&
ponto((ponto(float afloat %)
{
iniciali3a(a%);
}
void ponto((iniciali3a(float afloat %)
{
x"a;
y"%;
}
float ponto((retorna2x(void)
{ return x; }
float ponto((retorna2y(void)
{ return y; }
void ponto((altera2x(float a)
{ x"a; }
void ponto((altera2y(float %)
{ y"%; }
void ponto((mostra(void)
{
cout << &(& << x << && << y << &)& <<endl;
}
ponto2reflete((ponto2reflete(float afloat %)(ponto(a%)
{ }
void ponto2reflete((reflete(void)
{
altera2x(Mretorna2x());
altera2y(Mretorna2y());
}
ponto2move((ponto2move(float afloat %)(ponto(a%)
{ }
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
46 - 03/06/14
void ponto2move((move(float dxfloat dy)
{
altera2x(retorna2x()-dx);
altera2y(retorna2y()-dy);
}
#include <iostream.h>
#include &pontos.h&
void main()
{
ponto2reflete p#(J.#P4.#V);
p#.reflete();
cout << &5#&;
p#.mostra();
ponto2move p4(#.$#.$);
p4.move(.I.I);
cout << &54&;
p4.mostra();
}
Resulta! ! "#!$#a%a&
P1(-3.14,-2.17)
P2(1.5,1.5)
:e#a'1a P#)Cate&
Ainda no foi inserido no tutorial nenhum exemplo com este tipo de herana, mas o leitor pode experimentar
mais tarde especificar uma classe herdeira por heranca private como: class herdeira: private
nome_classe_base; , e notar que as funes membro desta classe base s so acessveis dentro das
declaraes da classe filha, ou seja a classe filha no atende por essas funes membro, mas pode us-las em
seu cdigo.
Herana private um recurso que voc precisa tomar cuidado quando usar. Normalmente, quando usamos
herana dizemos que a classe filha garante no mnimo o comportamento da classe pai (em termos de funes
membro) , a herana private pode invalidar esta premissa.
Muitos programadores usam herana private quando ficaria mais elegante, acadmico, trabalhar com
agregao. Uma classe pilha pode ser construda a partir de uma classe que implementa uma lista ligada por
agregao ou por herana private. Na agregao (a escolhida em hierarquias de impleme!a"#$) a classe pilha
possui um dado membro que uma lista ligada.
2.1.2. PROTECTED
gual ao exemplo um, mas agora tornando os atributos da classe pai acessveis para as classes filhas atravs
do uso de protected. Protected deixa os atributos da classe pai visveis, acessveis "hierarquia abaixo".
Diagramas de acesso, visibilidade, de dados membro e funes membro de uma classe pai para uma classe
filha ou herdeira:
Para uma classe filha por herana
pblica:
Visibilidade da classe herdeira
para o restante do programa:
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
47 - 03/06/14
//header file
class ponto
{
protected(
//11111aqui esta a diferenca 111111
float x;
//visiveis hierarquia a%aixo
float y;
//visiveis hierarquia a%aixo
pu%lic(
//daqui em diante tudo e acessivel.
ponto(float afloat %);
void iniciali3a(float afloat %);
float retorna2x(void);
float retorna2y(void);
void altera2x(float a);
void altera2y(float %);
void mostra(void);
};
class ponto2reflete(pu%lic ponto
{
private(
//se voce quer adicionar dados mem%ro encapsulados...
pu%lic(
ponto2reflete(float a float %);
void reflete(void);
};
class ponto2move(pu%lic ponto
{
pu%lic(
ponto2move(float afloat %);
void move(float dxfloat dy);
};
//implementation file
#include <iostream.h>
#include &pontos.h&
ponto((ponto(float afloat %)
{
iniciali3a(a%);
}
void ponto((iniciali3a(float afloat %)
{
x"a;
y"%;
}
float ponto((retorna2x(void)
{ return x; }
float ponto((retorna2y(void)
{ return y; }
void ponto((altera2x(float a)
{ x"a; }
void ponto((altera2y(float %)
{ y"%; }
void ponto((mostra(void)
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
48 - 03/06/14
cout << &(& << x << && << y << &)& <<endl;
}
ponto2reflete((ponto2reflete(float afloat %)(ponto(a%)
{ }
void ponto2reflete((reflete(void)
{
x"Mx;
//111 protected da esse tipo de acesso aos atri%utos da classe pai
y"My;
}
ponto2move((ponto2move(float afloat %)(ponto(a%)
{ }
void ponto2move((move(float dxfloat dy)
{
x"x-dx;
//acesso so na hierarquia no resto do pro,rama nao.
y"y-dy;
}
#include <iostream.h>
#include &pontos.h&
void main()
{
ponto2reflete p#(J.#P4.#V);
p#.reflete();
cout << &5#&;
p#.mostra();
ponto2move p4(#.$#.$);
p4.move(.I.I);
cout << &54&;
p4.mostra();
}
2.1.4. REDEFINIO DE FUN,ES MEMBRO :ERDADAS
. gual ao exemplo anterior, mas agora redefinindo a funo membro mostra para a classe filha ponto
reflete.
C!%e't(#)!s&
Na verdade este exemplo deveria pertencer ao tpico de polimorfismo, contudo, nos exemplos seguintes
usaremos tambm redefinies de funes membro, portanto faz-se necessrio introduzi-lo agora. Teremos
mais explicaes sobre o assunto.
Uma classe filha pode fornecer uma outra implementao para uma funo membro herdada, caracterizando
uma redefinio "overriding" de funo membro. mportante: a funo membro deve ter a mesma assinatura
(nome, argumentos e valor de retorno), seno no se trata de uma redefinio e sim sobrecarga "overloading".
No nosso exemplo a classe ponto2reflete redefine a funo membro mostra da classe pai, enquanto
que a classe herdeira ponto2move aceita a definio da funo membro mostra dada pela classe ponto
que sua classe pai.
//header file
class ponto
{
private(
float x;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
49 - 03/06/14
//sao ocultos por default
float y;
//sao ocultos por default
pu%lic(
//daqui em diante tudo e acessivel.
ponto(float afloat %);
void iniciali3a(float afloat %);
float retorna2x(void);
float retorna2y(void);
void altera2x(float a);
void altera2y(float %);
void mostra(void);
};
class ponto2reflete(pu%lic ponto
{
private(
//se voce quer adicionar dados mem%ro
pu%lic(
ponto2reflete(float a float %);
void reflete(void);
void mostra(void);
//redefinicao
};
class ponto2move(pu%lic ponto
{
pu%lic(
ponto2move(float afloat %);
void move(float dxfloat dy);
//esta classe filha nao redefine mostra
};
//implementation file
#include <iostream.h>
#include &pontos.h&
ponto((ponto(float afloat %)
{
iniciali3a(a%);
}
void ponto((iniciali3a(float afloat %)
{
x"a;
y"%;
}
float ponto((retorna2x(void)
{ return x; }
float ponto((retorna2y(void)
{ return y; }
void ponto((altera2x(float a)
{ x"a; }
void ponto((altera2y(float %)
{ y"%; }
void ponto((mostra(void)
{
cout << &(& << x << && << y << &)& <<endl;
}
ponto2reflete((ponto2reflete(float afloat %)(ponto(a%)
{ }
void ponto2reflete((reflete(void)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
50 - 03/06/14
{
altera2x(Mretorna2x());
altera2y(Mretorna2y());
}
void ponto2reflete((mostra(void)
{
cout << &)(& << retorna2x() << & +(&;
cout << retorna2y() << endl;
}
//somente altera o formato de impressao
ponto2move((ponto2move(float afloat %)(ponto(a%)
{ }
void ponto2move((move(float dxfloat dy)
{
altera2x(retorna2x()-dx);
altera2y(retorna2y()-dy);
}
#include <iostream.h>
#include &pontos.h&
void main()
{
ponto2reflete p#(J.#P4.#V);
p#.reflete();
cout << &5#&;
p#.mostra();
ponto2move p4(#.$#.$);
p4.move(.I.I);
cout << &54&;
p4.mostra();
}
Resulta! ! "#!$#a%a&
P1X:-3.14 Y:-2.17
P2(1.5,1.5)
2.1.7. UMA :IERAR5UIA DE LISTAS LIGADAS
. Construiremos sem importar nenhum outro cdigo, uma hierarquia de listas ligadas especializadas. Um dos
objetivos obter uma implementao de lista que possa ser reutilizada para criao de pilhas e filas.
O desenho acima foi elaborado segundo metodologia descrita no livro "Object Oriented Modeling and Design" .
A associao entre as classes lista e n uma associao do tipo "has many" enquanto que a associao entre
a classe lista e as classes lista ultimo e lista ordenada indica herana, uma associao do tipo "is
a". Algumas simplificaes foram feitas do diagrama original.
No tpico sobre templates 0 modificaremos este exemplo para suportar tipos parametrizados. No tpico sobre
hierarquias de implementao 2.2 usamos a verso de lista descrita aqui para criar uma classe que implementa
uma fila.
#ifndef 9BA@<K2K
#define 9BA@<K2K
#include <stdli%.h>
#include <iostream.h>
//:ria/0o de uma hierarquia de listas li,adas.
//6 elemento da lista eF um inteiro
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
51 - 03/06/14
enum Coolean{D8B@=<';=};
class no{ //este eF o no da lista li,ada so eF usado por ela
private(
int info; //informa/0o
no1 prox; //ponteiro para o prXximo
pu%lic(
no();
no(int ino1 p);
no1 ,et2prox(void);
void set2prox(no1 p);
int ,et2info(void);
void set2info(int i);
no1 do%ra(void);
Hno(void);
} ;
class lista{ //esta eF a lista li,ada comum.
protected( //&vis\vel hierarquia a%aixo&
no1 primeiro; //primeiro no da lista aqui eu insiro e removo.
pu%lic(
lista(void);
Coolean va3ia(void)const;
Coolean contem(int el)const;
void insere2primeiro(int elem);
int1 remove2primeiro();
void mostra()const;
Hlista(void);
}; //fim classe lista
class listaultimo(pu%lic lista { //essa e a lista util para
//implementar pilhas e filas.
protected( //protected e uma opcao outra eF ,et2ultimo() e set2...
no1 ultimo;
pu%lic(
listaultimo(void);
void insere2ultimo(int elem); //nova
void insere2primeiro(int elem); //redefinicao
int1 remove2primeiro();//redefinicao
Hlistaultimo(void);
//as operacoes nao redefinidas sao validas.
};
class listaordenada(pu%lic lista {
//essa eF a lista comum com aprimoramentos/especiali3acoes
pu%lic(
listaordenada(void);
Coolean contem(int el)const;
void insere2primeiro(int elem);
//insere em ordem
int1 remove2elemento(int el);
//remove elemento el se existir
Hlistaordenada(void);
};
#endif
#include &mlisth.h&
#include <iostream.h>
#include <stdli%.h>
no((no()
{prox"?;BB;cout << &Ki&;}
no((no(int ino1 p)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
52 - 03/06/14
{info"i;prox"p;cout << &Ki&;}
no1 no((,et2prox(void){return prox;}
void no((set2prox(no1 p) {prox"p;}
int no((,et2info(void) {return info;}
void no((set2info(int i) {info"i;}
no1 no((do%ra(void)
{
if (,et2prox()""?;BB) return neE no(,et2info()?;BB);
else return neE no(,et2info()thisM>,et2prox()M>do%ra());
//recursividade para duplicacao da lista
}
no((Hno(void) {cout << &%ye&;}
lista((lista(void)(primeiro(?;BB) {}
//%loco de codi,o va3io
Coolean lista((va3ia(void)const
{
return Coolean(primeiro""?;BB);
}
Coolean lista((contem(int el) const//mais rapido que iterador
{
no1 curr;
int :onti;
curr"primeiro;
:onti"<';=;
Ehile ((curr."?;BB) YY :onti )
{
if (currM>,et2info()."el)
{if (currM>,et2prox()""?;BB) :onti"D8B@=; else curr"currM>,et2prox();}
else
:onti"D8B@=;
}; //Ehile
return Coolean(currM>,et2info()""el);
};
void lista((insere2primeiro(int elem)
{
no1 insirame;
if (primeiro""?;BB) //lista va3ia
primeiro"neE no(elem?;BB);
else {
insirame"neE no(elemprimeiro);
primeiro"insirame;
};
};
int1 lista((remove2primeiro()
{
int1 devolvame"neE int; //return
no1 temp; //to delete
if (primeiro""?;BB) return ?;BB; //lista va3ia
else {
(1devolvame)"primeiroM>,et2info();
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
return devolvame;
};
};
void lista((mostra() const
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
53 - 03/06/14
no1 curr;
cout << &"&;
curr"primeiro;
Ehile (curr."?;BB)
{
cout <<&(&<<currM>,et2info()<<&)&<<&M&;
curr"currM>,et2prox();
};
}
lista((Hlista(void)
{
no1 temp;
Ehile (primeiro."?;BB)
{
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
};
}
listaordenada((listaordenada(void)(lista()
{};
Coolean listaordenada((contem(int el)const
{
no1 curr;
Coolean conti"<';=;
curr"primeiro;
Ehile ((curr."?;BB) YY conti)
{
if (currM>,et2info()<el)
curr"currM>,et2prox();
else conti"D8B@=;
};
if (curr""?;BB) return D8B@=;
else return Coolean(currM>,et2info()""el);
}
void listaordenada((insere2primeiro(int elem)
{
no1 curr"primeiro;
no1 prev"?;BB;
no1 insirame;
Coolean conti"<';=;
Ehile ((curr."?;BB) YY conti)
{
if (currM>,et2info()<elem)
{prev"curr; curr"currM>,et2prox();}
else conti"D8B@=;
};
insirame"neE no(elemcurr);
if (prev""?;BB) primeiro"insirame;
else prevM>set2prox(insirame);
}
int1 listaordenada((remove2elemento(int el)
{
int1 devolvame"neE int;
no1 curr"primeiro;
no1 prev"?;BB;
no1 deleteme;
Coolean conti"<';=;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
54 - 03/06/14
Ehile ((curr."?;BB) YY conti) //acha lu,ar onde pode estar el
{
if (currM>,et2info()<el)
{prev"curr; curr"currM>,et2prox();} //anda
else conti"D8B@=;
};
if (curr""?;BB) return ?;BB; //fim de lista ou va3ia
else //pode ser o elemento ou ele nao existe
{
if (currM>,et2info()""el)
{
deleteme"curr;
if (prev""?;BB) //lista so com um elemento ou primeiro el
primeiro"currM>,et2prox();
else
{
prevM>set2prox(currM>,et2prox());
}
(1devolvame)"deletemeM>,et2info(); //so para verificar
delete deleteme;
return devolvame;
}
else return ?;BB;
}
}
listaordenada((Hlistaordenada(void)
{cout << &Bista destruida.&;};
listaultimo((listaultimo(void)(lista()
{
ultimo"?;BB;
}
void listaultimo((insere2ultimo(int elem)
{
no1 insirame;
insirame"neE no(elem?;BB);
if (ultimo""?;BB) ultimo"insirame; //lista va3ia
else {
ultimoM>set2prox(insirame);
ultimo"insirame;
};
if (primeiro""?;BB) primeiro"ultimo; //lista va3ia
}
void listaultimo((insere2primeiro(int elem) //redefinicao
{
no1 insirame;
if (primeiro""?;BB) //lista va3ia
{
primeiro"neE no(elemultimo);
ultimo"primeiro;
}//lista va3ia
else {
insirame"neE no(elemprimeiro);
primeiro"insirame;
};
}
int1 listaultimo((remove2primeiro()//redefinicao
{
int1 devolvame"neE int; //return
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
55 - 03/06/14
no1 temp; //to delete
if (primeiro""?;BB) return ?;BB; //lista va3ia
else {
(1devolvame)"primeiroM>,et2info();
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
if (primeiro""?;BB) ultimo"?;BB; //volta lista va3ia
return devolvame;
};
}
listaultimo((Hlistaultimo(void)
{
no1 temp;
Ehile (primeiro."?;BB)
{
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
};
delete ultimo;
}
#include &mlisth.h&
main()
{
listaordenada minha;
char option; //use in menu as option varia%le
int el; //elemento a inserir
int1 receptor;
do {
cout <<&*n&; //menu options display
cout <<&5(Ansere no primeiro.*n&;
cout <<&'('emove no primeiro.*n&;
cout <<&>('emove elemento.*n&;
cout <<&=(=xiste elemento]*n&;
cout <<&^(^a3ia]*n&;
cout <<&9(9ostra lista.*n&;
cout <<&L(Luit teste lista.*n&;
cout <<&=ntre comando(&;
cin >> option; //reads user option
sEitch(option) //executes user option
{
case F>F(
case FdF(
cout << &=ntre elemento(&;
cin >>el;
receptor"minha.remove2elemento(el);
if (receptor""?;BB) cout << &?;BB& << endl;
else cout << (1receptor) << endl;
%rea[;
case F5F(
case FpF(
cout << &=ntre elemento(&;
cin >> el;
minha.insere2primeiro(el);
%rea[;
case F'F(
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
56 - 03/06/14
case FrF(
if (.minha.va3ia())
cout << (1minha.remove2primeiro()) <<endl;
else cout << &?;BB Bista va3ia.& <<endl;
%rea[;
case F9F(
case FmF(
minha.mostra();
%rea[;
case F=F(
case FeF(
cout << &=ntre elemento(&;
cin >>el;
cout << minha.contem(el);
%rea[;
case F^F(
case FvF(
cout << minha.va3ia();
%rea[;
default( ;
} //sEitchMcase code %loc[
} Ehile ((option."FLF) YY (option."FqF)); //menu loop code %loc[
return $;
} //main code %loc[
C!%e't(#)!s&
Note que o programa principal s testa a lista ordenada, em outros programas exemplo baseados neste
veremos testes para a lista_ultimo.
2.2. :IERAR5UIAS DE IMPLEMENTAO
Nossas hierarquias de implementao em termos de cdigo (herana) no so hierarquias, usamos delegao
para obter pilhas a partir listas. Agregamos uma lista em nossas classes e usamos esta lista de acordo com a
lgica envolvida. Tudo o que fizemos poderia ser feito usando herana private, o que justificaria o ttulo
"hierarquias de implementao", embora tornasse o nosso texto menos acadmico.
2.2.1. FILA A PARTIR DE UMA LISTA
Reuso de cdigo de uma lista ligada 2.1 para a implementao de uma fila atravs de agregao. Para
podermos declarar e usar um objeto lista na nossa classe fila precisamos conhecer sua interface. Sabemos que
nosso objeto lista permite inserir em ambas extremidades, inicio e fim da lista, mas s permite remoes em um
extremo, o inicio. Como uma fila permite inseres somente num extremo e remoes nos extremo oposto,
precisaremos usar nossa lista da seguinte forma: insero no final da lista e remoes no comeo.
Seguem abaixo exemplos de chamadas de funes membro da classe lista implementada em 2.1 para trabalhar
com nmeros inteiros.
Consideremos uma lista al, so vlidas as seguintes operaes:
al.vazia(); //retorna se a lista (fila agora) esta vazia.
al.contem(el); //retorna 1 se el pertence a lista e 0 se el nao pertence a lista.
al.insere_ultimo(el); //insere no final da lista (entrada da fila).
al.insere_primeiro(el); //nao usaremos na implementacao de fila, usariamos se //implementassemos uma pilha.
al.remove_primeiro(); //remove no comeco da lista (saida da fila).
al.mostra(); //mostra lista (mostra fila em ordem contraria de insercao)
Para maiores informaes consulte tpico anterior onde definimos esta lista. Por este motivo no vamos incluir
sua definio a seguir.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
57 - 03/06/14
//header file para a classe fila
#include &mlisth.h&
class fila { //a,re,acao de uma lista de
private(
listaultimo al; //a lista
pu%lic(
fila();
Coolean va3ia();
Coolean contem(int el);
void insere(int el);
int1 remove();
void mostra();
};
//implementacao para a classe fila
#include &mqueue.h&
#include &mlisth.h&
fila((fila(){};
Coolean fila((va3ia()
{return al.va3ia();}
Coolean fila((contem(int el)
{return al.contem(el);}
void fila((insere(int el)
{al.insere2ultimo(el);}
int1 fila((remove()
{return al.remove2primeiro();}
void fila((mostra()
{al.mostra();}
//pro,rama principal testes da classe fila
#include &mqueue.h&
main()
{
fila minha;
char option; //usada em menu como variavel de opcao
int el; //elemento a inserir
do {
cout <<&*n&; //opcoes do menu
cout <<&A(Ansere.*n&;
cout <<&'('emove.*n&;
cout <<&9(9ostra fila.*n&;
cout <<&L(Luit fila test.*n&;
cout <<&^(^a3ia]*n&;
cout <<&:(:ontem]*n&;
cout <<&=ntre comando(&;
cin >> option; //le opcao do usuario
sEitch(option) //executa opcao do usuario
{
case FAF(
case FiF(
cout << &=ntre elemento(&;
cin >>el;
minha.insere(el);
%rea[;
case F'F(
case FrF(
if (.minha.va3ia())
cout << (1minha.remove()) <<endl;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
58 - 03/06/14
else cout << &?;BB fila va3ia.& <<endl;
%rea[;
case F:F(
case FcF(
cout << &=ntre elemento(&;
cin >>el;
cout << minha.contem(el);
%rea[;
case F9F(
case FmF(
minha.mostra();
%rea[;
case F^F(
case FvF(
cout << &'esultado(& << minha.va3ia() <<endl;
%rea[;
default( ;
} //sEitchMcase %loco de codi,o
} Ehile ((option."FLF) YY (option."FqF)); //loop do menu fim
return $;
} // %loco de codi,o principal
4. POLIMORFISMO9 FUN,ES 6IRTUAIS
.Existem vrios tipos de polimorfismo. No que se refere a objetos, Modula-3 apresenta polimorfismos
classificados como universais, exemplos de polimorfismos do tipo "ad-hoc" e objetos podem ser encontrados
em outras linguagens como C++.
4.1. O 5UE SIGNIFICA POLIMORFISMO
Polimorfismo, do grego: muitas formas. Polimorfismo a capacidade de um operador executar a ao
apropriada dependendo do tipo do operando. Aqui operando e operador esto definidos num sentido mais geral:
operando pode significar argumentos atuais de um procedimento e operador o procedimento, operando pode
significar um objeto e operador um mtodo, operando pode significar um tipo e operador um objeto deste tipo.
4.1.1. SOBRECARGA DE M+TODOS
Modula-3 no oferece este tipo de polimorfismo que pode ser considerado com "ad-hoc". Este tipo de
polimorfismo permitiria a existncia de vrios procedimentos e mtodos de mesmo nome, porm com
assinaturas levemente diferentes, variando no nmero e tipo de argumentos. Ficaria a cargo do compilador
escolher de acordo com as listas de argumentos os procedimentos ou mtodos a serem executados.
4.1.2. REDEFINIO DE UMA FUNO MEMBRO PARA UMA CLASSE :ERDEIRA
.Este exemplo j foi apresentado em 2.1.3. Tambm trata-se de um polimorfismo, pode ser classificado como
polimorfismo de incluso.
4.1.4. BCOPL CONSTRUCTORB
A funo membro ponto(ponto& a); um copy constructor, alm disso tem o mesmo nome que ponto(float
dx,float dy);. Tal duplicao de nomes pode parecer estranha, porm C++ permite que eles coexistam para uma
classe porque no tem a mesma assinatura (nome+argumentos). sto se chama sobrecarga de funo membro,
o compilador sabe distinguir entre esses dois construtores. Outras funes membro, no s construtores
podero ser redefinidas, ou sobrecarregadas para vrios argumentos diferentes, esse recurso um
polimorfismo do tipo "ad-hoc".
O que interessante para ns o fato de o argumento do construtor ponto(pontoY a); ser da mesma
classe para qual o construtor foi implementado, esse o chamado "copy constructor". Ele usa um objeto de seu
tipo para se inicializar. Outros mtodos semelhantes seriam: circulo(circuloY a); mouse(mouseY
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
59 - 03/06/14
d);. mplementar copy constructor pode ser muito importante, lembre-se dos problemas com cpias de
objetos apresentados em 1.5.3.5.
#include <iostream.h>
struct ponto
{
float x;
float y;
ponto(float afloat %);
//construtor tam%em pode ser inline ou nao
ponto(pontoY a); //copy constructor
void mostra(void);
void move(float dxfloat dy);
};
ponto((ponto(float afloat %)
{
x"a;
y"%;
}
ponto((ponto(pontoY a)
{
x"a.x;
y"a.y;
}
void ponto((mostra(void)
{cout << &)(& << x << & +(& << y << endl;}
void ponto((move(float dxfloat dy)
{
x-"dx;
y-"dy;
}
void main()
{
ponto ap($.$$.$);
ap.mostra();
ap.move(#.$#.$);
ap.mostra();
ponto ap4(ap);
ap4.mostra();
}
C!%e't(#)!s&
Observe o cdigo:
ponto::ponto(ponto& a)
{
x=a.x;
y=a.y;
}
Essa funo membro, esse mtodo, pertence a outro objeto que no o argumento a, ento para distinguir o
atributo x deste objeto, do atributo x de a usamos a.x e simplesmente x para o objeto local (dono da funo
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
60 - 03/06/14
4.1.7. SOBRECARGA DE FUNO EM C++.
Este tpico apresenta exemplos importantes para o estudo do restante do tutorial.
Sobrecarga "Overloading" de funo um tipo de polimorfismo classificvel como ad-hoc. C++ permite que
funes de mesmo nome tenham parmetros distintos. Este exemplo mostra a sobrecarga da funo abs que
calcula o valor absoluto de um nmero:
//header file funcover.h
float a%s(float a);
int a%s(int a);
//implementation file
#include &funcover.h&
float a%s(float a)
{
if (a>$.$) return a;
else return Ma;
}
int a%s(int a)
{
if (a>$) return a;
else return Ma;
}
#include <iostream.h>
#include &funcover.h&
void main()
{
int i#;
float f#;
cout << a%s(int(M#$))<<endl;
cout << a%s(float(M#$.#))<<endl;
f#"MS.#;
i#"T.$;
cout << a%s(f#) << endl;
cout << a%s(i#) << endl;
}
Resulta! ! "#!$#a%a&
10
10.1
9.1
8
C!%e't(#)!s&
cout << abs(float(-10.1))<<endl;
Perceba que quando chamamos a funo abs para um valor (-10.1) e no uma varivel (possui um tipo), temos
que fazer a converso explcita para o compilador, porque este no sabe decidir qual funo chamar (para float
ou int), mesmo estando presente o ponto indicando a casa decimal.
Observe que -10.1 pode ser double ou float. Enquanto que 10 pode ser long ou int.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
61 - 03/06/14
No exemplo 4 veremos sobrecarga de operador, que semelhante a sobrecarga de funo. Observe que os
operadores * - e at mesmo os operadores de extrao << >> usados com cout so exemplos de sobrecarga de
operadores. Eles j esto definidos com a mesma forma para um conjunto restrito de tipos.
4.1.=. BDEFAULT ARGUMENTSB9 6ALORES SUGESTO
Valores sugesto, argumentos padro ou "default arguments", so nomes para um tipo de polimorfismo ad-hoc
fornecido por C++.
Para demonstrar o uso de default values vamos relembrar o nosso tipo abstrato de dados frao de 1.2.1.4. Um
de seus construtores tinha a seguinte forma: fracao() {num=0; den=1;} //construtor vazio,default enquanto que o
construtor normal da frao tinha a seguinte forma: fracao(long t,long m);.
"Default arguments" nos d a oportunidade de fundir esses dois construtores num s resultando no seguinte:
fracao(long t=0,long m=1); {num=t; den=m;} onde 1 e 0 so valores sugesto para os argumentos.
A instanciao fracao a( ) segundo aquele nico construtor cria : (0/1)
A instanciao fracao b(1) segundo aquele nico construtor cria: (1/1)
A instanciao fracao c(#4) segundo aquele nico construtor cria: (#/4)
Re$#as "a#a a /#)a1;! e BDe.ault a#$u%e'tsB&
No so permitidas declaraes do tipo fracao(long t=0,long m); uma vez que voc inseriu um argumento
padro na lista de argumentos todos a direita deste tambm devero ter seus valores sugesto. Ento, por esta
regra a nica alternativa restante para o tipo frao seria fracao(long t,long m=1);
4.1.?. SOBRECARGA DE OPERADOR
O tipo abstrato de dados frao (verso completa) de 1.2.4.4 possui vrios operadores sobrecarregados.
Algumas sobrecargas deste exemplo envolvem o uso da palavra chave friends que voc no aprendeu ainda,
portanto atenha-se aos exemplos que no contm essa palavra reservada.
Extenso da classe vetor de 1.5.3.6 para incluir um iterador. Este exemplo j apresentado com templates.
TE")/!s a3!#a!s&
Sobrecarga de operador.
//header file para classe vetor( vet.h
#include <iostream.h>
#include <stdli%.h> //exit(#)
const int inicio"$; //inicio do vetor
class vetor{
private(
float1 v; //pode ser qualquer tipo que atenda as operacoes < > "
int tamanho;
pu%lic(
vetor (int tamanho) ;
floatY operatorQR (int i);
float maximo(); //acha o valor maximo do vetor
int primeiro(void);
int ultimo(void);
};
vetor((vetor (int tam)
{v"neE floatQtamR; tamanho"tam;}
int vetor((primeiro (void)
{return inicio;}
int vetor((ultimo (void)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
62 - 03/06/14
{return tamanhoM#;}
floatY vetor((operatorQR(int i)
{
if (i<$ ZZ i>"tamanho)
{cout << &Dora dos limites. =xit pro,ram&; exit(#);}
return vQiR;
}
float vetor(( maximo(void)
{int candidato"inicio;
for (int i"inicio;i<tamanho;i--)
if (vQiR>vQcandidatoR) candidato"i;
return vQcandidatoR;}
E-"l)/a1;! as !"e#a12es9 as .u'1;! %e%3#!s ! )te#a!# Cet!#&
iteradorvetor(vetor & v); :Construtor, j cria o iterador de vetor inicializando-o para apontar para o comeo do
vetor.
virtual int comeca();: nicializa o iterador para o comeo do vetor.
virtual int operator!(); & Verifica se a iterao no chegou no fim do vetor: 1 indica que no chegou, 0 indica que
chegou no fim do vetor.
virtual int operator ++ ();: Faz o iterador mover adiante uma posio.
virtual float operator() (); :Retorna o elemento daquela posio do vetor.
virtual void operator= (float entra); : Atribui a posio atual do vetor.
int pos(); : Retorna a posio (ndice) do vetor em que o iterador se encontra, no virtual porque no faz
sentido para um iterador de rvore por exemplo.
//it.h arquivo com definicoes do iterador.
class iteradorvetor
{
private(
vetor vetorref;
int posicao;
pu%lic(
iteradorvetor(vetor Y v);
int comeca();
int operator.();
int operator -- ();
float operator() ();
void operator" (float entra);
int pos(); //retorna posicao nH virtual pq nH fa3 sentido p/ arvore por ex.
};
int iteradorvetor((pos()
{
return posicao;
}
int iteradorvetor((operator.()
{
return posicao<"vetorref.ultimo();
}
iteradorvetor((iteradorvetor(vetor Y vet)(vetorref(vet)
{
comeca();
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
63 - 03/06/14
}
int iteradorvetor((comeca()
{
posicao"vetorref.primeiro();
return operator.();
}
int iteradorvetor((operator --()
{
posicao--;
return operator.();
}
void iteradorvetor((operator"(float entra)
{
vetorrefQposicaoR"entra;
}
float iteradorvetor((operator() ()
{
float copia;
copia"vetorrefQposicaoR;
return copia;
}
P#!$#a%a "#)'/)"al9 testes&
#include <iostream.h>
#include &vet.h&
#include &it.h&
main()
{
int repete"$;
int ind;
float item;
vetor meu(I);
iteradorvetor itmeu(meu);
for (itmeu.comeca();.itmeu;--itmeu)
{
cout << &=ntre com valor da posicao(& << itmeu.pos() << &*n&;
cin >> item;
itmeu"item;
}
for (itmeu.comeca();.itmeu;--itmeu) cout<< itmeu()<< & &;
cout << &*n=ntre com o indice da posicao a atuali3ar(*n&;
cin >> ind;
cout << &=ntre com o valor a incluir(&;
cin >> item;
meuQindR"item;
for (int ["meu.primeiro();[<"meu.ultimo();[--) cout<< meuQ[R<< & &;
cout <<endl << &9aximo(& << meu.maximo();
return $;
}
C!%e't(#)!s&
O significado do operador voc que define, mas recomendvel dar ao operador um significado prximo ao j
definido na linguagem. Por exemplo: o operador + seria timo para representar a concatenao de dois objetos
do tipo string. A sintaxe de cada operador fixa: nmero de operandos, precedncia... O leitor pode aprender
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
64 - 03/06/14
melhor tais regras gravando ou relendo os exemplos de sobrecarga de cada operador e modificando-os quando
necessrio.
4.2. CLASSES ABSTRATAS E CONCRETAS
4.2.1. CLASSE ABSTRATA ITERADOR
Neste tpico voc ver que podem existir classes que apenas definem protocolos ou interfaces para o uso e
no podem ser instanciadas, as classes filhas que herdam sua interface que so instanciveis.
Neste exemplo vamos repetir o programa de 3.1.6, s que iremos incluir uma classe base abstrata para o
iterador.
O iterador de vetor definido por herana public da classe base abstrata de iteradores. Esta classe define o
protocolo, a interface de iteradores para listas e outras estruturas.
Perceba que algumas funes membro da classe base so desprovidas de implementao, porm nada impede
que voc coloque como cdigo dessas funes membro uma mensagem de erro do tipo &=rro classe
%ase n0o deve ser instanciada.& , como foi feito em alguns casos.
//exvetitU arquivo com definicoes do iterador.
class iterador{ //classe %ase a%strata
pu%lic(
int comeca(void)
{cout << &=rro classe a%strata.&;}
float operator()()
{cout << &=rro classe a%strata.&; return $;}
int operator.(void) {return $;}
int operator --() {return $;}
void operator"(float entra) {;}
};
class iteradorvetor(pu%lic iterador
{
private(
vetor vetorref;
int posicao;
//classe filha acrescentando dados mem%ro
pu%lic(
iteradorvetor(vetor Y v);
int comeca();
int operator.();
int operator -- ();
float operator() ();
void operator" (float entra);
int pos();
//retorna posicao nH virtual pq nH fa3 sentido p/ arvore por ex.
//esta eF uma funcao mem%ro acrescentada pela classe filha
};
int iteradorvetor((pos()
{
return posicao;
}
int iteradorvetor((operator.()
{
return posicao<"vetorref.ultimo();
}
iteradorvetor((iteradorvetor(vetor Y vet)(vetorref(vet)
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
65 - 03/06/14
comeca();
}
int iteradorvetor((comeca()
{
posicao"vetorref.primeiro();
return operator.();
}
int iteradorvetor((operator --()
{
posicao--;
return operator.();
}
void iteradorvetor((operator"(float entra)
{
vetorrefQposicaoR"entra;
}
float iteradorvetor((operator() ()
{
float copia;
copia"vetorrefQposicaoR;
return copia;
}
Os demais arquivos so identicos aos do exemplo sobre vetores de 3.1.6.
//header file para classe vetor
#include <iostream.h>
#include <stdli%.h> //exit(#)
const int inicio"$; //inicio do vetor
class vetor{
private(
float1 v; //pode ser qualquer tipo que atenda as operacoes < > "
int tamanho;
pu%lic(
vetor (int tamanho) ;
floatY operatorQR (int i);
float maximo(); //acha o valor maximo do vetor
int primeiro(void);
int ultimo(void);
};
vetor((vetor (int tam)
{v"neE floatQtamR; tamanho"tam;}
int vetor((primeiro (void)
{return inicio;}
int vetor((ultimo (void)
{return tamanhoM#;}
floatY vetor((operatorQR(int i)
{
if (i<$ ZZ i>"tamanho)
{cout << &Dora dos limites. =xit pro,ram&; exit(#);}
return vQiR;
}
float vetor(( maximo(void)
{int candidato"inicio;
for (int i"inicio;i<tamanho;i--)
if (vQiR>vQcandidatoR) candidato"i;
return vQcandidatoR;}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
66 - 03/06/14
#include <iostream.h>
#include &exvetU.h&
#include &exvetitU.h&
main()
{
int repete"$;
int ind;
float item;
vetor meu(I);
iteradorvetor itmeu(meu);
for (itmeu.comeca();.itmeu;--itmeu)
{
cout << &=ntre com valor da posicao(& << itmeu.pos() << &*n&;
cin >> item;
itmeu"item;
}
for (itmeu.comeca();.itmeu;--itmeu) cout<< itmeu()<< & &;
cout << &*n=ntre com o indice da posicao a atuali3ar(*n&;
cin >> ind;
cout << &=ntre com o valor a incluir(&;
cin >> item;
meuQindR"item;
for (int ["meu.primeiro();[<"meu.ultimo();[--) cout<< meuQ[R<< & &;
cout <<endl << &9aximo(& << meu.maximo();
return $;
}
Resulta! ! "#!$#a%a&
Entre com valor da posicao:0
2
Entre com valor da posicao:1
35
Entre com valor da posicao:2
82
Entre com valor da posicao:3
2
Entre com valor da posicao:4
3
2 35 82 2 3
Entre com o indice da posicao a atualizar:
0
Entre com o valor a incluir:1
1 35 82 2 3
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
67 - 03/06/14
Maximo:82
4.2.2. ACOPLAMENTO DE MENSAGENS
J dissemos que um objeto de uma classe filha garante no mnimo o comportamento "behaviour" de seu pai.
Por este motivo podemos atribuir um objeto da classe filha a uma varivel da classe pai, mas no o contrrio.
Acoplamento dinmico mostrar que possvel fazer com que o compilador execute a implementao desejada
de uma funo membro redefinida para classes herdeiras, mesmo no caso de chamada de funo membro para
uma varivel de um supertipo (classe pai) contendo um objeto de um subtipo (classe filha). sto nos permitir
construir listas hetorogneas 3.2.4.
4.2.2.1. CASO ESTDTICO
#include <iostream.h>
class pai {
pu%lic(
void print(void)
{cout << &@ou da classe pai&<<endl;}
};
class filho(pu%lic pai
{
private(
pu%lic(
void print(void)
{cout << &@ou da classe filha& << endl;}
};
void main()
{
filho ef#;
//estatica filho numero #
pai ep#;
//estatica pai numero #
ef#.print();
//variavel estatica contendo filho
ep#.print();
//variavel estatica contendo pai
ep#"ef#;
//variavel estatica do tipo pai contendo filho convertido no pai
ep#.print();
}
D)a$#a%a as /lasses&
A classe filha garante no mnimo o mesmo comportamento, "behaviour" que a classe pai, podendo acrescentar
ou redefinir parte do que foi herdado. Por este motivo, uma varivel da classe pai pode receber um objeto da
classe filha, o comportamento da classe pai fica garantido e o restante (o que a classe filha acrescentou)
perdido. J uma varivel da classe filha no pode receber um objeto da classe pai, porque as funes membro
acrescentadas passam a no fazer sentido.
Resulta! ! "#!$#a%a&
Sou da classe filha
Sou da classe pai
Sou da classe pai
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
68 - 03/06/14
E-"l)/a1;! ! "#!$#a%a9 "ass! a "ass!&
filho ef1;
Declarao de uma varivel da classe filha.
pai ep1;
Declarao de uma varivel da classe pai, menor ou igual quantidade de membros que a filha.
ef1.print();
Mostra a funo da classe filha, a qual pertence ef# e seu contedo.
ep1.print();
Mostra a funo da classe de ep# que a classe pai.
ep1=ef1;
Atribui o contedo de ef# a ep#, ou seja atribui um filho a um pai. O filho tem os dados membros e funes
membros acrescentados, descartados e se torna do tipo pai. Essa converso irreversvel no caso.
ep1.print();
Mostra a funo da classe de ep1 que a classe pai, a mesma de seu contedo.
4.2.2.2. DINFMICO SEM 6IRTUAL
#include <iostream.h>
class pai {
pu%lic(
void print(void)
{cout << &@ou da classe pai&<<endl;}
};
class filho(pu%lic pai
{
private(
pu%lic(
void print(void)
{cout << &@ou da classe filha& << endl;}
};
void main()
{
filho ef#;
//estatica filho numero #
pai ep#;
//estatica pai numero #
pai1 pp#;
//ponteiro pai numero #
ef#.print();
//variavel estatica contendo filho
ep#.print();
//variavel estatica contendo pai
pp#"Yep#;
pp#M>print();
//ponteiro de paiapontando para pai
pp#"Yef#;
pp#M>print();
//ponteiro de pai apontando para filho
ep#"ef#;
//variavel estatica do tipo pai contendo filho convertido no pai
ep#.print();
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
69 - 03/06/14
}
Resulta! ! "#!$#a%a&
Sou da classe filha
Sou da classe pai
Sou da classe pai
Sou da classe pai
Sou da classe pai
C!%e't(#)!s&
Note que a funo membro executada escolhida de acordo que a varivel e no de acordo com o contedo
desta, da mesma forma que no exemplo anterior.
4.2.2.4. DINFMICO COM 6IRTUAL
#include <iostream.h>
class pai {
pu%lic(
virtual void print(void)
{cout << &@ou da classe pai&<<endl;}
};
class filho(pu%lic pai
{
private(
pu%lic(
virtual void print(void)
{cout << &@ou da classe filha& << endl;}
};
void main()
{
filho ef#;
//estatica filho numero #
pai ep#;
//estatica pai numero #
pai1 pp#;
//ponteiro pai numero #
ef#.print();
//variavel estatica contendo filho
ep#.print();
//variavel estatica contendo pai
pp#"Yep#;
pp#M>print();
//ponteiro de paiapontando para pai
pp#"Yef#;
pp#M>print();
//ponteiro de pai apontando para filho
ep#"ef#;
//variavel estatica do tipo pai contendo filho convertido no pai
ep#.print();
}
Resulta! ! "#!$#a%a&
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
70 - 03/06/14
Sou da classe filha
Sou da classe pai
Sou da classe pai
Sou da classe filha
Sou da classe pai
C!%e't(#)!s&
Perceba que virtual faz com que a funo membro a executar seja escolhida de acordo com o contedo da
varivel ou ponteiro e no de acordo com o tipo da varivel ou ponteiro (repositrios). Virtual no tem efeito no
uso esttico de objetos, ou seja a funo membro ser escolhida de arcordo com o tipo da varivel (repositrio).
4.2.4. CONTAS BANCDRIAS
Neste programa exemplo vamos definir uma classe abstrata chamada conta. Esta classe define a interface de
contas bancrias, que se constitui das operaes: deposita, saca, get_saldo, get_jurosn (juros quando saldo
est negativo), get_jurosp (juros quando o saldo est positivo) e computa (calcula juros). Todos as funes
membro so "virtuais" exceto destrutor .
Preste ateno nas especificaes a seguir elas so detalhadas e importantssimas para o entendimento do
programa:
Da classe base abstrata descrita acima, criamos duas classes concretas com as seguintes propriedades:
1-Conta corrente:
-Neste tipo de conta as computaes dos juros so feitas pelo banco diariamente.
-Permite taxa de juros diferente para saldos negativos e positivos.
-Possui um atributo menor que zero chamado l)%)te. Saques que levem o saldo abaixo deste valor so
recusados. Esta definio acima no implica que o saldo tenha que estar sempre acima de l)%)te. Ele s vai
para valores menores que se os juros da dvida o fizerem e no o cliente.
-O valor de l)%)te definido na criao da conta, instanciao.
-Fica claro que este tipo de conta permite saldos negativos.
. -A taxa de juros para saldo positivo zero ou seja, no h rendimento.
2-Poupana:
-Possui uma data de aniversrio, s neste dia que se computa juros ou seja mensalmente.
-Os juros acrescentados so referentes ao saldo aps a ltima computao, isto significa que depsitos
intermedirios no rendem juros.
-Se houver algum saque que no seja no dia da computao os juros referentes a aquele ms so cancelados.
-S permitido saldo maior ou igual a zero.
Outra classe foi criada no programa: a classe data que armazena datas quaisquer. Por questes de
simplicidade a classe data que simplesmente uma classe auxiliar foi implementada com o mnimo necessrio
para o funcionamento e demonstrao do programa. A melhoria desta classe sugerida como exerccio.
Tpicos abordados: Funes membro virtual e pure virtual. Objetos constantes.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
71 - 03/06/14
//header file for conta.h
//todas as funcoes rece%em uma data porque o extrato presisa disso.
const float !p".$I; /1!uros padrao1/
const float va3io"$.$;
const float !nulo"$.$;
const float lmin"MP$$.$;
enum Coolean{D8B@=<';=};
typedef float dinh;
float a%s(float a); //funcao valor a%soluto
class data{ //definir outras operacoes ela%orar mais
private(
int dia;
int mes;
int ano;
pu%lic(
data() {dia"#;mes"#;ano"SI;} //default constructor importante para a,re,acao
data(int dint mint a) {dia"d;mes"m;ano"a;}
int ,et2dia(void) {return dia;}
int ,et2mes(void) {return mes;}
int ,et2ano(void) {return ano;}
};
const data ddef(##S$); //o%!eto constante;
class conta{ //pure virtual functions in a%stract %ase class
protected(
dinh saldo; //esse eF o dinheiro na conta.
float !urosp; //!uros p/ saldo positivo
float !urosn; //!uros p/ saldo ne,ativo
pu%lic(
//pure virtual functions in a%stract %ase class
conta (dinh quantia"va3iofloat taxap"!pfloat taxan"!pdata dd"ddef);
virtual Coolean computa(data dd)"$; //computa !uros da conta
virtual dinh ,et2saldo(data dd)const"$; //retorna conteudo da conta
virtual float ,et2!urosn(data dd)const"$; //criar as respectivas funcoes set(
set2!uros
virtual float ,et2!urosp(data dd)const"$;
virtual Coolean deposita(dinh quantiadata dd)"$;
virtual dinh saca(dinh quantiadata dd)"$;
Hconta(){};
};
class contacorrente(pu%lic conta{
private(
dinh lim; //saques que levam saldo para %aixo deste limite sao %loqueados.
pu%lic(
contacorrente(dinh quantia"va3iofloat taxan"!pdinh min"lmindata dd"ddef); //so
computa qdo ne,.
Coolean computa(data dd); //para esse tipo de conta eF diario. (poupanca mensal)
dinh ,et2saldo(data dd)const; //retorna conteudo da conta
float ,et2!urosn(data dd)const; //criar as respectivas funcoes set( set2!uros
float ,et2!urosp(data dd)const;
Coolean deposita(dinh quantiadata dd);
dinh saca(dinh quantiadata dd);
Hcontacorrente(){}; //pode deletar deque com operacoes so%re conta (extrato)
};
class poupanca(pu%lic conta{
private(
data aniversario; //dia do mes que a poupanca fa3 aniversario.
Coolean computar; //#(computar so%re ultimo $(rendimento perdido saque
dinh ultimo; //os !uros sao so%re o valor depois da ultima computacao.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
72 - 03/06/14
//o que depositou nao importa se sacou perdeu rendimento
pu%lic(
poupanca(dinh quantia"va3iofloat taxap"!pdata dd"ddef); //mensalmente
Coolean computa(data dd); // Coolean( 'endimento nao foi perdido]
dinh ,et2saldo(data dd)const; //retorna conteudo da conta
float ,et2!urosn(data dd)const; //criar as respectivas funcoes set( set2!uros
float ,et2!urosp(data dd)const;
Coolean deposita(dinh quantiadata dd);
dinh saca(dinh quantiadata dd);
Hpoupanca(){}; //pode deletar deque com operacoes so%re conta (extrato)
};
//file conta.cpp
#include &conta4.h&
float a%s(float a)
{
if (a<$.$) a"Ma;
return a;
}
conta((conta(dinh quantiafloat taxapfloat taxandata dd)
{
saldo"a%s(quantia);
!urosp"a%s(taxap);
!urosn"a%s(taxan);
}
poupanca((poupanca(dinh quantiafloat taxapdata dd)(
conta(quantiataxap!nulodd)
{aniversario"dd; computar"<';=; ultimo"a%s(quantia);};
Coolean poupanca((computa(data dd)
{
if (aniversario.,et2dia()""dd.,et2dia())
if (computar) {saldo"ultimo1!urosp-saldo;return <';=;}
else { computar"<';=; ultimo"a%s(saldo); }
return D8B@=;
}
dinh poupanca((,et2saldo(data dd)const
{return saldo;}
float poupanca((,et2!urosp(data dd)const
{ return !urosp; }
float poupanca((,et2!urosn(data dd)const
{ return !urosn; }
Coolean poupanca((deposita(dinh quantiadata dd)
{ saldo-"a%s(quantia);
return <';=;}
dinh poupanca((saca(dinh quantiadata dd)
{
if ((saldoMa%s(quantia))>va3io)
{saldoM"a%s(quantia); computar"D8B@=; return quantia;}
else return va3io;
}
contacorrente((contacorrente(dinh quantiafloat taxandinh mindata dd)(
conta(quantia!nulotaxandd)
{if (min<va3io) lim"min; else lim"Mmin;}
Coolean contacorrente((computa(data dd) //so computo !uros ne,ativos.
{
if (saldo<va3io) saldo"saldo1!urosn-saldo;
else saldo"saldo1!urosp-saldo;
return <';=;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
73 - 03/06/14
}
dinh contacorrente((,et2saldo(data dd) const
{return saldo;}
float contacorrente((,et2!urosn(data dd) const
{return !urosn;}
float contacorrente((,et2!urosp(data dd) const
{return !urosp;}
Coolean contacorrente((deposita(dinh quantiadata dd)
{
saldo-"quantia;
return <';=;
}
dinh contacorrente((saca(dinh quantiadata dd)
{
quantia"a%s(quantia);
if ((saldoMquantia)>lim)
{ saldoM"quantia; return quantia;}
else return va3io;
}
//main file.
#include <iostream.h>
#include &conta4.h&
main()
{
data ho!e(U#$SI);
contacorrente minhacc(#JP$.JP$.#MI$$.$ho!e);
poupanca minhap(#I$$.$$$.#ho!e);
cout << &@aldo(& <<minhacc.,et2saldo(ho!e)<<endl;
minhacc.deposita(#$.$$ho!e);
cout << &@aldo apos depositar #$.$$(&<<minhacc.,et2saldo(ho!e)<<endl;
minhacc.computa(ho!e);
cout << &@aldo apos computar(& <<minhacc.,et2saldo(ho!e)<<endl;
minhacc.saca(#I$$.$$ho!e);
cout << &@aldo apos sacar(& << minhacc.,et2saldo(ho!e)<<endl;
minhacc.computa(ho!e);
cout << &@aldo apos computar(& << minhacc.,et2saldo(ho!e) <<endl;
cout << &<axa de !uros(& << minhacc.,et2!urosn(ho!e)<<endl;
cout << endl;
cout << &8,ora a poupanca(&;
cout << &@aldo apos criacao(& << minhap.,et2saldo(ho!e) << endl;
cout << &_uros de saldo positivo(& << minhap.,et2!urosp(ho!e)<< endl;
cout << &:omputando(& << endl;
minhap.computa(ho!e) ;
cout << &@aldo apos computa(& << minhap.,et2saldo(ho!e) << endl;
cout << &'etirando I$$.$$(& <<endl;
minhap.saca(I$$.$$ho!e) ;
cout << &@aldo apos retirada(& << minhap.,et2saldo(ho!e) << endl;
cout << &:omputando(&<<endl;
minhap.computa(ho!e);
cout << &@aldo apos computa(& << minhap.,et2saldo(ho!e) << endl;
cout << &>epositando#$$ e :omputando(&<<endl;
minhap.deposita(#$$.$$ho!e);
minhap.computa(ho!e);
cout << &@aldo apos computa(& << minhap.,et2saldo(ho!e) << endl;
cout << &'etirando mais do que pode(4$$$.$$& << endl;
minhap.saca(4$$$.$$ho!e);
cout << &@aldo apos saca 4$$$.$$(& << minhap.,et2saldo(ho!e) << endl;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
74 - 03/06/14
return $;
}
Resulta! e teste ! "#!$#a%a&
Saldo:1340.34
Saldo apos depositar 10.00:1350.34
Saldo apos computar:1350.34
Saldo apos sacar:-149.66
Saldo apos computar:-164.626
Taxa de juros:0.1
Agora a poupanca:Saldo apos criacao:1500
Juros de saldo positivo:0.1
Computando:
Saldo apos computa:1650
Retirando 500.00:
Saldo apos retirada:1150
Computando:
Saldo apos computa:1150
Depositando100 e Computando:
Saldo apos computa:1365
Retirando mais do que pode:2000.00
Saldo apos saca 2000.00:1365
C!%e't(#)!s&
Observe que objetos da classe base no podem ser criados, voc no pode ter um objeto instanciado, mas ela
pode ser usada. Declarar um ponteiro: conta1 , no significa criar um objeto. Esse ponteiro pode referenciar
qualquer objeto da hierarquia (conta corrente , poupana) , veremos seu uso mais tarde.
Cu#)!s)ae&
Veja a importncia da criao de componentes de software seguros, de fcil modificao e reutilizveis:
Muitos programas que tinham que fazer uma representao de datas esto sendo revistos devido a mudana
do sculo e outros provavelmente falharo devido a esta mudana. Seja pela restrio da faixa de valores de
anos com mximo em 2000 ou mesmo por outros motivos que no levassem este fator em conta, como a
subtrao entre dois anos distintos exemplo 2001 e 1999 armazenados na forma 01 e 99.
O exerccio 5 pede que voc melhore a classe data apresentada neste exemplo. Com um pouquinho de
pesquisa voc pode criar meios de checar anos bissextos (%4), meses com nmeros de dias diferentes e
"viradas" de sculo.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
75 - 03/06/14
4.2.7. LISTA :ETEROGHNEA DE CONTAS BANCDRIAS.
Lista heterognea de contas bancrias de exemplo anterior, obteno do saldo total das contas corrente e
poupanas da lista (no caso vetor).
TE")/!s a3!#a!s&
BDynamic binding", no aborda type casting, vai ser abordado num programa mais completo: a simulao
dirigida a eventos de 4.6.2 .
//pro,rama principal
#include <iostream.h>
#include &conta4.h& ///
const int tamanho"J;
main()
{
dinh soma"$.$;
contacorrente cc#(I$$.$$$.#MP$$); //@8B>6_;'6@BA9A<= ?=7
contacorrente cc4(I$$.$$$.#IMP$$);
poupanca p#(I$$.$$$.#); //@8B>6 _;'6@
conta1 lhetero,eneaQtamanhoR"{Ycc#Ycc4Yp#}; //lista hetero,enea
for (int i"$;i<tamanho;i--) soma-"lhetero,eneaQiRM>,et2saldo(ddef);
cout << &<otal arma3enado nas contas(& << soma <<endl;
return $;
}
7. TMPICOS A6ANADOS
Tpicos avanados apresenta recursos extremamente teis para programao orientada a objetos, por isso
convm ler este tpico somente quando voc tiver uma boa base de programao C++. Adquira prtica.
A ordem em que os exemplos so apresentados semelhante a ordem de tpicos inicial. Como tpico
avanado de Encapsulamento temos friends, como tpico avanado de herana temos herana mltipla, como
tpico avanado de polimorfismo, temos polimorfismo paramtrico. Os demais tpicos no esto diretamente
relacionados com os anteriores.
7.1. FRIENDS
Friends permite que uma classe toda ou uma funo membro acesse atributos encapsulados de outra classe.
Por este motivo, friends representa uma quebra do encapsulamento e deve portanto ser usado com muita
cautela. No raro programadores descobrem que o uso de certos princpios de orientao a objetos evita
programar usando demasiadamente friends. Se voc vai aplicar este recurso, analise bem as outras
possibilidades, cheque outras abordagens antes.
Novamente nos deparamos com um qualificador ou "specifier", mas este tem uma diferena, no basta dizer
que uma classe ou funo membro amiga, &friend& preciso dizer de que classe ela amiga
Friends muito usado em conjunto com operadores. Operadores so frequentemente usados para implementar
operaes entre tipos enquanto que funes membro comuns so mais usadas para passagem de mensagens
alterando o estado de um nico objeto, segundo alguns parmetros, normalmente tipos simples.
7.1.1. UMA CLASSE PERMITINDO ACESSO A OUTRA
Suponha que voc est trabalhando em conjunto com um colega no desenvolvimento de um software. Voc faz
a interface grfica enquanto que seu colega est implementado as classes estritamente usurias da interface
grfica.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
76 - 03/06/14
Como seu colega no sabe usar sua interface grfica ainda, ele define algumas classes dele como friends de
suas classes de caixas de dilogos e janelas. Assim voc ganha acesso as definies private e public dele nas
suas classes. Ele s precisa perguntar a voc quais os nomes das suas classes.
Como voc desconhece a implementao das classes de seu colega, ele define pensando em voc e tambm
por razes de portabilidade, funes membro que retornam os dados membros mais teis aos usurios das
classes. Porm estas funes no retornam todos os dados membros porque alguns objetos que ele est
definindo so estruturas de alocao dinmica como rvores e muito difcil prever que tipo de acesso ser
feito nas estruturas.
Este o tema do exemplo seguinte, s que no iremos definir nenhuma interface grfica, vamos apenas usar
cout simulando uma sada de tela mais complicada, como por exemplo numa caixa de dialogo. Nosso objeto
no define estruturas de alocao dinmica nenhuma, afinal o exemplo tem que ser simples e objetivo.
#include <iostream.h>
class relo,io
{
friend class caixa2de2mensa,em;
//permitiu acesso as definicoes private e pu%lic
private(
int hora;
int minuto;
int se,undo;
//atri%utos private encapsulados
pu%lic(
relo,io(int hint mint s)
{hora"h; minuto"m; se,undo"s;}
} ;
class caixa2de2mensa,em{
pu%lic(
void imprime(relo,io a)
{
cout << a.hora << &(& << a.minuto << &(& << a.se,undo << endl;
}
} ;
void main()
{
relo,io meurolex(##J$#$);
caixa2de2mensa,em ativa;
ativa.imprime(meurolex);
}
Resulta! ! "#!$#a%a&
11:30:10
Cu#)!s)ae&
Existem "libraries" em C++ que permitem programar em ambientes grficos como o Windows sem saber muitos
detalhes. Estas "libraries" definem objetos como caixas de dialogo, gerenciadores de eventos, etc. O uso agora
diferente do descrito no exemplo: O programador s vai utilizar os recursos grficos padro definidos pela
"libraries". Os objetos definidos para uso na interface grfica so agregados ao seu programa e podem ser
chamados de dentro das implementaes das funes membro das suas classes.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
77 - 03/06/14
7.1.2. OPERADORES E FRIENDS
Vamos tomar o exemplo do tipo abstrato de dados frao de 1.4.1 e acrescentar sobrecarga de operador e
funes friends. Fica faltando somente tratamento de excees que sugerido como exerccio no captulo
respectivo.
TE")/!s a3!#a!s&
Sobrecarga de operador, "copy constructor" ,funes friends. uma implementao bastante completa e
portvel de um TAD, use como referncia para sintaxe de sobrecarga de operadores.
//=ste pro,rama implementa o tipo fracao.
#ifndef 6D2K
//diretivas do compilador
#define 6D2K
lon, mdc(lon, nlon, d)
//maximo divisor comum
//metodo de =uclides
{
if (n<$) n"Mn;
if (d<$) d"Md;
Ehile (d."$) {
lon, r"n N d;
// N"96>
n"d;
d"r;
}
return n;
};
class fracao {
private(
lon, num;
lon, den;
pu%lic(
void simplifica(void);
//simplificacao
fracao(fracao Yt);
//copy constructor
fracao() {num"$; den"#;}
//construtor va3io.
fracao(const lon, tconst lon, m);
fracao(const lon, t) {num"t;den"#;}
Hfracao() {};
//?ao precisa fa3er nada
lon, ,et2num(void) {return num;}
lon, ,et2den(void) {return den;}
//operacoes matematicas %asicas
friend fracao operator- (const fracaoY fconst fracaoY !);
friend fracao operatorM (const fracaoY fconst fracaoY !);
friend fracao operator1 (const fracaoY fconst fracaoY !);
friend fracao operator/ (const fracaoY fconst fracaoY !);
//operadores de comparacao
friend int operator"" (const fracaoY sconst fracaoY t);
friend int operator." (const fracaoY sconst fracaoY t);
friend int operator>" (const fracaoY sconst fracaoY t);
friend int operator<" (const fracaoY sconst fracaoY t);
friend int operator> (const fracaoY sconst fracaoY t);
friend int operator< (const fracaoY sconst fracaoY t);
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
78 - 03/06/14
//operadores de atri%uicao
fracaoY operator" (const fracaoY t);
fracaoY operator-" (const fracaoY t);
fracaoY operatorM" (const fracaoY t);
fracaoY operator1" (const fracaoY t);
fracaoY operator/" (const fracaoY t);
//operadores de input output
friend istreamY operator>> (istreamY cifracaoY f);
friend ostreamY operator<< (ostreamY coconst fracaoY f);
//operadores de conversao de tipos
operator dou%le() const;
operator float() const;
operator lon,() const;
operator int() const;
};
#endif
//codi,o para a classe fracao
#include <iostream.h>
#include <math.h>
#include <iomanip.h>
#include <stdio.h>
#include &of.h&
fracao((fracao(fracao Yt)
//copy constructor
{
num"t.num;
den"t.den;
}
void fracao((simplifica(void)
{
lon, commd;
commd"mdc(numden); //divisor comum
num"num/commd;
den"den/commd;
if (den<$) { den"Mden; num"Mnum;};
//move o sinal p/ cima
}
fracaoY fracao((operator-" (const fracaoY t)
{
num"num1t.den-den1t.num;
den"den1t.den;
simplifica();
return 1this;
}
fracao((fracao(const lon, tconst lon, m)
{
num"t;
den"m;
simplifica();
//thisM>simplifica
}
fracao operator/ (const fracaoY fconst fracaoY !)
{
fracao ,(f.num1!.denf.den1!.num);
,.simplifica();
//esse metodo nao pertence a , mas ela chama
//,.simplifica(); isto eF permitido aqui mesmo com simplifica
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
79 - 03/06/14
//como private.
return ,;
}
fracao operator- (const fracaoY fconst fracaoY !)
{
fracao ,((f.num1!.den)-(f.den1!.num)!.den1f.den);
//retorna variavel
,.simplifica();
return ,;
}
fracao operatorM (const fracaoY fconst fracaoY !)
{
fracao ,((f.num1!.den)M(f.den1!.num)!.den1f.den);
//retorna variavel
,.simplifica();
return ,;
}
fracao operator1 (const fracaoY fconst fracaoY !)
{
fracao ,(f.num1!.numf.den1!.den);
//(f.num1!.num)/(f.den1!.den)
,.simplifica();
return ,;
}
ostreamY operator<< (ostreamY coconst fracaoY f)
{
co << &(& << f.num << &/& << f.den << &)&;
return co;
}
istreamY operator>> (istreamY ci fracaoY f)
{
lon, ,cdiv;
//melhorar ler mais so%re cin.
ci >> f.num >> f.den;
,cdiv"mdc(f.numf.den);
f.num"f.num/,cdiv;
f.den"f.den/,cdiv;
return ci;
}
int operator"" (const fracaoY sconst fracaoY t)
{
return ((s.num1t.den)""(s.den1t.num));
//ve!a operacoes matematicas com fracao
}
int operator." (const fracaoY sconst fracaoY t)
{
return ((s.num1t.den)."(s.den1t.num));
}
int operator<" (const fracaoY sconst fracaoY t)
{
return ((s.num1t.den)<"(s.den1t.num));
}
int operator< (const fracaoY sconst fracaoY t)
{
return ((s.num1t.den)<(s.den1t.num));
}
int operator> (const fracaoY sconst fracaoY t)
{
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
80 - 03/06/14
return ((s.num1t.den)>(s.den1t.num));
}
int operator>" (const fracaoY sconst fracaoY t)
{
return ((s.num1t.den)>"(s.den1t.num));
}
fracaoY fracao((operator" (const fracaoY t)
//equivale a copy constructor
{
num"t.num;
den"t.den;
return 1this;
}
fracaoY fracao((operatorM" (const fracaoY t)
{
num"num1t.denMden1t.num;
den"den1t.den;
simplifica();
return 1this;
//ponteiro para o proprio o%!eto (o apontado por this)
}
fracaoY fracao((operator1" (const fracaoY t)
{
num"num1t.num;
den"den1t.den;
simplifica();
return 1this;
}
fracaoY fracao((operator/" (const fracaoY t)
{
num"num1t.den;
den"den1t.num;
simplifica();
return 1this;
}
fracao((operator dou%le() const
{
dou%le d%l;
d%l"(dou%le(num)/dou%le(den));
return d%l;
}
fracao((operator float() const
{
float flt;
flt"(float(num)/float(den));
return flt;
}
fracao((operator lon,() const
{
lon, ln,;
ln,"num/den;
return ln,;
}
//converte fracao para lon,
fracao((operator int() const
{
int nt,r;
nt,r"int(num/den);
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
81 - 03/06/14
return nt,r;
}
//pro,rama principal testes e demonstracao
#include <iostream.h>
#include &of.h&
//definicao da fracao
#include <stdio.h>
main()
{
char ,;
cout << & =ntre com fracao a( &;
fracao a%;
cin >> a;
cout<< &a&<< a << &*n&;
cout << & =ntre fracao %(&;
cin >> %;
cout << &%& << % << &*n&;
fracao c;
c"a-%;
cout << &c"a-% & << c << &*n&;
fracao d(c);
cout << &fracao d(c)&<< d << endl;
//eF o que chamamos de copy constructor
cout << &a1% & << (a1%)<< &*n&;
cout << &aM% & << (aM%)<< &*n&;
cout << &a/% & << (a/%)<< &*n&;
cout << &a>% & << (a>%)<< &*n&;
cout << &a<% & << (a<%)<< &*n&;
cout << &a<"% & << (a<"%)<< &*n&;
cout << &a>"% & << (a>"%)<< &*n&;
cout << &a""% & << (a""%)<< &*n&;
cout << &a."% & << (a."%)<< &*n&;
c"a;
a1"%;
cout << &a1"% & << a<< &*n&;
a"c;
a/"%;
cout << &a/"% & << a<< &*n&;
a"c;
a-"%;
cout << &a-"% & << a << &*n&;
a"c;
aM"%;
cout << &aM"% & << a<< &*n&;
a"c;
cout << &lon,(a) & << lon,(a) << &*n&;
cout << &dou%le(a) & << dou%le(a) << &*n&;
cout << &int(a) & << int(a) << &*n&;
cout << &float(a) & << float(a) << &*n&;
cin >> ,;
return $;
}
Resulta! ! "#!$#a%a&
Entre fracao a:9
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
82 - 03/06/14
8
a(9/8)
Entre fracao b:9
4
b(9/4)
c=a+b (27/8)
fraction d(c)(27/8)
a*b (81/32)
a-b (-9/8)
a/b (1/2)
a>b 0
a<b 1
a<=b 1
a>=b 0
a==b 0
a!=b 1
a*=b (81/32)
a/=b (1/2)
a+=b (27/8)
a-=b (-9/8)
long(a) 1
double(a) 1.125
int(a) 1
float(a) 1.125
Resulta! ! "#!$#a%a&
Entre fracao a:1
2
a(1/2)
Entre fracao b:5
3
b(5/3)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
83 - 03/06/14
c=a+b (13/6)
fraction d(c)(13/6)
a*b (5/6)
a-b (-7/6)
a/b (3/10)
a>b 0
a<b 1
a<=b 1
a>=b 0
a==b 0
a!=b 1
a*=b (5/6)
a/=b (3/10)
a+=b (13/6)
a-=b (-7/6)
long(a) 0
double(a) 0.5
int(a) 0
float(a) 0.5
7.2. :ERANA MNLTIPLA
"Herana:mltipla"Se nos exemplos anteriores tnhamos uma hierarquia que se comportava da seguinte
maneira:
Agora teremos algo como:
ou ento:
Tendo o seguinte significado: A classe herdeira tem comportamento, "behaviour", semelhante ao das duas
classes pais.
7.2.1. UM E8EMPLO SIMPLES.
Este exemplo seria sobre como implementar uma hierarquia semelhante a hierarquia 1, mas no est pronto
ainda . Precisamos de sugestes sobre exemplos mais claros que um rdio relgio ou um Estagirio
Remunerado. O exemplo seguinte supre a falta deste, mas o apredizado mas abrupto.
7.2.2. 6IRTUAL PUBLIC E RESOLUO DE CONFLITOS.
Referente ao diagrama hierarquia de veculos apresentado neste tpico.
O que este caso tem de novo com relao ao anterior que veculo utilitrio pode herdar as caractersticas de
veculo por dois ramos da "hierarquia" de herana, como prevenir os possveis conflitos decorrentes deste fato?
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
84 - 03/06/14
Simples, os pais de veculo utilitrio devem receber veculo (a classe comum) atravs do qualificador virtual
public.
Este exemplo tambm apresenta a estratgia para resoluo de conflitos de nomes em herana mltipla,
lembre-se que agora as classes pai podem ter nomes, identificadores em comum. Nesse caso usamos o
operador de resoluo de escopo (( , veja os comentrios.
TE")/!s a3!#a!s&
Resoluo de conflitos quando existe mais de um caminho de herana para uma classe pai (veculo), chamada
do construtor para essa classe pai nas classes filhas. Resoluo de conflitos entre identificadores comuns.
//header file
class veiculo {
private(
char1 nome; //qualificacao do veiculo
int peso; //massa do veiculo
int hp; //potencia em hp.
pu%lic(
veiculo(char1 nint pint h);
void altera2hp(int en);
int retorna2hp(void);
void altera2peso(int en);
int retorna2peso(void);
};
class v2passeio(virtual pu%lic veiculo {
private(
int vol2int; //volume interno.
pu%lic(
v2passeio(char1 nint pint hpint vi);
void altera2vi(int en);
int retorna2vi(void);
float peso2pot(void); //relacao peso potencia.
};
class v2car,a(virtual pu%lic veiculo {
private(
int car,a; //car,a do veiculo.
pu%lic(
v2car,a(char1 nint pint hpint c);
void altera2car,a(int en);
int retorna2car,a(void);
float peso2pot(void); //relacao peso potencia veiculo carre,ado
};
class v2utilitario(pu%lic v2passeiopu%lic v2car,a {
private(
//qualquer outro atri%uto unico de v2utilitario.
pu%lic(
v2utilitario(char1 nint pint hpint viint c);
float peso2pot(void);
};
//implementation file
#include &multiple.h&
veiculo((veiculo(char1 nint pint h)
{ nome"n; peso"p; hp"h; }
void veiculo((altera2peso(int en)
{ peso"en;}
int veiculo((retorna2peso(void)
{ return peso; }
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
85 - 03/06/14
void veiculo((altera2hp(int en)
{ hp"en; }
int veiculo((retorna2hp(void)
{ return hp;}
v2passeio((v2passeio(char1 nint pint hpint vi)(veiculo(nphp)
{ vol2int"vi; }
void v2passeio((altera2vi(int en)
{ vol2int"en; }
int v2passeio((retorna2vi(void)
{ return vol2int; }
float v2passeio((peso2pot(void)
{ return float(retorna2peso())/float(retorna2hp()); }
v2car,a((v2car,a(char1 nint pint hpint c)(veiculo(nphp)
{ car,a"c; }
void v2car,a((altera2car,a(int en)
{ car,a"en; }
int v2car,a((retorna2car,a(void)
{ return car,a; }
float v2car,a((peso2pot(void)
{ return float(retorna2peso()-car,a)/float(retorna2hp()); }
v2utilitario((v2utilitario(char1 mint pint hpint viint
c)(v2car,a(mphpc)v2passeio(mphpvi)veiculo(mphp)
{
//o construtor veiculo(mphp) declarado aqui e que vale
//os construtores veiculo(mphp) hierarquia acima sao descartados
}
float v2utilitario((peso2pot(void)
{ return v2car,a((peso2pot(); }
//main file
#include &multiple.h&
#include <iostream.h>
void main()
{
v2passeio v#(&<oyota :orolla&J$$#J$J);
cout << v#.peso2pot()<<endl;
v2utilitario v4(&5ic[Mup 8&P$$#T$4P$$);
cout << v4.peso2pot()<<endl;
cout << v4.retorna2peso();
}
C!%e't(#)!s&
float v_utilitario::peso_pot(void)
{ return v_carga::peso_pot(); }
A funo membro peso_pot est presente em todas as classes da "hierarquia". Na classe veiculo utilitario ela
no precisa ser reimplementada, basta escolher se em termos de peso potncia, veiculo utilitario deve se
comportar como veiculo de carga ou como veiculo de passeio.
A escolha do comportamento foi a de veiculo de car,a, agora o que temos a fazer chamar a funo
membro peso2pot de veiculo de car,a que j est implementada, o que fazer para distinguir entre a
funo membro de mesmo nome da classe base veiculo de passeio? Usa-se o operador de resoluo de
escopo, mas agora acompanhado do nome da classe base que se deseja acessar: v2car,a((peso2pot();.
A mesma estratgia adotada para dados membros em conflito:
nome2classe2pai((dado2mem%ro2em2conflito; , neste caso os atributos em comum esto na classe
veiculo, topo da "hierarquia".
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
86 - 03/06/14
Resulta! ! "#!$#a%a&
2.30769
4.44444
400
7.4. POLIMORFISMO PARAM+TRICO OTEMPLATEP
Polimorfismo paramtrico um recurso bastante til para evitar redundncia de cdigo, portanto se trata de um
meio de reuso deste. importante para criar famlias de classes ou funes relacionadas.
Este recurso permite por exemplo definir uma classe matriz (do campo da matemtica) uma nica vez num
"header file" e utilizar esta classe matriz para matrizes de tipo float, tipo int ou long ,etc. muito importante e
existncia de um comportamento uniforme entre os tipos que sero instanciados, por exemplo se na sua classe
matriz voc usa o operador %, todos os tipos a serem instanciados (susbtitudos como tipo usado na matriz)
devem atender da maneira desejada a esse operador.
Em linguagens orientadas a objetos que no definem sobrecarga de operador (Mdula-3) surge um problema:
suponha que voc definiu o tipo frao e quer usar em sua matriz de tipos parametrizados tanto o tipo frao
quanto o tipo inteiro. Como uniformizar o comportamento desses tipos no que se refere a operao de soma
usada na classe matriz? Uma soluo redefinir o tipo inteiro oferecido pela linguagem de modo que ele atenda
a funo membro de mesmo nome usada no tipo frao, exemplo a funo soma(novo_inteiro a);.
7.4.1. TAD 6ETOR
Modificao do programa vetor de 1.5.3.6 para suportar polimorfismo paramtrico (template).
Uma condio para que o polimorfismo paramtrico funcione bem : Os tipos que so substitudos no template
devem se comportar de maneira uniforme para exemplificar isso vamos substituir no template da classe vetor o
tipo frao com sobrecarga de operadores de 4.1.2 e o tipo float.
Foi proposta a implementao do tipo abstrato de dados string, uma boa indicao da qualidade de sua
implementao uma substituio no template deste exemplo sem acarretar modificaes, isto s vale se
nessa implementao j foi feita sobrecarga de operadores (comparao entre strings).
Dica de implementao: Se voc deseja fazer um programa que use "templates" seguir os passos indicados
abaixo normalmente lhe poupar tempo:
-Defina os tipos que voc quer parametrizar um termos de chamadas de funes membro e operadores de
nomes e sintaxe iguais (uniformidade). Os tipos dos argumentos vo variar.
-Construa seu programa para operar em um s destes tipos.
-Termine incluindo as definies dos templates no programa e testando para os demais tipos.
-Corrija as eventuais falhas de substituio.
//tempvet.h definicao da classe vetor com template.
#include <stdli%.h>
//header file para classe vetor
const int inicio"$;
template<class <> class vetor{ //< eF o tipo do elemento do vetor
private(
<1 v; //pode ser qualquer tipo que atenda as operacoes < > "
int tamanho;
pu%lic(
vetor (int tamanho) ;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
87 - 03/06/14
<Y operatorQR (int i);
< maximo();
int primeiro(void);
int ultimo(void);
};
template<class <> vetor<<>((vetor (int tam)
{v"neE <QtamR; tamanho"tam;}
template<class <> int vetor<<>((primeiro (void)
{return inicio;}
template<class <> int vetor<<>((ultimo (void)
{ return tamanhoM#; }
template<class <> <Y vetor<<>((operatorQR(int i)
{
if (i<$ ZZ i>"tamanho) {cout << &Dora dos limites.&; exit(#);}
//use exception handlin, to ma[e it chec[ %ounds for you.
return vQiR;
}
template<class <> < vetor<<>(( maximo(void)
{int candidato"inicio;
for (int i"inicio;i<tamanho;i--)
if (vQiR>vQcandidatoR) candidato"i;
return vQcandidatoR;}
#include <iostream.h>
#include &exvetJ.h&
main()
{
vetor<float> meu(I);
for (int i"meu.primeiro();i<"meu.ultimo();i--)
{
cout << &=ntre com valor da posicao(& << i << &*n&;
cin >> meuQiR;
}
for (int !"meu.primeiro();!<"meu.ultimo();!--) cout<< meuQ!R<< & &;
cout << endl << &9aximo(& << meu.maximo();
return $;
}
//main file pro,rama principal
#include <iostream.h>
#include &exvetJ.h&
#include &fractio4.h&
#include &fractio4.cpp&
main()
{
vetor<fraction> meu(I);
for (int i"meu.primeiro();i<"meu.ultimo();i--)
{
cout << &=ntre com valor da posicao(& << i << &*n&;
cin >> meuQiR;
}
for (int !"meu.primeiro();!<"meu.ultimo();!--) cout<< meuQ!R<< & &;
cout << endl << &9aximo(& << meu.maximo();
return $;
}
C!%e't(#)!s:
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
88 - 03/06/14
Se voc substitusse no template do vetor o tipo frao que vamos definido em 4.1.2, o resultado seria igual ao
apresentado no sub-tpico resultado do programa em comentrios. sto s a ttulo de curiosidade. Voc no
precisa tentar implementar um tipo frao para uso neste template ainda.
Resulta! e teste ! "#!$#a%a e% /!%e't(#)!s&
Entre com valor da posicao:0
1
2
Entre com valor da posicao:1
5
4
Entre com valor da posicao:2
6
1
Entre com valor da posicao:3
2
8
Entre com valor da posicao:4
4
2
(1/2) (5/4) (6/1) (1/4) (2/1)
Maximo: (6/1)
Resulta! ! "#!$#a%a /!% ! t)"! .l!at "a#a%et#)Ja!:
Entre com valor da posicao:0
1.2
Entre com valor da posicao:1
2.1
Entre com valor da posicao:2
5.3
Entre com valor da posicao:3
1.5
Entre com valor da posicao:4
1.9
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
89 - 03/06/14
1.2 2.1 5.3 1.5 1.9
Maximo:5.3
7.4.2. TEMPLATE DE FUNO
Template de funo , introduziremos tipos parametrizados na funo mdc que calcula o mximo divisor comum
tanto para long quanto para int e outros tipos que definam o operador %:
//exemplo facil de templates de funcao
#include <iostream.h>
template<class <> < mdc(< n< d) //maximo divisor comum
//metodo de =uclides
{
if (n<$) n"Mn;
if (d<$) d"Md;
Ehile (d."$) {
< r"n N d; //template < N"96>
n"d;
d"r;
}
return n;
}
void main(void)
{
int a"I;
lon, %"U;
lon, c"V;
int d"#P;
cout << &mdc(IU)"& << mdc(aU) << &*n&; //int int
cout << &mdc(4J)"& << mdc(4J) << &*n&; //int int ZZ lon, lon,
cout << &mdc(UV)"& << mdc(%c) << &*n&;//lon, lon,
cout << &mdc(V#P)"& << mdc(cd) << &*n&; //lon, int //erro....
}
//^ersao que nao produ3 erro.
//exemplo facil de templates de funcao
#include <iostream.h>
template<class <> < mdc(< n< d) //maximo divisor comum
//metodo de =uclides
{
if (n<$) n"Mn;
if (d<$) d"Md;
Ehile (d."$) {
< r"n N d; //template < N"96>
n"d;
d"r;
}
return n;
}
lon, mdc(lon, mlon, n); //definicao exata lon, prevalece so%re int em termos de
conversao
//nao acrescente int mdc(int aint %); voce tera am%i,uidades e o compilador nao
fara a //conversao
void main(void)
{
int a"I;
lon, %"U;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
90 - 03/06/14
lon, c"V;
int d"#P;
cout << &mdc(IU)"& << mdc(aU) << &*n&; //int int
cout << &mdc(4J)"& << mdc(4J) << &*n&; //int int ZZ lon, lon,
cout << &mdc(UV)"& << mdc(%c) << &*n&;//lon, lon,
cout << &mdc(V#P)"& << mdc(cd) << &*n&; //lon, int 6` conversao.
}
C!%e't(#)!s&
Na primeira verso do programa tudo funciona bem, com exceo da ltima linha, ela produz um erro que
corrigido na segunda verso do programa. Vamos explicar esse erro:
Quando o compilador resolve, decide, uma chamada de funo ele primeiro tentar achar uma definio exata
dela (tipos j definidos) exemplo long mdc (int a,long b);.
Se no houver nenhuma verso exata o compilador tenta achar uma verso com tipos paramtricos que aceite
os tipos da chamada da funo, no caso uma definio de template que aceitaria seria: template<class T1,class
T2> T2 max(T2 n,T1 d) , que um tanto perigosa em termos de operaes entre tipos, por isso tambm no foi
fornecida.
Se esta tentativa tambm falhar o compilador tenta fazer a converso implcita do argumento de modo a
satisfazer uma definio exata, essa converso no pode resultar numa ambiguidade. Na segunda verso
fornecemos uma verso exata: long mdc (long a, long b);. somente, no deixando margens para ambiguidades.
7.4.4. :ERANA E TEMPLATES.
Modificao do programa de listas ligadas de 2.1.4 para suportar templates. Esta verso usada em muitos
outros exemplos do tutorial.
#ifndef 9BA@<K2K
#define 9BA@<K2K
#include <stdli%.h>
#include <iostream.h>
//:riacao de uma hierarquia de listas li,adas.
//6 elemento da lista eF um inteiro
enum Coolean{D8B@=<';=};
template <class <>class no{ //este eF o no da lista li,ada so eF usado por ela
private(
< info; //informacao
no1 prox; //ponteiro para o proximo
pu%lic(
no();
no(< ino1 p);
no1 ,et2prox(void);
void set2prox(no1 p);
< ,et2info(void);
void set2info(< a);
no1 do%ra(void);
Hno(void);
} ;
template <class <>class lista{ //esta eF a lista li,ada comum.
protected( //&visivel hierarquia a%aixo&
no<<>1 primeiro; //primeiro no da lista aqui eu insiro e removo.
pu%lic(
lista(void);
lista(const lista<<>Y lc); //copy constructor.
Coolean va3ia(void)const;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
91 - 03/06/14
Coolean contem(< el)const;
void insere2primeiro(< elem);
<1 remove2primeiro();
void mostra()const;
Hlista(void);
}; //fim classe lista
template <class <>class listaultimo(pu%lic lista<<> { //essa e a lista util para
//implementar pilhas e filas.
protected( //protected e uma opcao outra eF ,et2ultimo() e set2...
no<<>1 ultimo;
pu%lic(
listaultimo(void);
listaultimo(const listaultimo<<>Y lc); //redefinicao
void insere2ultimo(< elem); //nova
void insere2primeiro(< elem); //redefinicao
<1 remove2primeiro();//redefinicao
Hlistaultimo(void);
//as operacoes nao redefinidas sao validas.
};
template <class <>class listaordenada(pu%lic lista<<> {
//essa eF a lista comum com aprimoramentos.
pu%lic(
listaordenada(void);
//nao definimos copy constructor
Coolean contem(< el)const;
void insere2primeiro(< elem); //insere em ordem
<1 remove2elemento(< el);
Hlistaordenada(void);
};
template<class <>no<<>((no()
{prox"?;BB;cout << &Ki&;}
template<class <>no<<>((no(< ino1 p)
{info"i;prox"p;cout << &Ki&;}
template<class <> no<<>1 no<<>((,et2prox(void)
{return prox;}
template<class <> void no<<>((set2prox(no1 p)
{prox"p;}
template<class <> < no<<>((,et2info(void) {return info;}
template<class <> void no<<>((set2info(< i)
{info"i;}
template<class <> no<<>1 no<<>((do%ra(void)
{
if (,et2prox()""?;BB) return neE no<<>(,et2info()?;BB);
else return neE no<<>(,et2info()thisM>,et2prox()M>do%ra());
//recursividade para duplicacao da lista
}
template<class <> no<<>((Hno(void)
{cout << &%ye&;} //%ye e so para de%u,ar retire depois de compilado.
template<class <> lista<<>((lista(void)(primeiro(?;BB)
{} //%loco de codi,o va3io
template<class <> lista<<>((lista(const lista<<>Y lc)
{ primeiro"lc.primeiroM>do%ra(); }
template<class <> Coolean lista<<>((va3ia(void)const
{ return Coolean(primeiro""?;BB); }
template<class <> Coolean lista<<>((contem(< el) const//mais rapido que iterador
{
no<<>1 curr;
curr"primeiro;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
92 - 03/06/14
Ehile ((curr."?;BB) YY (currM>,et2info()."el))
{
curr"currM>,et2prox();
};
return Coolean(currM>,et2info()""el);
}
template<class <> void lista<<>((insere2primeiro(< elem)
{
no<<>1 insirame;
if (primeiro""?;BB) //lista va3ia
primeiro"neE no<<>(elem?;BB);
else {
insirame"neE no<<>(elemprimeiro);
primeiro"insirame;
};
};
template<class <> <1 lista<<>((remove2primeiro(void)
{
<1 devolvame; //return
no<<>1 temp; //to delete
if (primeiro""?;BB) return ?;BB; //lista va3ia
else {
(1devolvame)"primeiroM>,et2info();
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
return devolvame;
};
};
template<class <>void lista<<>((mostra() const
{
no<<>1 curr;
cout << &"&;
curr"primeiro;
Ehile (curr."?;BB)
{
cout <<&(&<<currM>,et2info()<<&)&<<&M&;
curr"currM>,et2prox();
};
}
template<class <>lista<<>((Hlista(void)
{
no<<>1 temp;
Ehile (primeiro."?;BB)
{
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
};
}
template<class <>listaordenada<<>((listaordenada(void)(lista<<>()
{};
template<class <> Coolean listaordenada<<>((contem(< el)const
{
no<<>1 curr;
Coolean conti"<';=;
curr"primeiro;
Ehile ((curr."?;BB) YY conti)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
93 - 03/06/14
{
if (currM>,et2info()<el)
curr"currM>,et2prox();
else conti"D8B@=;
};
if (curr""?;BB) return D8B@=;
else return Coolean(currM>,et2info()""el);
}
template<class <>void listaordenada<<>((insere2primeiro(< elem)
{
no<<>1 curr"primeiro;
no<<>1 prev"?;BB;
no<<>1 insirame;
Coolean conti"<';=;
Ehile ((curr."?;BB) YY conti)
{
if (currM>,et2info()<elem)
{prev"curr; curr"currM>,et2prox();}
else conti"D8B@=;
};
insirame"neE no<<>(elemcurr);
if (prev""?;BB) primeiro"insirame;
else prevM>set2prox(insirame);
}
template<class <> <1 listaordenada<<>((remove2elemento(< el)
{
<1 devolvame;
no<<>1 curr"primeiro;
no<<>1 prev"?;BB;
no<<>1 deleteme;
Coolean conti"<';=;
Ehile ((curr."?;BB) YY conti) //acha lu,ar onde pode estar el
{
if (currM>,et2info()<el)
{prev"curr; curr"currM>,et2prox();} //anda
else conti"D8B@=;
};
if (curr""?;BB) return D8B@=; //fim de lista ou va3ia
else //pode ser o elemento ou ele nao existe
{
if (currM>,et2info()""el)
{
deleteme"curr;
if (prev""?;BB) //lista so com um elemento ou primeiro el
primeiro"currM>,et2prox();
else
{
prevM>set2prox(currM>,et2prox());
}
cout << deletemeM>,et2info()<<endl; //so para verificar
(1devolvame)"deleteM>,et2info();
delete deleteme;
return devolvame;
}
else return ?;BB;
}
}
template<class <>listaordenada<<>((Hlistaordenada(void)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
94 - 03/06/14
{cout << &Bista destruida.&;};
template<class <>listaultimo<<>((listaultimo(void)(lista<<>()
{
ultimo"?;BB;
}
template<class <>listaultimo<<>((listaultimo(const listaultimo<<>Y lc)
{
no<<>1 curr;
primeiro"ultimo"?;BB; //iniciali3a lista
if (.lc.va3ia())
{
curr"lc.primeiro;
Ehile (curr."?;BB)
{
insere2ultimo(currM>,et2info());
curr"currM>,et2prox();
}
}
}
template<class <>void listaultimo<<>((insere2ultimo(< elem)
{
no<<>1 insirame;
insirame"neE no<<>(elem?;BB);
if (ultimo""?;BB) ultimo"insirame; //lista va3ia
else {
ultimoM>set2prox(insirame);
ultimo"insirame;
};
if (primeiro""?;BB) primeiro"ultimo; //lista va3ia
}
template<class <> void listaultimo<<>((insere2primeiro(< elem) //redefinicao
{
no<<>1 insirame;
if (primeiro""?;BB) //lista va3ia
{
primeiro"neE no<<>(elemultimo);
ultimo"primeiro;
}//lista va3ia
else {
insirame"neE no<<>(elemprimeiro);
primeiro"insirame;
};
}
template<class <> <1 listaultimo<<>((remove2primeiro()//redefinicao
{
<1 devolvame; //return
no<<>1 temp; //to delete
if (primeiro""?;BB) return $; //lista va3ia
else {
(1devolvame)"primeiroM>,et2info();
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
if (primeiro""?;BB) ultimo"?;BB; //volta lista va3ia
return devolvame;
};
}
template<class <>listaultimo<<>((Hlistaultimo(void)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
95 - 03/06/14
{
no<<>1 temp;
Ehile (primeiro."?;BB)
{
temp"primeiro;
primeiro"primeiroM>,et2prox();
delete temp;
};
delete ultimo;
}
#endif
#include &mlistht.h&
main()
{
listaultimo<int> minha;
listaultimo<int>1 copia;
char option; //use in menu as option varia%le
char cpyopt; //copy option para copia
int el; //elemento a inserir
do {
cout <<&*n&; //menu options display
cout <<&5(Ansere no primeiro.*n&;
cout <<&'('emove no primeiro.*n&;
cout <<&;(Ansere no ultimo.*n&;
cout <<&=(=xiste elemento]*n&;
cout <<&^(^a3ia]*n&;
cout <<&9(9ostra lista.*n&;
cout <<&:(:opia lista e mostra.*n&;
cout <<&L(Luit teste lista.*n&;
cout <<&=ntre comando(&;
cin >> option; //reads user option
sEitch(option) //executes user option
{
case F5F(
case FpF(
cout << &=ntre elemento(&;
cin >>el;
minha.insere2primeiro(el);
%rea[;
case F'F(
case FrF(
if (.minha.va3ia())
cout << (1minha.remove2primeiro())<<endl;
else cout << &?;BB Bista va3ia.& <<endl;
%rea[;
case F;F(
case FuF(
cout << &=ntre elemento(&;
cin >> el;
minha.insere2ultimo(el);
%rea[;
case F9F(
case FmF( minha.mostra();
%rea[;
case F=F(
case FeF(
cout << &=ntre elemento(&;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
96 - 03/06/14
cin >>el;
cout << minha.contem(el);
%rea[;
case F^F(
case FvF(
cout << minha.va3ia();
%rea[;
case F:F(
case FcF(
copia"neE listaultimo<int>(minha);
copiaM>mostra();
cout << &8,ora tra%alhando na lista copia.& << endl;
do {
cout <<&*n&; //menu options display
cout <<&5(Ansere no primeiro.*n&;
cout <<&'('emove no primeiro.*n&;
cout <<&;(Ansere no ultimo.*n&;
cout <<&=(=xiste elemento]*n&;
cout <<&^(^a3ia]*n&;
cout <<&9(9ostra lista.*n&;
cout <<&L(Luit teste lista copia]^olta lista anterior].*n&;
cout <<&=ntre comando(&;
cin >> cpyopt; //reads user option
sEitch(cpyopt) //executes user option
{
case F5F(
case FpF(
cout << &=ntre elemento(&;
cin >>el;
copiaM>insere2primeiro(el);
%rea[;
case F'F(
case FrF(
if (.copiaM>va3ia())
cout << (1copiaM>remove2primeiro())<<endl;
else cout << &?;BB Bista va3ia.& <<endl;
%rea[;
case F;F(
case FuF(
cout << &=ntre elemento(&;
cin >>el;
copiaM>insere2ultimo(el);
%rea[;
case F9F(
case FmF(
copiaM>mostra();
%rea[;
case F=F(
case FeF(
cout << &=ntre elemento(&;
cin >>el;
cout << copiaM>contem(el);
%rea[;
case F^F(
case FvF(
cout << copiaM>va3ia();
%rea[;
case FLF(
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
97 - 03/06/14
case FqF(
delete copia;
%rea[;
default( ;
} //sEitchMcase code %loc[
} Ehile ((cpyopt."FLF) YY (cpyopt."FqF));
%rea[;
default( ;
} //sEitchMcase code %loc[
} Ehile ((option."FLF) YY (option."FqF)); //menu loop code %loc[
return $;
} //main code %loc[
7.4.7. TEMPLATES E AGREGAO
Usando o template definido no exemplo dois criaremos uma classe pilha e a testaremos de modo anlogo ao
que foi feito em 2.2 s que agora com templates e com uma pilha e no fila.
mlisth.h no ser copiada, idntica a do exemplo anterior de "templates".
#include &mlistht.h&
template<class <>class pilha { //a,re,acao de uma lista
private(
lista<<> al; //a lista
pu%lic(
pilha();
Coolean va3ia();
Coolean contem(< el);
void insere(< el);
<1 remove();
void mostra();
};
template<class <> pilha<<>((pilha(){};
template<class <> Coolean pilha<<>((va3ia()
{return al.va3ia();}
template<class <> Coolean pilha<<>((contem(< el)
{return al.contem(el);}
template<class <> void pilha<<>((insere(< el)
{al.insere2primeiro(el);}
template<class <> <1 pilha<<>((remove()
{return al.remove2primeiro();}
template<class <> void pilha<<>((mostra()
{al.mostra();}
#include &mpilhat.h&
main()
{
pilha<int> minha;
char option; //use in menu as option varia%le
int el; //elemento a inserir
do {
cout <<&*n&; //menu options display
cout <<&A(Ansere.*n&;
cout <<&'('emove.*n&;
cout <<&9(9ostra pilha.*n&;
cout <<&L(Luit pilha test.*n&;
cout <<&^(^a3ia]*n&;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
98 - 03/06/14
cout <<&:(:ontem]*n&;
cout <<&=ntre comando(&;
cin >> option; //reads user option
sEitch(option) //executes user option
{
case FAF(
case FiF(
cout << &=ntre elemento(&;
cin >>el;
minha.insere(el);
%rea[;
case F'F(
case FrF(
if (.minha.va3ia())
cout << (1(minha.remove()))<<endl;
else cout << &?;BB pilha va3ia.& <<endl;
%rea[;
case F:F(
case FcF(
cout << &=ntre elemento(&;
cin >>el;
cout << minha.contem(el);
%rea[;
case F9F(
case FmF(
minha.mostra();
%rea[;
case F^F(
case FvF(
cout << &'esultado(& << minha.va3ia() <<endl;
%rea[;
default( ;
} //sEitchMcase code %loc[
} Ehile ((option."FLF) YY (option."FqF)); //menu loop code %loc[
return $;
} //main code %loc[
7.7. METACLASSES
Metaclasses armazenam informaes sobre classes definidas pelo usurio e so comuns em algumas
linguagens de programao orientadas a objetos. Essa informao armazenada a chamada metainformao.
C++ no possui metaclasses, porm existem meios de armazenar alguma metainformao, um deles o uso
de variveis do tipo static que guardam informaes sobre os vrios objetos de uma mesma classe.
A utilidade da metainformao vasta. Por exemplo um arquivo que armazena uma imagem contm
geralmente um cabealho sobre a imagem (nmero de "pixels", largura, altura, etc). Numa classe lista, pode ser
considerado como meta-informao: o nmero de elementos, o estado: ordenado ou no, etc. Em bancos de
dados muito comum se armazenar meta-informao nos arquivos.
7.7.1. UM TIPO SIMPLES COMO STATIC
Quando se declara um atributo static em uma classe, todos os objetos instanciados tem uma referncia para ele
(o mesmo atributo), ou seja ele pode ser modificado ou lido por funes membro de todos os objetos desta
classe. No exemplo a seguir declaramos um atributo static inteiro que incrementado quando o objeto criado
(construtor) e decrementado quando o objeto destrudo. Esse atributo static pode ser de qualquer tipo, pode
ser at um objeto.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
99 - 03/06/14
Variveis static servem para fazer estatsticas sobre uma classe, tambm so adequadas para tornar
informaes de um objeto disponveis para outros da mesma classe, elas continuam existindo (conservam seu
valor) mesmo que no haja nenhum objeto instanciado e no destrudo (vivo).
O programa abaixo mostra como faz-lo, alive representa o nmero de objetos da classe robot criados. Veja
que a declarao de alive segue a palavra static.
Diagrama do atributo static alive, compartilhado por vrios robs:
#include <iostream.h>
class ro%o {
private(
float xy;
static int vivos; //,uarda numero de ro%os vivos.
pu%lic(
ro%o(float xfloat y) {vivos--;} //cria ro%o
void move(float dxfloat dy) {x-"dx;y-"dy;}
static int ,et2vivos(void) {return vivos;} //quantos vivos
Hro%o(void) {vivosMM;} //mata ro%o
};
int ro%o((vivos"$; //iniciali3acao da variavel static.
main()
{
cout << ro%o((,et2vivos() << endl;
ro%o 1r#"neE ro%o(#.J#.P); //cria ro%o #
ro%o 1r4;
cout << r#M>,et2vivos() << &*n& ; //# vivo
r4"neE ro%o($.$$.$); //cri ro%o 4
cout << r#M>,et2vivos() << &*n& ; //4 vivos
delete r#; //[ill ro%o #
cout << ro%o((,et2vivos() << &*n& ; //# vivo
r4M>move(#4.P4J.4); //movendo ro%o certa distancia.
delete r4; //mata ro%o 4.
//nenhum ro%o vivo
cout << ro%o((,et2vivos() << endl;
return $;
}
Resulta! ! "#!$#a%a&
0
1
2
1
0
C!%e't(#)!s&
Observe o trecho de cdigo: int robot::alive=0; perceba que voc deve inicializar o atributo antes da criao de
qualquer objeto. Esse tipo de acesso no permitido em main(), mantendo assim o encapsulamento. Quando
os objetos so criados eles incrementam alive atravs de seus construtores, e decrementam quando so
destrudos.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
100 - 03/06/14
Existe uma funo membro declarada como static: static int get_vivos(void) {return vivos;} esta funo membro
tem um tipo de acesso diferente dos outros , o seguinte trecho de cdigo usado em nosso programa
permitido: cout << robo::get_vivos() << endl;. Perceba que get_vivos chamado sem o operador . ou ->, isto
permitido porque get_vivos um funo membro static, opera portanto sobre variveis static que podem existir
antes da criao do primeiro objeto da classe ou quando nenhum objeto est ativo.
7.7.2. UM TIPO DEFINIDO PELO USUDRIO USADO COMO STATIC
Trechos de um programa com um objeto static representando uma lista parametrizada (templates). A estrutura
poderia ser parametrizada de modo a armazenar informaes sobre os estados dos demais objetos, permitindo
que eles realizem algum tipo de interao. Neste exemplo vamos s armazenar os mdulos das distncia que
os robos se moveram (funo membro move())
Faa a incluso do arquivo que define sua estrutura de armazenamento, "storage", no seu projeto:
#include "mlistht.h"
Crie o atributo static com o encapsulamento desejado na definio da classe ro%o. Se preciso indique o tipo
parametrizado:
class faca_estatisticas_sobre_mim {
private:
static lista<float> registro; //storage class
public: ...
Acesse o atributo static aonde seu encapsulamento permite atravs de chamadas de funes membro
como:
registro.insere_ultimo(a);
Tente fazer este exemplo sozinho, depois confira com o programa a seguir:
#include <iostream.h>
#include <math.h>
#include &mlistht.h&
class ro%ot {
private(
float xy; //posicoes
static lista<float> deltas;//,uarda os passos dados
pu%lic(
ro%ot(float afloat %)
{
x"a;
y"%;
} //cria ro%o
void move(float dxfloat dy)
{
x-"dx;
y-"dy;
deltas.insere2primeiro(sqrt(x1x-y1y));
}
static void mostra2lista(void)
{
deltas.mostra();
cout << endl;
}
Hro%ot(void) {} //mata ro%o
};
lista<float> ro%ot((deltas; //chama o construtor.
main()
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
101 - 03/06/14
{
ro%ot 1r#"neE ro%ot($.$$.$); //cria ro%o #
r#M>move(##);
ro%ot 1r4;
ro%ot((mostra2lista(); //mostra lista.
r4"neE ro%ot(#.$#.$); //cria ro%o 4
ro%ot((mostra2lista(); //mostra lista.
r4M>move(#$#$);
ro%ot((mostra2lista(); //mostra lista.
delete r#;
delete r4;
return $;
}
Resulta! ! "#!$#a%a&
=(1.41421)-
=(1.41421)-
=(15.5563)-(1.41421)-
Stat)/ e .u'12es /!%u's&
Funes comuns tambm podem ter variveis static e no s objetos. Neste caso as variveis permanecem
ativas durante chamadas da funo.
7.=. TRATAMENTO DE E8CE,ES
Adicionando tratamento de excees ao programa vetor do item 4.3.1.
//header file para classe vetor ex.h
#include <iostream.h>
const int inicio"$;
class excecoesvetor { //to %e throEed
pu%lic( //nao tenho interesse de encapsular por enquanto.
excecoesvetor(char1 texto);
char1 mensa,em;
char1 retorna2mensa,em(void);
};
class excecaoalocacao(pu%lic excecoesvetor{
pu%lic(
excecaoalocacao(char1 texto);
};
class excecaoinstanciacao(pu%lic excecoesvetor{
pu%lic(
excecaoinstanciacao(char1 textoint num);
int quant; //numero de elementos com que se tentou instanciar vetor
};
class excecaolimite(pu%lic excecoesvetor{ //limite de indice desrespeitado
pu%lic(
excecaolimite(char1 textoint indint max);
int indice; //arma3ena o indice que ,erou excecao
int maximo; //arma3ena o indice maximo
//indice minimo eF fixo para este pro,rama"$
};
excecoesvetor((excecoesvetor(char1 texto)
{ mensa,em"texto;}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
102 - 03/06/14
char1 excecoesvetor((retorna2mensa,em(void)
{ return mensa,em; }
excecaolimite((excecaolimite(char1 textoint indint max)(excecoesvetor(texto)
{ indice"ind; maximo"max;}
excecaoinstanciacao((excecaoinstanciacao(char1 textoint num)(excecoesvetor(texto)
{ quant"num; }
excecaoalocacao((excecaoalocacao(char1 texto)(excecoesvetor(texto)
{}
template<class <> class vetor{ //< eF o tipo do elemento do vetor
private(
<1 v; //pode ser qualquer tipo que atenda as operacoes < > "
int tamanho;
pu%lic(
vetor (int tamanho) ;
<Y operatorQR (int i);
< maximo();
int primeiro(void);
int ultimo(void);
};
template<class <> vetor<<>((vetor (int tam)
{
if (tam<#)
throE excecaoinstanciacao(&^etores de tamanho <#. @ao invalidos.&tam);
v"neE <QtamR;
if (v""?;BB)
throE excecaoinstanciacao(&?ao conse,ui alocar memoria&tam);
tamanho"tam;
}
template<class <> int vetor<<>((primeiro (void)
{return inicio;}
template<class <> int vetor<<>((ultimo (void)
{return tamanhoM#;}
template<class <> <Y vetor<<>((operatorQR(int i)
{
if (i<$ ZZ i>"tamanho)
throE excecaolimite(&Dora dos limites.&itamanho);
return vQiR;
}
template<class <> < vetor<<>(( maximo(void)
{
int candidato"inicio;
for (int i"inicio;i<tamanho;i--)
if (vQiR>vQcandidatoR) candidato"i;
return vQcandidatoR;
}
//main file
#include <iostream.h>
#include &ex.h&
main()
{
try
{
int ind; //indice usado para atuali3acoes
float item; //item usado para insercoes no vetor
vetor<float>1 meu;
try
{ meu"neE vetor<float>(I); }
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
103 - 03/06/14
catch (excecaoinstanciacaoY e)
{
cout << &=xcecao ,erada. 6 vetor nao pode ser criado.& << endl;
cout << e.retorna2mensa,em() << endl;
cout << &6 indice invalido eF(&<< e.quant << endl;
cout << &6 pro,rama sera terminado.& << endl;
throE; //HrethroE
}
catch (excecaoalocacaoY e)
{
cout << &=xcecao ,erada. 6 vetor nao pode ser criado.& << endl;
cout << e.retorna2mensa,em() << endl;
cout << &6 pro,rama sera terminado.& << endl;
throE;
}
catch (excecoesvetorY e)
{
cout << &=sta excecao nao estava prevista em nosso codi,o.&<<endl;
cout << &5ode ser resultado de uma extensao na hierarquia de excecoes.&<<endl;
cout << e.retorna2mensa,em() << endl;
}
for (int i"meuM>primeiro();i<"meuM>ultimo();i--)
{
cout << &=ntre com valor da posicao(& << i << &*n&;
cin >> meuM>operatorQR(i);
}
for (int !"meuM>primeiro();!<"meuM>ultimo();!--) cout<< (1meu)Q!R<< & &;
cout << &=ntre com o indice da posicao a atuali3ar(*n&;
cin >> ind;
cout << &=ntre com o valor a incluir(&;
cin >> item;
try{(1meu)QindR"item;}
catch (excecaolimiteY e)
{
cout << &*a @u%scriptin, desconsiderado.&<<endl;
cout << e.retorna2mensa,em() << endl;
}
//incluir um loop ate o%ter do teclado valores validos.
for (int ["meuM>primeiro();[<"meuM>ultimo();[--) cout<< (1meu)Q[R<< & &;
cout <<endl << &9aximo(& << meuM>maximo();
return $;
}//try
catch(...)
{
cout << &=xcecoes nao tratadas fim do pro,rama.&<<endl;
}
}
Resulta! '!#%al ! "#!$#a%a&
Entre com valor da posicao:0
5.2
Entre com valor da posicao:1
5632.2
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
104 - 03/06/14
Entre com valor da posicao:2
12.5
Entre com valor da posicao:3
12
Entre com valor da posicao:4
2.21
5.2 5632.2 12.5 12 2.21 Entre com o indice da posicao a atualizar:
0
Entre com o valor a incluir:2
2 5632.2 12.5 12 2.21
Maximo:5632.2
Resulta! a'!#%al eC)! a Q')/e )'C(l)! a! a! "#!$#a%a&
Entre com valor da posicao:0
2.2
Entre com valor da posicao:1
5.9
Entre com valor da posicao:2
4.1
Entre com valor da posicao:3
65.5
Entre com valor da posicao:4
2.3
2.2 5.9 4.1 65.5 2.3 Entre com o indice da posicao a atualizar:
6
Entre com o valor a incluir:4.5
Subscripting desconsiderado.
Fora dos limites.
2.2 5.9 4.1 65.5 2.3
Maximo:65.5
Resulta! a'!#%al eC)! a .al0a e al!/a1;! e %e%E#)a:
Excecao gerada! O vetor nao pode ser criado.
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
105 - 03/06/14
Nao consegui alocar memoria
O indice invalido e':5
O programa sera terminado.
Excecoes nao tratadas, fim do programa.
Resulta! a'!#%al eC)! a 'u%e#! e ele%e't!s ! Cet!# R 1&
Excecao gerada! O vetor nao pode ser criado.
Vetores de tamanho <1. Sao invalidos.
O indice invalido e':-5
O programa sera terminado.
Excecoes nao tratadas, fim do programa.
7.?. CONCLUS,ES
Neste tpico apresentaremos programas mais elaborados dentre eles uma simulao dirigida a eventos e uma
implementao de uma rvore binria.
7.?.1. DR6ORE BINDRIA.
Este programa implementa uma rvore binria e testa-a:
#include<iostream.h>
const <';="#;
const D8B@="$;
class no //no a,re,ado na classe arvore por ra3oes de encapsulamento
{
private(
int info; //atri%uto informacao use template depois...
no1 esq; //su%arvore esquerda
no1 dir; //su%arvore direita
int %usca2maisesq(void);
pu%lic(
no(int a); //sem filhos
no(int ano1 %no1 c); //com filhos
int retorna2quant(void);
no1 insere(int aintY res);
no1 remove(int %intY res);//res " resultado (sucesso])
int %usca(int c); //%usca %inaria
void in2order(); //parentisada
Hno(void); //destrutor da arvore/su%arvore
static int quant; //so para testes pode ser pu%lic.
};
class arv2%in { //encapsula no e redireciona chamadas de metodos
private(
no1 ar;
pu%lic(
arv2%in(void);
arv2%in(int a);
void insere(int aintY result);
void remove(int %intY result);
int %usca(int c); //%usca %inaria
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
106 - 03/06/14
void in2order(); //parentisada
Harv2%in(void);
};
#include<iostream.h>
#include<stdli%.h>
#include&%inatree.h&
int no((quant"$; //aqui eu uso uma variavel static
no((no(int a)
{info"a; esq"?;BB; dir"?;BB;quant--;}
no((no(int ano1 %no1 c) //constructor
{info"a;esq"%;dir"c;quant--;}
int no((retorna2quant(void)
{ return quant; }
int no(( %usca2maisesq(void)
{
if ((1this).esq""$) return info;
else return ((1this).esqM>%usca2maisesq());
//chamada recursiva.
}
no1 no((insere(int aintY res)
{
res"#;
if (this""?;BB) return neE no(a?;BB?;BB);
if (a>"info) if (dir""?;BB) dir"neE no(a?;BB?;BB);
else dir"(1dir).insere(ares);
else if (a<info) if (esq""?;BB) esq"neE no(a?;BB?;BB);
else esq"(1esq).insere(ares);
return this; //nao e necessario.
};
no1 no((remove(int %intY res)
{
int copy;
no1 delete2aux;
no1 return2aux; //usado para deletar um no
if (this""?;BB) {
res"D8B@=;
return ?;BB; //arvore ou su%arvore va3ia
}
else //not a nill pointer
if (%>(1this).info) (1this).dir"(1this).dirM>remove(%res);
if (%<(1this).info) (1this).esq"(1this).esqM>remove(%res);
if (%""(1this).info) //preciso deletar aqui
{
res"<';=;
if (((1this).dir""?;BB) YY ((1this).esq""?;BB)) //sem filhos
{
delete this;
return ?;BB;
}
else if ((1this).esq""?;BB) //como remover de lista linear
{
delete2aux"this;
return2aux"((1this).dir);
(1delete2aux).dir"?;BB; //evita deletar su%arvore
delete delete2aux;
return return2aux;
}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
107 - 03/06/14
else if ((1this).dir""?;BB) //como lista linear
{
delete2aux"this;
return2aux"(1this).esq;
(1delete2aux).esq"?;BB;
delete delete2aux; //nao esqueca
return return2aux;
}
else //o caso mais complicado
{
copy"(1this).dirM>%usca2maisesq();
info"copy;
(1this).dir"(1this).dirM>remove(copyres);
}
}
return this; //para muitos casos.
}
int no((%usca(int c)
{
if (this."?;BB)
if (c""info) return c;
else if (c>info) return ((1dir).%usca(c));
else return ((1esq).%usca(c));
else return Mc;
}
void no((in2order(void) //percurso in2order
{
if (this."?;BB)
{
cout << &(& ;
(1esq).in2order();
cout << info;
(1dir).in2order();
cout << &)&;
};
}
no((Hno(void)
{
if (this."?;BB)
{
quantMM;
if (dir."?;BB) delete dir; //primeiro chama destrutor depois deleta no
if (esq."?;BB) delete esq; //o destrutor e chamado para toda a arvore e entao
}
//ela volta deletando os nos
}
arv2%in((arv2%in(void)
{ ar"?;BB;}
arv2%in((arv2%in(int a)
{ ar"neE no(a);}
//inline
void arv2%in((insere(int aintY result)
{ ar"arM>insere(aresult); }
//inline
void arv2%in((remove(int aintY result)
{ ar"arM>remove(aresult);}
//inline
int arv2%in((%usca(int a)
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
108 - 03/06/14
{ return arM>%usca(a); }
//inline
void arv2%in((in2order(void)
{ arM>in2order(); }
arv2%in((Harv2%in()
{ delete ar; }
#include <iostream.h>
#include &%inatree.h&
main() //testa a arvore com menu.
{
int n; //lido para ser inserido ou removido.
int fla,;
arv2%in my2tree;
char option"FEF;
do
{
cout << endl;
cout << & AMAnsere*n&;
cout << & 'M'emove*n&;
cout << & ?MAn 6rder (5ercurso)*n&;
cout <<V & CMCusca*n&;
cout << & @M@air*n&;
cout << & =ntre opcao(&;
cout << & *n&;
cin >>option; //entre a opcao do menu
sEitch(option) //executes user option
{
case FAF(
case FiF(
cout << &*n >i,ite numero a inserir(&;
cin >> n;
cout << &*n&;
fla,"D8B@=;
my2tree.insere(nfla,);
cout << &fla,(&<<fla, << endl;
%rea[;
case F'F(
case FrF(
cout << &*n >i,ite numero a remover(&;
cin >> n;
cout << &*n&;
fla,"D8B@=;
my2tree.remove(nfla,);
cout << &fla,(&<<fla, << endl;
%rea[;
case F?F(
case FnF(
cout << &*n&;
my2tree.in2order();
cout << & & << no((quant << &(?os*n&;
cout << &*n&;
%rea[;
case FCF(
case F%F(
cout << &*n >i,ite numero a achar(&;
cin >> n;
cout << &*n&;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
109 - 03/06/14
cout << & & << my2tree.%usca(n);
cout << &*n&;
%rea[;
case F@F(
case FsF(
cout << &*n C+= *n&;
%rea[;
default( ;
} //sEitchMcase code %loc[
} Ehile ((option."FsF)YY(option."F@F));
cout << & ?odes(& << no((quant << endl;
return $;
}
Resulta! ! "#!$#a%a&
No pode ser exibido por ser muito extenso.
7.?.2. SIMULAO DIRIGIDA A E6ENTOS.
Este tpico o ltimo e o nico que ainda est sendo editado.
Este exemplo apresenta uma simulao dirigida a eventos. Simulamos um banco, as variveis da simulao
so: tempo mdio de entrada de clientes no banco, tempo mdio de atendimento, nmero de atendentes.
A linguagem precursora das atuais linguagens orientadas a objetos, Simula, no por acaso foi criada para
programar simulaes. Em programao orientada a objetos estamos frequentemente preocupados em modelar
entidades, objetos, do mundo real, justamente esta a tarefa de uma simulao.
Voc notar que nosso programa principal bastante pequeno. Ocorre que main usado para apenas
inicializar os objetos e a simulao, a maioria das aes ocorre atravs de chamadas de funes membro entre
os objetos, isto muito bom, evitamos ao mximo a presena de variveis locais e passagem por referncia.
Neste diagrama esto presentes as classes com que iremos trabalhar: costumer, clerk, scheduler, manager,
front_door, geometric. Costumer e clerk so subclasses de active, uma classe base abstrata. Manager,
costumer, clerk so objetos reais, existiriam no mundo real. Scheduler e front_door, geometric no so objetos
reis, so criados para auxiliar na simulao.
Nossa simulao do tipo discreta, dirigida a eventos, em contraposio com o tipo contnuo. Ou seja
estaremos atentos, monitorando,eventos tais como o fato de um cliente entrar no banco ou ser atendido e no
grandezas continuas como a vazo de uma bomba hidrulica ou a velocidade de um motor eltrico.
Nossa simulao dita discreta porque os eventos ocorrem em intervalos fixos de tempo e no entre eles, o
nmero desses intervalos escolhido pelo usurio e deve ser grande com relao aos tempos usados na
simulao (tempo mdio de atendimento, etc). Estes tempos mdios por serem inteiros devem ser escolhidos
de forma a no gerar casos degenerados, ou seja se voc estimou que em seu banco o tempo de atendimento
em geral trs vezes maior que o tempo mdio de entrada de clientes no banco, ento prefira uma relao do
tipo (27/9) ao envs de (9/3), esses tempos continuaro pequenos perto do tempo de duraco da simulao:
10000, porm no to pequenos que possam ser pouco [[dieresis]]representativos[[dieresis]] em termos de
tempos diferentes que podem ocorrer. Entenda por casos degenerados, casos que no sero capazes de
representar, modelar corretamente o que aconteceria em seu banco, fornecendo resultados discrepantes com
outras opes equivalentes (em termos de propores) de valores iniciais da simulao.
Um pouco sobre estatstica e probalilidade. Vamos precisar de conceitos de estatstica neste problema. A
tempo de atendimento de clientes segue usualmente uma distribuio geomtrica (lembre-se que em estatstica
existem distribuies discretas e contnuas), a nossa discreta. A linguagem s oferece a distribuio de
nmeros conhecida como uniforme ,aquela em que todos nmeros tem a mesma probabilidade de serem
sorteados, ela pode ser gerada por chamadas a funo rand() da [[dieresis]]library[[dieresis]] stdlib.h, rand()
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
110 - 03/06/14
gera nmeros pseudo-aleatrios na faixa de 0 at RAND_MAX (no se preocupe, RAND_MAX est definido na
stdlib.h e geralmente==32767).
Dizemos que rand() gera nmeros pseudo-aleatrios porque esta funo utiliza uma semente para gerar uma
sequncia de nmeros, esta sequncia de nmeros pode ser repetida, basta utilizar a mesma semente. Esta
possbilidade de repetio ser importante para realizar testes do programa, frequentemente o programador
deseja repetir o resultado da ltima execuo, isto s possvel se for fornecida a mesma semente de gerao
dos nmeros atravs de uma chamada a funo void srand(unsigned s) , j importada com as "libraries" que
voc utilizar na simulao.
Felizmente dispomos de uma maneira de construir um gerador de nmeros que obedecem uma distribuio
geomtrica, a partir de um gerador de nmeros aleatrios. A distribuio uniforme precisa como parametro um
valor mximo, enquanto que a geomtrica precisa de um valor mdio.
Na distribuio geomtrica, se um cliente atendido em um tempo mdio de 10, ento podemos dizer que se
ele tiver comeado a ser atendido agora, existe em mdia uma chance em dez de ele terminar de ser atendido
no prximo instante. Vamos supor que o cliente no foi atendido logo no primeiro instante, ento existe uma
chance em dez de ele ser atendido no prximo instante e assim por diante. As probabilidades so iguais e
independentes uma das outras. A soma das probabilidades de cada instante completa 1 no tempo mdio de
atendimento que no caso 10. Porm isto no significa que 10 um limite mximo, mas apenas a mdia!
Se a probabilidade p de o cliente ser atendido no instante atual p==(1/mdia) ento a probabilidade de ele no
ser atendido (1-p). Seguindo o raciocnio anterior, a probabilidade de o cliente ser atendido no primeiro tique
do relgio p. A probabilidade que o mesmo cliente seja atendido s no segundo tique igual a probabilidade
de ele no ser atendido no primeiro tique==(1-p) e OSP a probabilidade de ele ser atendido no segundo tique==p
(igual a p para todos os instantes isolados). Seguindo o mesmo raciocnio, a probabilidade de o cliente vir a ser
atendido s no terceiro tique (1-p)*(1-p)*p. A formula geral da probabilidade de um cliente esperar t tiques
enquanto atendido : p*((1-p)(t-1)).
Suponha que tomamos n=100 bolas, das quais pintamos (n/mdia) de branco e o restante de preto (mdia<n).
Chamemos de p a probabilidade de se retirar numa nica tentativa uma bola branca de nossas n bolas, p
igual a (1/mdia). A probabilidade do evento complementar (1-(1/mdia))==(1-p). A probabilidade de se obter
uma bola branca s na segunda retirada com reposio (1-p)*p, enquanto que s na terceira retirada (1-
p)*(1-p)*p e assim por diante, como no exemplo anterior.
Pois bem, as nossas n bolas podem ser vistas como os nmeros da distribuio uniforme gerada por rand().
Pintar de branco parte das bolas de branco e o restante de preto equivale a dividir o intervalo de 0 at
RAND_MAX em nmeros menores que ('8?>298)-#/mWdia)""Eays2to2occur (brancos) e nmeros
maiores que isso (pretos). Sortear uma bola e verificar a cor equivale a chamar rand() e ver em que intervalo
o resultado cai. Temos ento o procedimento para obter nmeros segundo uma distribuio geomtrica a partir
de um gerador de nmeros aleatrios. Construiremos uma classe em nosso programa para obter estes
nmeros, ser a classe geometric. Sua implementao est no arquivo geometric.cpp.
//Dile repair.h
//Keader file for costumerMservement simulation
#include <stdli%.h>
#include <iostream.h>
enum Coolean {D8B@=<';=}; //$ ou #
class scheduler; //classe nao real
class mana,er; //classe real
//class of ,eometricMdistri%ution random num%er ,enerators
class ,eometric{
int ,eo2max; //maximum value of random num%er
int Eays2to2occur; //no. Eays desired event can occur
pu%lic(
,eometric(dou%le meanint max);
int draE(); //return next random num%er
Coolean e2a,ora(void); //verifica se e a,ora que entra costumer
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
111 - 03/06/14
};
//8%stract %ase class of active o%!ects
class active{
active1 next; //nextMo%!ect pointer for lin[ed lists
pu%lic(
void set2next(active1 p) {next"p;}
active1 ,et2next(void) {return next;}
virtual void event()"$; //tri,,er scheduled event
};
//:lass for costumer o%!ects
class costumer(pu%lic active{
scheduler1 sp; //pointer to scheduler
mana,er1 mp; //pointer to service mana,er
,eometric ,; //random num%er ,enerator
Coolean is2up; //state2varia%le
int tot2up2time; //tempo total de pe
int up2time2start; //start of most recent upMperiod
static dou%le servedcost; //total num%er of served costumers
static dou%le Eaitedtime; //total Eaited time for all costumers
pu%lic(
costumer(dou%le meanint maxscheduler1 smana,er1 m);
void event(); //time to %e served
void served(); //:ome %ac[ home costumer. (`illed)
static dou%le ,2servedcost() {return servedcost;}
static dou%le ,2Eaitedtime() {return Eaitedtime;}
static int vivos; //numero de costumers vivos so p/de%u,,in,
Hcostumer() {vivosMM;} //so para controle de alocacao dinamica
};
//:lass for cler[ o%!ects
class cler[(pu%lic active{
scheduler1 sp; //pointer to scheduler
mana,er1 mp; //pointer to service mana,er
,eometric ,; //random num%er ,enerator
costumer1 Eor[p; //pointer to costumer under repair
Coolean is2%usy; //state varia%le
int %usy2time2start; //start of most recent %usy period
int tot2%usy2time; //total %usy time
pu%lic(
cler[(dou%le meanint maxscheduler1 smana,er1 m);
void event(); //time to complete repair
void serve(costumer1 p); //acept Eor[ assi,ment
int %usy2time(); //return total %usy time
};
class mana,er {
enum Eho {:6@<;9='@:B='`@?6?=};
Eho Eaitin,; //[ind of o%!ects in queue
active1 first; //points to first o%!ect in queue
active1 last; //points to last o%!ect in queue
dou%le llsum; //line len,ht sum (sum every tic[ Ehen Eith costumers)
int len,ht; //comprimento da fila
//5rivate functions for manipulatin, queue
void insert2first(active1 p)
{first"last"p; pM>set2next($);len,ht--;}
void insert(active1 p)
{lastM>set2next(p); pM>set2next($); last"p;len,ht--;}
void remove()
{first"firstM>,et2next();len,htMM;}
//vamos percorrer a lista e sortear cler[ desocupado
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
112 - 03/06/14
cler[1 escolhe2randomico(void)
{ //escolhe randomico
int posicao;
posicao"(rand() N len,ht)-#; //#..len,ht posicao a deletar
active1 corr"first; //corrente itera so%re lista
active1 prev"?;BB; //ainda nao esta so%re a lista
for (int i"$;i<(posicaoM#);i--) //i"local do previo ($...len,htM#)
{
prev"corr;
corr"corrM>,et2next(); //desloca ponteiros na lista
}
cler[1 retorne"(cler[1) corr; //type cast
if (last""corr) last"prev;
if (prev""?;BB) first"corrM>,et2next();
else prevM>set2next(corrM>,et2next());
len,htMM;
return retorne;
} //escolhe2randomico
pu%lic(
mana,er() {first"last"$; Eaitin,"?6?=;len,ht"$;llsum"$;}
void request2service(costumer1 p); //service request
costumer1 request2Eor[(cler[1 p); //Eor[ request
void tic[(void)
{ if (Eaitin,"":6@<;9='@) llsum-"len,ht;}
dou%le ,2llsum(void)
{ return llsum;}
Hmana,er()
{
Ehile (first."?;BB)
{active1 aux"first; first"firstM>,et2next(); delete aux;}
}
};
//:lass for scheduler
class front2door{
private(
dou%le media;
int maximo;
scheduler1 sp;
mana,er1 mp;
,eometric1 ,;
pu%lic(
void init(dou%le meanint maxscheduler1 smana,er1 m)
{
media"mean;
maximo"max;
sp"s;
mp"m;
,"neE ,eometric(meanmax);
}
void sorteia2cost(void)
{
costumer1 esquecame;
if (,M>e2a,ora()) esquecame"neE costumer(mediamaximospmp);
//nao se preocupe com delecao o costumer se pendura nas listas
//(this) e vai aca%ar sendo deletado pelo cler[
}
Hfront2door(void) { delete ,;}
};
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
113 - 03/06/14
class scheduler {
int cloc[; //simulation cloc[
int calendar2si3e; //si3e of calendar2queue array
active11 calendar; //pointer to calendar queue array
int index; //calendar queue array su%script for current time
front2door1 fd;
mana,er1 m;
pu%lic(
scheduler(int s3front2door1 fdpmana,er1 mp);
int time() {return cloc[;} //return time
void schedule(active1 pint delay); //schedule event
void run(int tic[s); //run simulation
Hscheduler(void)
{
for (int i"$;i<calendar2si3e;i--)
{
Ehile (calendarQiR."?;BB)
{
active1 aux;
aux"calendarQiR;
calendarQiR"calendarQiRM>,et2next();
delete aux;
}
}
}
};
//Dile ,eometrc.cpp
//@ource file for class ,eometric
#include <stdli%.h>
#include &repair.h&
#ifndef '8?>298)
#define '8?>298) J4VUV
#endif
//'8?>2:6;?< is num%er of different values that
//rand() can return
const dou%le '8?>2:6;?<"dou%le('8?>298))-#.$;
//Anitiali3e ,eometricMdistri%ution o%!ect
,eometric((,eometric(dou%le mean int max)
{
Eays2to2occur"int('8?>2:6;?</mean-$.I);
,eo2max"max;
}
//'eturn next ,eometrically distri%uted random num%er
int ,eometric((draE()
{
for (int i"#;i<,eo2max;i--)
if(rand()<Eays2to2occur) return i;
return ,eo2max;
}
Coolean ,eometric((e2a,ora(void)
{
return (rand()<Eays2to2occur); //chances de entrar a,ora pela porta
}
//Dile active.cpp
//@ource file for classes costumer and cler[
#include <iostream.h>
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
114 - 03/06/14
#include &repair.h&
//Anitiali3e costumer o%!ect and schedule first %rea[doEn
costumer((costumer(dou%le meanint maxscheduler1 smana,er1 m)(,(meanmax)
{
sp"s;
mp"m;
vivos--; //controle de alocacao dinamica.
tot2up2time"$;
is2up"<';=;
spM>schedule(this,.draE());
//up2time2start is not initiali3ed here %ut Ehen costumers enter in %an[
}
//'equest service for disa%led costumer
void costumer((event() //enterin, in the %an[ start countin, Eait time
{
is2up"D8B@=; //not outside the %an[
up2time2start"spM>time();
mpM>request2service(this); //entrou no %anco fica na fila ou vai direto ao caixa
}
//'eturn repaired costumer to service
void costumer((served() //may %e [illed deleted noE.
{
is2up"<';=;
tot2up2time-"spM>time()Mup2time2start;
Eaitedtime-"tot2up2time;
servedcost-"#;
}
//Anitiali3e cler[ o%!ect and if possi%le ,et o%!ectFs
//Dirst Eor[ assi,nment
cler[((cler[(dou%le meanint maxscheduler1 smana,er1 m)(,(meanmax)
{
sp"s;
mp"m;
tot2%usy2time"$;
Eor[p"mpM>request2Eor[(this);
if (Eor[p""$)
is2%usy"D8B@=;
else {
is2%usy"<';=;
%usy2time2start"spM>time();
spM>schedule(this,.draE());
}
}
//:omplete repair on current costumer; if possi%le ,et
//neE Eor[ assi,nment
void cler[((event()
{
tot2%usy2time-"spM>time()M%usy2time2start;
Eor[pM>served(); //,rava estatisticas.
delete Eor[p; //mata costumer
Eor[p"mpM>request2Eor[(this);
if (Eor[p""$) is2%usy"D8B@=;
else {
is2%usy"<';=;
%usy2time2start"spM>time();
spM>schedule(this,.draE());
}
}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
115 - 03/06/14
//8cept Eor[ assi,nment
void cler[((serve(costumer1 p)
{
Eor[p"p;
is2%usy"<';=;
%usy2time2start"spM>time(); //comeca contar tempo de ocupado
spM>schedule(this,.draE()); //me tire do atendimente daqui a ,.draE tempos
}
//'eturn total %usy time
int cler[((%usy2time()
{
int t"tot2%usy2time;
if (is2%usy) t-"spM>time()M%usy2time2start;
return t;
}
//Dile mana,er.cpp
//@ource file for class mana,er
#include <iostream.h>
#include &repair.h&
//Kandle service request from disa%led costumer
void mana,er((request2service(costumer1 p)
{
cler[1 q;
sEitch(Eaitin,) {
case :6@<;9='@(
insert(p);
return;
case :B='`@(
q"escolhe2randomico(); //pe,a um cler[ desocupado qualquer !a converte (cler[1)
if (first""?;BB) Eaitin,"?6?=;
qM>serve(p);
return;
case ?6?=(
Eaitin,":6@<;9='@;
insert2first(p);
return;
}
};
//Kandle Eor[ request from idle cler[
costumer1 mana,er((request2Eor[(cler[1 p)
{
costumer1 q;
sEitch (Eaitin,){
case :6@<;9='@(
q"(costumer1) first;
remove();
if (first""?;BB) Eaitin,"?6?=;
return q;
case :B='`@(
insert(p);
return ?;BB;
case ?6?=(
Eaitin,":B='`@;
insert2first(p);
return ?;BB;
}
return ?;BB;
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
116 - 03/06/14
}
//Dile schedule.cpp
//@ource file for class scheduler
#include <iostream.h>
#include &repair.h&
//:reate scheduler Eith calendar queue havin, s3 elements
scheduler((scheduler(int s3front2door1 fdpmana,er1 mn,rp)
{
fd"fdp; //arma3ena o front2door pointer
m"mn,rp; //arma3ena o mana,er pointer
cloc["$;
calendar2si3e"s3;
calendar"neE active1Qs3R;
for (int i"$;i<s3;i--) calendarQiR"$;
index"$;
}
//@chedule o%!ect 1p to receive event messa,e
//after delay tic[s have elapsed
void scheduler((schedule(active1 pint delay)
{
int t"index-delay;
if (t>"calendar2si3e) tM"calendar2si3e;
pM>set2next(calendarQtR);
calendarQtR"p;
}
//'un simulation for ,iven num%er of tic[s
void scheduler((run(int tic[s)
{
active1 p;
for (int i"$;i<tic[s;i--) {
fdM>sorteia2cost(); //a,enda entrada do novo costumer enquanto
//nao comecou a mexer em listas ainda senao corrompe estado
mM>tic[(); //fa3 mana,er ,ravar estatisticas das listas
Ehile((p"calendarQindexR)."$)
{ calendarQindexR"pM>,et2next();
pM>event();
}
cloc[--;
if (--index""calendar2si3e) index"$;
}
}
//Dile simula.cpp
//pro,rama demonstracao para simulacao de clienteMatendente
#include <iostream.h>
#include <stdli%.h>
#include &repair.h&
//iniciali3ando os mem%ros static da classe costumer
dou%le costumer((servedcost"$.$;
dou%le costumer((Eaitedtime"$.$;
int costumer((vivos"$; //para controle da alocacao dinamica
main()
{
//declaracao de variaveis o%tencao de valores do usuario
unsi,ned semente; //seed for rand()
int num2ad!; //numero de cler[s
dou%le m2mean; //tempo medio entre entradas no esta%elecimento
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
117 - 03/06/14
dou%le a2mean; //tempo medio de atendimento
cout << &?umero de atendentes]&;
cin >> num2ad!;
cout << &<empo medio de entrada de clientes pela porta]&;
cin >> m2mean;
cout << &<empo medio de servico atendimento]&;
cin >> a2mean;
cout << &@emente de numeros randomicos]&;
cin >> semente;
//@eed rand(); set max2time to ten times maximum of
//m2mean and a2mean
srand(semente);
int max2time"#$1int(m2mean>a2mean]m2mean(a2mean);
int i;
//:ria mana,er e scheduler
mana,er mn,r;
front2door criador;
scheduler sch(max2time-#YcriadorYmn,r);
criador.init(m2meanmax2timeYschYmn,r); //iniciali3a criador de costumers
//com as caracteristicas esperadas dos costumers como nao e construtor posso
//modificar as caracteristicas dos costumers durante pro,rama.
//:ria cler[s
cler[11 a2list"neE cler[1Qnum2ad!R;
for (i"$;i<num2ad!;i--)
a2listQiR"neE cler[(a2meanmax2timeYschYmn,r);
//Da3 sucessivos loops da simulacao; imprime estatisticas cumulativas
//depois de cada con!unto de iteracoes completo
char ch;
do
{
//7et num%er of tic[s for this run
int duration;
cout << &*n?um%er of time steps]&;
cin >> duration;
//'un duration
sch.run(duration);
//:695;<8 = A95'A9= <=956 9=>A6 >= DAB8 (por costumer)
lon, tempo2medio"(costumer((,2Eaitedtime())/(costumer((,2servedcost());
cout << &<empo medio na fila(& << tempo2medio << endl;
//computa e imprime utili3acao media dos atendentes
dou%le a2factor"#$$.$/dou%le(sch.time())/dou%le(num2ad!);
lon, tot2%usy2time"$;
for (i"$;i<num2ad!;i--)
tot2%usy2time-"a2listQiRM>%usy2time();
cout << &9edia da utili3acao dos atendentes(& << tot2%usy2time1a2factor<<&N*n&;
dou%le avll; //avera,e costumer line len,ht
avll"mn,r.,2llsum()/sch.time();
cout << &:omprimento medio da fila(& << avll << endl;
//>etermine if user Eants to do more runs
cout << &:lientes ainda nao atendidos(& << costumer((vivos << endl;
//estes ou estao na fila para serem atendidos ou se penduraram no
//calendar queue e so para controle da alocacao dinamica.
cout << &:ontinue (+/?)]&;
cin >> ch;
} Ehile (ch""FyF ZZ ch""FyF);
delete QRa2list;
return $;
}
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
118 - 03/06/14
//'=@;B<8>6@ >6 5'67'898 8 58'<A' >6@ ^8B6'=@ A?A:A8A@ >6 5'A9=A'6 <=@<=
//(<=@<= 8 @=7;A') D;A ^8'A8?>6 ;9 58'89=<'6 56' ^=O = ^=?>6 @= 6
//'=@;B<8>6 ='8 :6='=?<=.
//?umero de atendentes]#
//<empo medio de entrada de clientes pela porta]T
//<empo medio de servico atendimento]J
//@emente de numeros randomicos]J#P#U
//
//?um%er of time steps]I$$$
//<empo medio na fila(J
//9edia da utili3acao dos atendentes(JU.#PN
//:omprimento medio da fila($.#JTP
//:lientes ainda nao atendidos(#
//:ontinue (+/?)]y
//
//?um%er of time steps]#$$$$
//<empo medio na fila(P
//9edia da utili3acao dos atendentes(JV.VSJJN
//:omprimento medio da fila($.#IJUUV
//:lientes ainda nao atendidos(P
//:ontinue (+/?)]n
//
//?umero de atendentes]4
//<empo medio de entrada de clientes pela porta]T
//<empo medio de servico atendimento]J
//@emente de numeros randomicos]J#P#U
//
//?um%er of time steps]I$$$
//<empo medio na fila(4
//9edia da utili3acao dos atendentes(#T.JN
//:omprimento medio da fila($.$$TT
//:lientes ainda nao atendidos($
//:ontinue (+/?)]y
//
//?um%er of time steps]#$$$$
//<empo medio na fila(J
//9edia da utili3acao dos atendentes(#T.P$JJN
//:omprimento medio da fila($.$$UT
//:lientes ainda nao atendidos(4
//:ontinue (+/?)]
//
//?umero de atendentes]#
//<empo medio de entrada de clientes pela porta]U
//<empo medio de servico atendimento]J
//@emente de numeros randomicos]J#P#U
//
//?um%er of time steps]I$$$
//<empo medio na fila(P
//9edia da utili3acao dos atendentes(I$.$UN
//:omprimento medio da fila($.J#$P
//:lientes ainda nao atendidos($
//:ontinue (+/?)]y
//
//?um%er of time steps]#$$$$
//<empo medio na fila(I
//9edia da utili3acao dos atendentes(I#N
//:omprimento medio da fila($.JIUSJJ
//:lientes ainda nao atendidos(#
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a
119 - 03/06/14
//:ontinue (+/?)]
//
//?umero de atendentes]#
//<empo medio de entrada de clientes pela porta]T
//<empo medio de servico atendimento]I
//@emente de numeros randomicos]J#P#U
//
//?um%er of time steps]I$$$
//<empo medio na fila(##
//9edia da utili3acao dos atendentes(IS.IPN
//:omprimento medio da fila($.VU#U
//:lientes ainda nao atendidos(#
//:ontinue (+/?)]y
A p o s t i l a s e t u t o r i a i s n a r e a d e i n f o r m t i c a

You might also like