Polimorfismo
BCC 221 - Programa¸
c˜
ao Orientada a Objectos(POO)
Guillermo C´
amara-Ch´
avez
Departamento de Computa¸c˜ao - UFOP Baseado nos slides do Prof. Marco Antˆonio CarvalhoI
O Polimorfismo ´
e um recurso que nos permite programar
“em geral” ao inv´
es de programar espec´ıficamente ;
I
Vamos supor um programa que simula o movimento de v´
arios
Introdu¸c˜
ao
I
Trˆ
es classes representam os animais pesquisados:
I Peixe;
I Sapo;
I P´assaro
I
Todos herdam da classe Animal
I
Cada classe derivada implementa o m´
etodo mover();
I
O programa mant´
em um vetor de ponteiros para objetos
das classes derivadas da classe Animal
I
Para simular o movimento do animal, envia-se a mesma
Introdu¸c˜
ao (cont.)
I
Cada objeto responder´
a de uma maneira diferente;
I
A mensagem ´
e enviada genericamente
I
Cada objeto sabe como modificar sua posi¸
c˜
ao de acordo com
Introdu¸c˜
ao (cont.)
I
Atrav´
es do polimorfismo pode-se projetar e implementar
sistemas que sejam facilmente extens´ıveis
I
Novas classes podem ser adicionadas com pouca ou
mesmo nenhuma modifica¸
c˜
ao `
as partes gerais do programa
I
Por exemplo, se criarmos uma classe Tartaruga somente
precisamos implementar:
I a classe e,
I a parte da simula¸c˜ao que instˆancia o objeto
I
As partes que processam a classe Animal genericamente n˜
ao
Outro Exemplo
I
Vamos imaginar que temos um programa que controla um
jogo que cont´
em as seguintes classes/objetos/elementos
I Marciano;
I Plutoniano;
I RaioLaser;
I NaveEspacial.
I
Para gerenciar os elementos presentes na tela, mantemos um
vetor com ponteiros para objetos da classe ObjetoEspacial
I
Cada objeto possui um m´
etodo desenhar(), que o imprime na
Polimorfismo (cont.)
I
Para atualizar a tela do jogo, ´
e necess´
ario redesenhar todos
os seus elementos.
I
Enviar a mesma mensagem para cada objeto do vetor
I
M´
etodo desenhar():
I Cada objeto redefine este m´etodo para suas especificidades;
I A classe ObjetoEspacial determina que as classes derivadas o implementem.
I
Podem ser criadas novas classes para outros elementos do
jogo
I
Vamos supor um programa que simula diversos animais
emitindo sons.
I
Cada personagem emite seu pr´
oprio som
I Cada personagem ´e um objeto que invoca seu pr´oprio m´etodo emitirSom();
I A classe derivada sabe como deve ser implementado.
I
Em uma hierarquia de heran¸
ca, podemos criar uma classe
Mamifero, a partir dela derivam Boi, cachorro, gato, bode,
etc.
Implementa¸c˜
oes
c l a s s M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \ nsom de mamifero " ; } ; } ; c l a s s C a c h o r r o : p u b l i c M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \n woof woof " ; } ; } ; c l a s s Vaca : p u b l i c M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \n moo moo " ; } ; } ; c l a s s Bode : p u b l i c M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \n baa baa " ; } ; } ;i n t main ( ) { C a c h o r r o c a c h o r r o ; Vaca v a c a ; Bode bode ; Gato g a t o ; c a c h o r r o . e m i t i r S o m ( ) ; v a c a . e m i t i r S o m ( ) ; bode . e m i t i r S o m ( ) ; g a t o . e m i t i r S o m ( ) ; r e t u r n 0 ; }
Sem Polimorfismo (cont.)
woof woof moo moo baa baa meow meow
c l a s s M a m i f e r o { p u b l i c: v i r t u a l v o i d e m i t i r S o m ( ) {c o u t << " \ nsom de mamifero " ; } ; } ; c l a s s C a c h o r r o : p u b l i c M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \n woof woof " ; } ; } ; c l a s s Vaca : p u b l i c M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \n moo moo " ; } ; } ; c l a s s Bode : p u b l i c M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \n baa baa " ; } ; } ; c l a s s Gato : p u b l i c M a m i f e r o { p u b l i c: v o i d e m i t i r S o m ( ) {c o u t << " \n meow meow " ; } ;
Polimorfismo (cont.)
i n t main ( ) { M a m i f e r o ∗ p [ 5 ] = { new C a c h o r r o ( ) , new Vaca ( ) , new Bode ( ) , new Gato ( ) } ; } f o r (i n t i = 0 ; i < 5 ; i ++) { p [ i ]−> e m i t i r S o m ( ) ; } r e t u r n 0 ; }woof woof moo moo baa baa meow meow
Polimorfismo (cont.)
I
Como vimos na aula anterior, ´
e poss´ıvel realizar a convers˜
ao
de tipo entre classe base e derivada
I
Um objeto da classe base pode receber um objeto da classe
derivada
I
Tamb´
em ´
e poss´ıvel fazer o mesmo com ponteiros
I
Um ponteiro para a classe base pode apontar para um objeto
da classe derivada
Polimorfismo (cont.)
I
Note que a classe Derivada
redefine o m´
etodo print();
I
O m´
etodo original imprime
os atributos a, b e c;
I
O m´
etodo redefinido
acrescenta a impress˜
ao dos
atributos d , e e f .
Base –a: int –b: int –c: int +Base() +getABC() +setABC() +print() Derivada –d: int –e: int –f: int +Derivada() +getDEF()c l a s s Base { i n t a , b , c ; p u b l i c: Base (i n t a =0 ,i n t b =0 ,i n t c = 0 ) : a ( a ) , b ( b ) , c ( c ) { } v o i d p r i n t ( ) { c o u t << " \n Base : " << a << " ,"<< b << " ," <<c ; } } ; c l a s s D e r i v a d a : p u b l i c Base { i n t d , e , f ; p u b l i c: D e r i v a d a (i n t d =0 ,i n t e =0 ,i n t f = 0 ) : d ( d ) , e ( e ) , f ( f ) { } v o i d p r i n t ( ) { c o u t << " \n Derivada " << d << " ,"<< e << " ," <<f ; }
Polimorfismo (cont.)
#i n c l u d e <i o s t r e a m > #i n c l u d e " base . h " u s i n g n a m e s p a c e s t d ; i n t main ( ) { Base o b j B ( 1 , 2 , 3 ) , ∗ p o b j B=n u l l p t r; D e r i v a d a objD ( 4 , 5 , 6 ) , ∗ p o b j D=n u l l p t r; p o b j B = &o b j B ; p o b j B −>p r i n t ( ) ; p o b j D = &objD ; P−objD−>p r i n t ( ) ; p o b j B = &objD ; p o b j B −>p r i n t ( ) ;#i n c l u d e <i o s t r e a m > #i n c l u d e " base . h " u s i n g n a m e s p a c e s t d ; i n t main ( ) { Base o b j B ( 1 , 2 , 3 ) , ∗ p o b j B=n u l l p t r; D e r i v a d a objD ( 4 , 5 , 6 ) , ∗ p o b j D=n u l l p t r; p o b j B = &o b j B ; // aponta para objeto da classe Base
p o b j B −>p r i n t ( ) ; // invoca m´etodo da classe Base
p o b j D = &objD ; // aponta para objeto da classe Derivada
P−objD−>p r i n t ( ) ; // invoca m´etodo da classe Derivada
p o b j B = &objD ; // aponta para objeto da classe Derivada
p o b j B −>p r i n t ( ) ; // invoca m´etodo da classe Base
r e t u r n 0 ; }
Polimorfismo (cont.)
Base D e r i v a d a Base
I
Este tipo de constru¸
c˜
ao ´
e permitido pelo compilador por
conta do relacionamento de heran¸
ca
Polimorfismo (cont.)
I
A funcionalidade invocada depende do handle (tipo do
ponteiro ou referˆ
encia) utilizado para invoc´
a-la
I
N˜
ao depende do tipo do objeto apontado pelo handle.
I
Utilizando um tipo especial de m´
etodo podemos fazer com
que este comportamento seja invertido
#i n c l u d e <i o s t r e a m > #i n c l u d e " base . h " u s i n g n a m e s p a c e s t d ; i n t main ( ) { Base o b j B ( 1 , 2 , 3 ) , ∗ p o b j B=n u l l p t r; D e r i v a d a objD ( 4 , 5 , 6 ) , ∗ p o b j D=n u l l p t r; p o b j B = &o b j B ; // aponta para objeto da classe Base
p o b j B −>p r i n t ( ) ; // invoca m´etodo da classe Base // ERRO! n˜ao ´e poss´ıvel apontar para objeto da classe Base
p o b j D = &o b j B ;
// Erro! Um objeto da classe base n˜ao // ´e um objeto da classe derivada
p o b j D −>p r i n t ( ) ;
r e t u r n 0 ; }
Fun¸c˜
oes Virtuais
I
O tipo do handle determina a vers˜
ao de um m´
etodo que ser´
a
invocada
I N˜ao o tipo do objeto apontado
Base ∗ p o b j B=n u l l p t r; D e r i v a d a objD ( 4 , 5 , 6 ) ;
p o b j B = &objD ; // aponta para objeto da classe Derivada
I
Com fun¸
c˜
oes virtuais, ocorre o contr´
ario
I
O tipo do objeto apontado determina qual ser´
a a vers˜
ao do
Fun¸c˜
oes Virtuais (cont.)
I
Voltando ao exemplo do jogo espacial, cada classe derivada da
classe ObjetoEspacial define um objeto de formato
geom´
etrico diferente
I
Cada classe define seu pr´
oprio m´
etodo desenhar()
I
Podemos atrav´
es de um ponteiro para classe base invocar o
m´
etodo desenhar();
I
Por´
em, seria ´
util se o programa determinasse
dinamicamente (tempo de execu¸
c˜
ao) qual m´
etodo deve
I
Para permitir este tipo de comportamento dinˆ
amico,
declaramos na classe base o m´
etodo desenhar() como uma
fun¸
c˜
ao virtual
I O redefinimos nas classes derivadas;
I O m´etodo sobrescrito possui o mesmo prot´otipo do original (assinatura e tipo de retorno).
Fun¸c˜
oes Virtuais (cont.)
I
Para declararmos um m´
etodo como virtual, adicionamos a
palavra chave virtual antes de seu prot´
otipo
v i r t u a l v o i d d e s e n h a r ( )
I
Se uma classe n˜
ao sobrescrever um m´
etodo virtual, ela herda
I
Definindo o m´
etodo como virtual na classe base, ele
permanecer´
a assim por toda a hierarquia de heran¸
ca
I Mesmo que as classes derivadas a sobrescrevam e n˜ao a declarem como virtual novamente;
I E uma boa pr´´ atica declarar o m´etodo como virtual por toda a hierarquia de classes.
Resolu¸c˜
ao Est´
atica e Dinˆ
amica
I
As instru¸c˜
oes de chamada a m´
etodos n˜
ao virtuais s˜
ao
resolvidas em tempo de compila¸
c˜
ao
I E traduzidas em chamadas a fun¸c˜oes de endere¸co fixo;
I Isso faz com que a instru¸c˜ao seja vinculada `a fun¸c˜ao antes de sua execu¸c˜ao;
I
Resolu¸
c˜
ao Est´
atica
I Acontece quando invocamos um m´etodo atrav´es de um objeto, usando o operador .
Resolu¸c˜
ao Dinˆ
amica
I
Quando uma instru¸c˜
ao de chamada a um m´
etodo virtual ´
e
encontrada pelo compilador, ele n˜
ao tem como identificar
qual ´
e o m´
etodo associado em tempo de compila¸
c˜
ao.
I
Quando utilizamos ponteiros (ou referˆ
encias) para objetos,
o compilador n˜
ao conhece qual ´
e a classe do endere¸
co
contido no ponteiro antes de o programa ser executado;
I
A instru¸
c˜
ao ´
e avaliada em tempo de execu¸
c˜
ao;
Poligono –base –altura +setValores() +calculaArea() Retangulo +calculaArea() Triangulo +calculaArea()
Exemplo (cont.)
c l a s s P o l i g o n o { p r o t e c t e d: d o u b l e b a s e , a l t u r a ; p u b l i c: v o i d s e t V a l o r e s (d o u b l e a , d o u b l e b ) { b a s e=a ; a l t u r a=b ; } v i r t u a l d o u b l e a r e a (v o i d) { r e t u r n 0 ; }c l a s s R e t a n g u l o : p u b l i c P o l i g o n o { p u b l i c: d o u b l e a r e a (v o i d) { r e t u r n ( b a s e ∗ a l t u r a ) ; } } ; c l a s s T r i a n g u l o : p u b l i c P o l i g o n o { p u b l i c: d o u b l e a r e a (v o i d) { r e t u r n ( b a s e ∗ a l t u r a / 2 ) ; } } ;
Exemplo (cont.)
i n t main ( ) { R e t a n g u l o r e c t ; T r i a n g u l o t r g l ; P o l i g o n o p o l y ; P o l i g o n o ∗ p p o l y 1 = &r e c t ; P o l i g o n o ∗ p p o l y 2 = & t r g l ; P o l i g o n o ∗ p p o l y 3 = &p o l y ; p p o l y 1 −>s e t V a l o r e s ( 4 , 5 ) ; p p o l y 2 −>s e t V a l o r e s ( 4 , 5 ) ; p p o l y 3 −>s e t V a l o r e s ( 4 , 5 ) ; c o u t << p p o l y 1 −>a r e a ( ) << e n d l ; c o u t << p p o l y 2 −>a r e a ( ) << e n d l ; c o u t << p p o l y 3 −>a r e a ( ) << e n d l ;I
As trˆ
es classes (Poligono, Retangulo e Triangulo)
possuem os mesmos membros: base, altura, setValores()
e area().
I
area() foi definida como virtual porque ´
e redefinida depois
Outro Exemplo
I
Considere uma classe Ve´
ıculo com duas classes derivadas
Autom´
ovel e Bicicleta
I
Essas classes tˆ
em trˆ
es m´
etodos, definidos para ve´ıculos de
forma geral e redefinidas mais especificamente para
autom´
oveis e bicicletas;
I
As fun¸c˜
oes s˜
ao:
I VerificaLista(): para verificar o que precisa ser analisado no ve´ıculo;
I Reparar(): para realizar os reparos e a manuten¸c˜ao necess´aria
I Limpa(): para realizar procedimentos de limpeza do ve´ıculo
I
A aplica¸c˜
ao Oficina define um objeto que recebe objetos da
classe Ve´
ıculos.
I Para cada ve´ıculo recebido, a oficina executa na sequencia os trˆes m´etodos da classe Ve´ıculo.
Outro Exemplo (cont.)
c l a s s V e i c u l o { p u b l i c: v i r t u a l v o i d v e r i f i c a L i s t a ( ) { c o u t<<" \n Verifica Veiculo " ; } ; v i r t u a l v o i d r e p a r a r ( ) { c o u t<<" \n Repara Veiculo " ; } ; v i r t u a l v o i d l i m p a ( ) { c o u t<<" \n Limpa Veiculo " ; } ; } ;c l a s s A u t o m o v e l : p u b l i c V e i c u l o { p u b l i c: v o i d v e r i f i c a L i s t a ( ) {c o u t<<" \n Verifica Automovel " ; } ; v o i d r e p a r a r ( ) {c o u t<<" \n Repara Automovel " ; } ; v o i d l i m p a ( ) {c o u t<<" \n Limpa Automovel " ; } ; } ; c l a s s B i c i c l e t a : p u b l i c V e i c u l o { p u b l i c: v o i d v e r i f i c a L i s t a ( ) {c o u t<<" \n Verifica Bicicleta " ; } ; v o i d r e p a r a r ( ) {c o u t<<" \n Repara Bicicleta " ; } ; v o i d l i m p a ( ) {c o u t<<" \n Limpa Bicicleta " ; } ; } ;
Outro Exemplo (cont.)
I
N˜
ao h´
a como saber no momento de programa¸
c˜
ao se a
Oficina estar´
a recebendo um autom´
ovel ou uma bicicleta
I
O momento de decis˜
ao sobre qual m´
etodo ser´
a aplicado s´
o
c l a s s O f i c i n a { i n t R ; p u b l i c: V e i c u l o ∗ p r o x i m o ( ) ; v o i d m a n t e r ( V e i c u l o ∗ v ) ; i n t g e t R ( ) ; } ;
Outro Exemplo (cont.)
V e i c u l o ∗ O f i c i n a : : p r o x i m o ( ) { V e i c u l o ∗ v ; R = r a n d ( ) ; i f (R % 2 == 0 ) v = new A u t o m o v e l ( ) ; e l s e v = new B i c i c l e t a ( ) ; r e t u r n v ; } v o i d O f i c i n a : : m a n t e r ( V e i c u l o ∗ v ) { v−> V e r i f i c a L i s t a ( ) ; v−>R e p a r a r ( ) ; v−>Limpa ( ) ; } i n t O f i c i n a : : g e t R ( ) {i n t main ( ) { O f i c i n a Of ; V e i c u l o ∗ pv ; i n t n = 0 ; w h i l e ( n < 6 ) { pv = Of . p r o x i m o ( ) ; c o u t<<e n d l <<Of . g e t R ()<< e n d l ; Of . m a n t e r ( pv ) ; n++; d e l e t e pv ; } r e t u r n 0 ; }
Outro Exemplo (cont.)
Na tela ´
e mostrado
41 V e r i f i c a B i c i c l e t a R e p a r a B i c i c l e t a Limpa B i c i c l e t a 18467 V e r i f i c a B i c i c l e t a R e p a r a B i c i c l e t a Limpa B i c i c l e t a 6334 V e r i f i c a A u t o m o v e l 26500 V e r i f i c a A u t o m o v e l R e p a r a A u t o m o v e l Limpa A u t o m o v e l 19169 V e r i f i c a B i c i c l e t a R e p a r a B i c i c l e t a Limpa B i c i c l e t a 15724 V e r i f i c a A u t o m o v e lI
O m´
etodo Of.proximo() realiza uma atribui¸c˜
ao de
I um objeto Autom´ovel `a vari´avel R quando o valor do n´umero aleat´orio gerado ´e par.
I um objeto Bicicleta `a vari´avel R quando o valor do n´umero aleat´orio gerado ´e ´ımpar.
Sum´
ario das Atribu¸c˜
oes permitidas entre Ponteiros de
Classe Base e Derivada
I
Apesar de um objeto de uma classe derivada ser um objeto
da classe base, temos dois tipos de objetos completamente
diferentes.
I
um objeto de uma classe derivada pode ser tratado como
um objeto da classe base
Classe Base e Derivada (cont.)
I
O contr´
ario n˜
ao ´
e v´
alido (objeto da classe Base ser tratado
como da classe Derivada)
I Os membros da classe derivada s˜ao indefinidos para objetos da classe base;
I E poss´ıvel realizar um downcasting;´
Sum´
ario das Atribu¸c˜
oes Permitidas
Considere o seguinte caso:
c l a s s Base { p u b l i c: Base ( ) {} v o i d p r i n t ( ) { c o u t << " \n Base " ; } } ; c l a s s D e r i v a d a : p u b l i c Base { p u b l i c: D e r i v a d a ( ) { } v o i d p r i n t ( ) { c o u t << " \n Derivada " ; } i n t main ( ) { Base objB , ∗ p o b j B=n u l l p t r; D e r i v a d a objD , ∗ p o b j D=n u l l p t r; . . . r e t u r n 0 ; }
I
Apontar um ponteiro base para um objeto base ´
e simples
p o b j B = &o b j B ;
I
Apontar um ponteiro derivado para um objeto derivado ´
e
simples
Sum´
ario das Atribu¸c˜
oes Permitidas (cont.)
I
Apontar um ponteiro base para um objeto derivado ´
e
seguro
p o b j B = &objD ;
I O ponteiro deve ser utilizado apenas para realizar chamadas da classe base;
p o b j B −>p r i n t 2 ( ) ; // ERRO n˜ao ´e membro da classe Base
I Chamadas da classe derivada gerar˜ao erros, a n˜ao ser que seja utilizado downcasting, o que n˜ao ´e seguro
I
Apontar um ponteiro derivado para um objeto base gera
um erro de compila¸
c˜
ao
p o b j D = &o b j B ; // ERRO de compila¸c˜ao
Classes Abstratas e M´
etodos Virtuais Puros
I
Quando pensamos em classes, podemos pensar que os
programas as instanciar˜
ao, criando objetos daquele tipo
I Por´em, existem casos em que ´e ´util definir classes que n˜ao ser˜ao instanciadas nunca.
I
Tais classes s˜
ao denominadas classes abstratas
I Como s˜ao normalmente utilizadas como base em hierarquias de heran¸ca, tamb´em s˜ao conhecidas como classes base
abstratas.
I S˜ao classes “incompletas”, que devem ser completadas por classes derivadas;
Classes Abstratas
I
Classes que podem ser instanciadas s˜
ao chamadas de
classes concretas
I Providenciam implementa¸c˜ao para todos os m´etodos que definem.
I
O prop´
osito de uma classe base abstrata ´
e exatamente
I
Classes base abstratas s˜
ao gen´
ericas demais para
definirem com precis˜
ao objetos reais e serem instanciadas
I
As classes concretas cuidam das especificidades
necess´
arias para que objetos sejam bem modelados e
Classes Abstratas (cont.)
I
Em uma hierarquia de heran¸ca, n˜
ao ´
e obrigat´
oria a existˆ
encia
de uma base abstrata
I
Por´
em, bons projetos de engenharia de software possuem
hierarquias de heran¸
ca cujo topo ´
e formado por classes
abstratas;
I
Em alguns casos, classes abstratas constituem
completamente os primeiros n´ıveis de uma hierarquia de
heran¸
ca.
I
Uma classe ´
e determinada abstrata automaticamente
quando um ou mais de seus m´
etodos virtuais s˜
ao
M´
etodos Virtuais Puros
I
Para declararmos um m´
etodo como virtual puro, utilizamos a
seguinte sintaxe:
v i r t u a l v o i d p r i n t ( ) = 0 ;
I
O “=0” ´
e conhecido como especificador puro
I N˜ao se trata de atribui¸c˜ao;
I M´etodos virtuais n˜ao possuem implementa¸c˜ao;
I
A diferen¸
ca entre um m´
etodo virtual e um m´
etodo virtual
puro ´
e que o primeiro opcionalmente possui implementa¸
c˜
ao na
classe base
I
O segundo requer obrigatoriamente uma implementa¸
c˜
ao nas
M´
etodos Virtuais Puros (cont.)
I
Um m´
etodo virtual puro nunca ser´
a executada na classe base
I
Deve ser sobrescrita nas classes derivadas;
I
Serve para fornecer uma interface polim´
orfica para classes
I
Novamente, uma classe que possui um m´
etodo virtual
puro n˜
ao pode ser instanciada
I
Invocar um m´
etodo virtual puro geraria erro.
I
Pode-se declarar ponteiros para uma classe base abstrata e
Exemplo de Polimorfismo
A utiliza¸c˜
ao de polimorfismo ´
e particularmente eficiente na
implementa¸c˜
ao de sistemas de software em camadas
I
Como um sistema operacional;
I
Cada tipo de dispositivo f´ısico opera de uma forma diferente
I
Uma classe base abstrata pode ser utilizada para gerar
uma interface para todos os dispositivos
I Todo o comportamento necess´ario pode ser implementado como m´etodos virtuais puros;
I Cada dispositivo sobrescreve os m´etodos em suas pr´oprias classes, derividas da classe base abstrata.
I
Para cada novo dispositivo, instala-se o driver, que cont´
em
Outro Exemplo de Polimorfismo
Outro aplica¸c˜
ao ´
util do polimorfismo ´
e na cria¸
c˜
ao de classes de
iteradores
I
Iteradores s˜
ao utilizados para percorrer estruturas de dados ou
(cole¸c˜
oes)
I Vetores, listas, ´arvores, etc;
I Percorrem os objetos de uma agrega¸c˜ao sem expˆor sua implementa¸c˜ao interna
I
Pagamento de funcion´
arios: 4 tipos de funcion´
arios
1. Sal´ario fixo semanal;
2. Horistas (hora extra depois de 40 horas);
3. Comissionados;
4. Assalariados Comissionados
I
A id´
eia ´
e realizar o c´
alculo dos pagamentos utilizando
comportamento polim´
orfico.
I
Na aula sobre heran¸
ca, t´ınhamos apenas os dois ´
ultimos tipos
de funcion´
arios, em uma hierarquia de heran¸
ca.
I
Neste exemplo, n˜
ao h´
a uma classe que absorva o
comportamento das outras
I
Ser´
a necess´
ario criar uma outra classe que sirva de base para
os outras
I Representar´a um funcion´ario gen´erico
I Nome, sobrenome e documento s˜ao os atributos;
I Getters e setters para cada um dos atributos.
I Um print para todos os atributos.
Exemplo: Funcionarios (cont.)
I
Teremos quatro classes derivadas, cada uma representando
um tipo de funcion´
ario
I A diferen¸ca se d´a basicamente pela forma em que o pagamento ´e calculado (m´etodo earnings()).
Exemplo: Funcionarios (cont.)
Dada a hierarquia estabelecida e a necessidade de polimorfismo:
I
Os getters e setters da classe base ser˜
ao m´
etodos concretos;
I
O m´
etodo print ser´
a um m´
etodo virtual
I Ter´a implementa¸c˜ao, mas opcionalmente poder´a ser sobrescrito pelas classes derivadas.
I
O m´
etodo earnings ser´
a um m´
etodo virtual puro
I N˜ao ter´a implementa¸c˜ao e obrigatoriamente ser´a sobrescrito pelas classes derivadas.
#i f n d e f EMPLOYEE H
#d e f i n e EMPLOYEE H
#i n c l u d e <s t r i n g> // classe string padr˜ao C++
u s i n g s t d : :s t r i n g; c l a s s E m p l o y e e { s t r i n g f i r s t N a m e ; s t r i n g l a s t N a m e ; s t r i n g s o c i a l S e c u r i t y N u m b e r ; p u b l i c: E m p l o y e e (c o n s t s t r i n g=" " , c o n s t s t r i n g&=" " , c o n s t s t r i n g&=" " ) ; v o i d s e t F i r s t N a m e ( c o n s t s t r i n g& ) ; s t r i n g g e t F i r s t N a m e ( ) c o n s t; v o i d s e t L a s t N a m e ( c o n s t s t r i n g& ) ; s t r i n g g e t L a s t N a m e ( ) c o n s t;
Employee.h (cont.)
. . .
v o i d s e t S o c i a l S e c u r i t y N u m b e r ( c o n s t s t r i n g& ) ;
s t r i n g g e t S o c i a l S e c u r i t y N u m b e r ( ) c o n s t;
// a fun¸c˜ao virtual pura cria a classe b´asica abstrata Employee
v i r t u a l d o u b l e e a r n i n g s ( ) c o n s t = 0 ; // virtual pura
v i r t u a l v o i d p r i n t ( ) c o n s t; // virtual
} ; // fim da classe Employee
#i n c l u d e <i o s t r e a m >
u s i n g s t d : :c o u t;
#i n c l u d e " Employee . h " // Defini¸c˜ao da classe Employee // construtor E m p l o y e e : : E m p l o y e e ( c o n s t s t r i n g & f i r s t , c o n s t s t r i n g &l a s t , c o n s t s t r i n g &s s n ) : f i r s t N a m e ( f i r s t ) , l a s t N a m e ( l a s t ) , s o c i a l S e c u r i t y N u m b e r ( s s n ) {} } // fim do construtor Employee
Employee.cpp
// imprime informa¸c˜oes de Employee (virtual, mas n˜ao virtual pura)
v o i d E m p l o y e e : : p r i n t ( ) c o n s t
{
c o u t << g e t F i r s t N a m e ( ) << ’ ’ << g e t L a s t N a m e ( ) << " \ nsocial security number : "
<< g e t S o c i a l S e c u r i t y N u m b e r ( ) ; } // fim da fun¸c˜ao print
#i f n d e f HOURLY H
#d e f i n e HOURLY H
#i n c l u d e " Employee . h " // Defini¸c˜ao da classe Employee
c l a s s H o u r l y E m p l o y e e : p u b l i c E m p l o y e e {
d o u b l e wage ; // sal´ario por hora
d o u b l e h o u r s ; // horas trabalhadas durante a semana
p u b l i c: H o u r l y E m p l o y e e ( c o n s t s t r i n g &=" " , c o n s t s t r i n g &=" " , c o n s t s t r i n g &=" " , d o u b l e = 0 . 0 , d o u b l e = 0 . 0 ) ; v o i d setWage ( d o u b l e ) ; d o u b l e getWage ( ) c o n s t; v o i d s e t H o u r s ( d o u b l e ) ; d o u b l e g e t H o u r s ( ) c o n s t;
// palavra-chave virtual assinala inten¸c˜ao de sobrescrever
v i r t u a l d o u b l e e a r n i n g s ( ) c o n s t; // calcula os rendimentos
v i r t u a l v o i d p r i n t ( ) c o n s t; // imprime HourlyEmployee
HourlyEmployee.cpp
u s i n g s t d : :c o u t;
#i n c l u d e " H o u r l y E m p l o y e e . h " // Defini¸c˜ao da classe HourlyEmployee // construtor H o u r l y E m p l o y e e : : H o u r l y E m p l o y e e ( c o n s t s t r i n g & f i r s t , c o n s t s t r i n g &l a s t , c o n s t s t r i n g &s s n , d o u b l e h o u r l y W a g e , d o u b l e h o u r s W o r k e d ) : E m p l o y e e ( f i r s t , l a s t , s s n ) {
setWage ( h o u r l y W a g e ) ; // valida a remunera¸c˜ao por hora
s e t H o u r s ( h o u r s W o r k e d ) ; // valida as horas trabalhadas
// calcula os rendimentos;
// sobrescreve a fun¸c˜ao virtual pura earnings em Employee
d o u b l e H o u r l y E m p l o y e e : : e a r n i n g s ( ) c o n s t
{
i f ( g e t H o u r s ( ) <= 40 ) // nenhuma hora extra
r e t u r n getWage ( ) ∗ g e t H o u r s ( ) ;
e l s e
r e t u r n 40 ∗ getWage ( ) + ( ( g e t H o u r s ( ) − 40 ) ∗ getWage ( ) ∗ 1 . 5 ) ;
HourlyEmployee.cpp (cont.)
// imprime informa¸c˜oes do HourlyEmployee
v o i d H o u r l y E m p l o y e e : : p r i n t ( ) c o n s t
{
c o u t << " hourly employee : " ;
E m p l o y e e : : p r i n t ( ) ; // reutiliza¸c˜ao de c´odigo
c o u t << " \ nhourly wage : " << getWage ( ) << " ; hours worked : " << g e t H o u r s ( ) ; } // fim da fun¸c˜ao print
#i f n d e f SALARIED H
#d e f i n e SALARIED H
#i n c l u d e " Employee . h " // Defini¸c˜ao da classe Employee
c l a s s S a l a r i e d E m p l o y e e : p u b l i c E m p l o y e e {
d o u b l e w e e k l y S a l a r y ; // sal´ario por semana
p u b l i c:
S a l a r i e d E m p l o y e e ( c o n s t s t r i n g &=" " , c o n s t s t r i n g &=" " ,
c o n s t s t r i n g &=" " , d o u b l e = 0 . 0 ) ;
v o i d s e t W e e k l y S a l a r y ( d o u b l e ) ;
d o u b l e g e t W e e k l y S a l a r y ( ) c o n s t;
// palavra-chave virtual assinala inten¸c˜ao de sobrescrever
v i r t u a l d o u b l e e a r n i n g s ( ) c o n s t; // calcula os rendimentos
v i r t u a l v o i d p r i n t ( ) c o n s t; // imprime SalariedEmployee
} ; // fim da classe SalariedEmployee
SalariedEmployee.h
#i n c l u d e <i o s t r e a m > u s i n g s t d : :c o u t; #i n c l u d e " S a l a r i e d E m p l o y e e . h " // construtor S a l a r i e d E m p l o y e e : : S a l a r i e d E m p l o y e e ( c o n s t s t r i n g & f i r s t , c o n s t s t r i n g &l a s t , c o n s t s t r i n g &s s n , d o u b l e s a l a r y ) : E m p l o y e e ( f i r s t , l a s t , s s n ) { s e t W e e k l y S a l a r y ( s a l a r y ) ; } // fim do construtor SalariedEmployee// calcula os rendimentos;
// sobrescreve a fun¸c˜ao virtual pura earnings em Employee
d o u b l e S a l a r i e d E m p l o y e e : : e a r n i n g s ( ) c o n s t
{
r e t u r n g e t W e e k l y S a l a r y ( ) ; } // fim da fun¸c˜ao earnings
// imprime informa¸c˜oes de SalariedEmployee
v o i d S a l a r i e d E m p l o y e e : : p r i n t ( ) c o n s t
{
c o u t << " salaried employee : " ; E m p l o y e e : : p r i n t ( ) ;
c o u t << " \ nweekly salary : " << g e t W e e k l y S a l a r y ( ) ; } // fim da fun¸c˜ao print
ComissionEmployee.h
#i f n d e f COMMISSION H
#d e f i n e COMMISSION H
#i n c l u d e " Employee . h " // Defini¸c˜ao da classe Employee
c l a s s C o m m i s s i o n E m p l o y e e : p u b l i c E m p l o y e e {
d o u b l e g r o s s S a l e s ; // vendas brutas semanais
d o u b l e c o m m i s s i o n R a t e ; // porcentagem da comiss˜ao p u b l i c: C o m m i s s i o n E m p l o y e e ( c o n s t s t r i n g &=" " , c o n s t s t r i n g &=" " , c o n s t s t r i n g &=" " , d o u b l e = 0 . 0 , d o u b l e = 0 . 0 ) ; v o i d s e t C o m m i s s i o n R a t e ( d o u b l e ) ; d o u b l e g e t C o m m i s s i o n R a t e ( ) c o n s t; v o i d s e t G r o s s S a l e s ( d o u b l e ) ; d o u b l e g e t G r o s s S a l e s ( ) c o n s t;
// palavra-chave virtual assinala inten¸c˜ao de sobrescrever
#i n c l u d e <i o s t r e a m > u s i n g s t d : :c o u t; #i n c l u d e " C o m m i s s i o n E m p l o y e e . h " // construtor C o m m i s s i o n E m p l o y e e : : C o m m i s s i o n E m p l o y e e (c o n s t s t r i n g & f i r s t , c o n s t s t r i n g &l a s t , c o n s t s t r i n g &s s n , d o u b l e s a l e s , d o u b l e r a t e ) : E m p l o y e e ( f i r s t , l a s t , s s n ) { s e t G r o s s S a l e s ( s a l e s ) ; s e t C o m m i s s i o n R a t e ( r a t e ) ; } // fim do construtor CommissionEmployee
ComissionEmployee.cpp (cont.)
// calcula os rendimentos;
// sobrescreve a fun¸c˜ao virtual pura earnings em Employee
d o u b l e C o m m i s s i o n E m p l o y e e : : e a r n i n g s ( ) c o n s t
{
r e t u r n g e t C o m m i s s i o n R a t e ( ) ∗ g e t G r o s s S a l e s ( ) ; } // fim da fun¸c˜ao earnings
// imprime informa¸c˜oes do CommissionEmployee
v o i d C o m m i s s i o n E m p l o y e e : : p r i n t ( ) c o n s t { c o u t << " commission employee : " ; E m p l o y e e : : p r i n t ( ) ; // reutiliza¸c˜ao de c´odigo c o u t << " \ ngross sales : " << g e t G r o s s S a l e s ( ) << " ; commission rate : " << g e t C o m m i s s i o n R a t e ( ) ;
#i f n d e f BASEPLUS H
#d e f i n e BASEPLUS H
#i n c l u d e " C o m m i s s i o n E m p l o y e e . h "
c l a s s B a s e P l u s C o m m i s s i o n E m p l o y e e :
p u b l i c C o m m i s s i o n E m p l o y e e {
d o u b l e b a s e S a l a r y ; // sal´ario-base por semana
p u b l i c:
B a s e P l u s C o m m i s s i o n E m p l o y e e ( c o n s t s t r i n g &=" " ,
c o n s t s t r i n g &=" " , c o n s t s t r i n g &=" " , d o u b l e = 0 . 0 ,
d o u b l e = 0 . 0 , d o u b l e = 0 . 0 ) ;
v o i d s e t B a s e S a l a r y ( d o u b l e ) ; // configura o sal´ario-base
d o u b l e g e t B a s e S a l a r y ( ) c o n s t; // retorna o sal´ario-base // palavra-chave virtual assinala inten¸c˜ao de sobrescrever
v i r t u a l d o u b l e e a r n i n g s ( ) c o n s t; // calcula os rendimentos
v i r t u a l v o i d p r i n t ( ) c o n s t; // imprime o objeto BasePlusCom-missionEmployee
BasePlusComissionEmployee.cpp
#i n c l u d e <i o s t r e a m >
u s i n g s t d : :c o u t;
// Defini¸c˜ao da classe BasePlusCommissionEmployee
#i n c l u d e " B a s e P l u s C o m m i s s i o n E m p l o y e e . h " // construtor B a s e P l u s C o m m i s s i o n E m p l o y e e : : B a s e P l u s C o m m i s s i o n E m p l o y e e ( c o n s t s t r i n g & f i r s t , c o n s t s t r i n g &l a s t , c o n s t s t r i n g &s s n , d o u b l e s a l e s , d o u b l e r a t e , d o u b l e s a l a r y ) : C o m m i s s i o n E m p l o y e e ( f i r s t , l a s t , s s n , s a l e s , r a t e ) {
// calcula os rendimentos;
// sobrescreve a fun¸c˜ao virtual pura earnings em Employee
d o u b l e B a s e P l u s C o m m i s s i o n E m p l o y e e : : e a r n i n g s ( ) c o n s t
{
r e t u r n g e t B a s e S a l a r y ( ) +
C o m m i s s i o n E m p l o y e e : : e a r n i n g s ( ) ; } // fim da fun¸c˜ao earnings
// imprime informa¸c˜oes de BasePlusCommissionEmployee
v o i d B a s e P l u s C o m m i s s i o n E m p l o y e e : : p r i n t ( ) c o n s t
{
c o u t << " base - salaried " ;
C o m m i s s i o n E m p l o y e e : : p r i n t ( ) ; // reutiliza¸c˜ao de c´odigo
c o u t << " ; base salary : " << g e t B a s e S a l a r y ( ) ; } // fim da fun¸c˜ao print
Main.cpp
#i n c l u d e <i o s t r e a m >
#i n c l u d e <i o m a n i p >
u s i n g n a m e s p a c e s t d ;
#i n c l u d e <v e c t o r >
// inclui defini¸c˜oes de classes na hierarquia Employee
#i n c l u d e " Employee . h " #i n c l u d e " S a l a r i e d E m p l o y e e . h " #i n c l u d e " H o u r l y E m p l o y e e . h " #i n c l u d e " C o m m i s s i o n E m p l o y e e . h " #i n c l u d e " B a s e P l u s C o m m i s s i o n E m p l o y e e . h " v o i d v i r t u a l V i a P o i n t e r (c o n s t E m p l o y e e ∗ c o n s t) ; // prot´otipo
i n t main ( ) {
// configura a formata¸c˜ao de sa´ıda de ponto flutuante
c o u t << f i x e d << s e t p r e c i s i o n ( 2 ) ;
// cria objetos da classe derivada
S a l a r i e d E m p l o y e e s a l a r i e d E m p l o y e e ( " John " , " Smith " , " 111 -11 -1111 " , 800 ) ; H o u r l y E m p l o y e e h o u r l y E m p l o y e e ( " Karen " , " Price " , " 222 -22 -2222 " , 1 6 . 7 5 , 40 ) ; C o m m i s s i o n E m p l o y e e c o m m i s s i o n E m p l o y e e ( " Sue " , " Jones " , " 333 -33 -3333 " , 1 0 0 0 0 , . 0 6 ) ; B a s e P l u s C o m m i s s i o n E m p l o y e e b a s e P l u s C o m m i s s i o n E m p l o y e e ( " Bob " , " Lewis " , " 444 -44 -4444 " , 5 0 0 0 , . 0 4 , 300 ) ; . . .
Main.cpp (cont.)
c o u t << " Employees processed individually using static binding :\ n \ n " ;
// sa´ıda de info. e rendimentos dos Employees com vincula¸c˜ao est´atica
s a l a r i e d E m p l o y e e . p r i n t ( ) ; c o u t << " \ nearned $" << s a l a r i e d E m p l o y e e . e a r n i n g s ( ) ; h o u r l y E m p l o y e e . p r i n t ( ) ; c o u t << " \ nearned $" << h o u r l y E m p l o y e e . e a r n i n g s ( ) ; c o m m i s s i o n E m p l o y e e . p r i n t ( ) ; c o u t << " \ nearned $" << c o m m i s s i o n E m p l o y e e . e a r n i n g s ( ) ; b a s e P l u s C o m m i s s i o n E m p l o y e e . p r i n t ( ) ; c o u t << " \ nearned $" ’ << b a s e P l u s C o m m i s s i o n E m p l o y e e . earnings ();
// cria um vector a partir dos quatro ponteiros da classe b´asica
v e c t o r < E m p l o y e e ∗ > e m p l o y e e s ( 4 ) ;
// inicializa o vector com Employees
e m p l o y e e s [ 0 ] = &s a l a r i e d E m p l o y e e ; e m p l o y e e s [ 1 ] = &h o u r l y E m p l o y e e ; e m p l o y e e s [ 2 ] = &c o m m i s s i o n E m p l o y e e ;
e m p l o y e e s [ 3 ] = &b a s e P l u s C o m m i s s i o n E m p l o y e e ;
c o u t << " Employees processed polymorphically via dynamic binding :\ n \ n " ;
Main.cpp (cont.)
// chama virtualViaPointer para imprimir informa¸c˜oes e rendimentos // de cada Employee utilizando vincula¸c˜ao dinˆamica
c o u t << " Virtual function calls made off base - class pointers :\ n \ n " ;
f o r ( s i z e t i = 0 ; i < e m p l o y e e s . s i z e ( ) ; i++ ) v i r t u a l V i a P o i n t e r ( e m p l o y e e s [ i ] ) ;
// chama virtualViaReference para imprimir informa¸c˜oes // de cada Employee utilizando vincula¸c˜ao dinˆamica
c o u t << " Virtual function calls made off base - class re fer enc es :\ n \ n " ;
f o r ( s i z e t i = 0 ; i < e m p l o y e e s . s i z e ( ) ; i++ )
// observe o desreferenciamento
// chama fun¸c˜oes print e earnings virtual de Employee a partir de um // ponteiro de classe b´asica utilizando vincula¸c˜ao dinˆamica
v o i d v i r t u a l V i a P o i n t e r (c o n s t E m p l o y e e ∗ c o n s t b a s e C l a s s P t r ) {
b a s e C l a s s P t r −>p r i n t ( ) ;
c o u t << " \ nearned $" << b a s e C l a s s P t r −>e a r n i n g s ( ) ; } // fim da fun¸c˜ao virtualViaPointer
// chama fun¸c˜oes print e earnings virtual de Employee a partir de um // referˆencia de classe b´asica utilizando vincula¸c˜ao dinˆamica
v o i d v i r t u a l V i a R e f e r e n c e ( c o n s t E m p l o y e e &b a s e C l a s s R e f ) {
b a s e C l a s s R e f . p r i n t ( ) ;
c o u t << " \ nearned $" << b a s e C l a s s R e f . e a r n i n g s ( ) ; } // fim da fun¸c˜ao virtualViaReference