• Nenhum resultado encontrado

DCC004 - Algoritmos e Estruturas de Dados II

N/A
N/A
Protected

Academic year: 2021

Share "DCC004 - Algoritmos e Estruturas de Dados II"

Copied!
69
0
0

Texto

(1)

Herança e Composição (Reuso)

DCC004 - Algoritmos e Estruturas de Dados II

Renato Martins

Email:

renato.martins@dcc.ufmg.br

https://www.dcc.ufmg.br/~renato.martins/courses/DCC004

(2)

2 DCC004 - Algoritmos e Estruturas de Dados II

Introdução

Técnica para reutilizar características de

uma classe na definição de outra classe

Hierarquia de classes

Terminologias relacionadas à Herança

Classes mais genéricas: superclasses

(pai)

Classes especializadas: subclasses

(3)

3 DCC004 - Algoritmos e Estruturas de Dados II

Introdução

Superclasses

Devem guardar membros em comum

Subclasses

Acrescentam novos membros

(especializam)

Componentes facilmente

reutilizáveis

(4)

4 DCC004 - Algoritmos e Estruturas de Dados II

Herança

Contexto de Classe

Classe C

Classe B

Classe A

(5)

5 DCC004 - Algoritmos e Estruturas de Dados II

Herança

Os atributos e métodos são herdados por

todos os objetos dos níveis mais baixos

Considerando o modificador de acesso

Diferentes subclasses podem herdar as

características de uma ou mais

superclasses

Herança simples

(6)

6 DCC004 - Algoritmos e Estruturas de Dados II

Herança

Reutilização de código

Compartilhar similaridades

Preservar as diferenças

Facilita a manutenção do sistema

Maior legibilidade do código existente

Quantidade menor de linhas de código

Alterações em poucas partes do código

(7)

7 DCC004 - Algoritmos e Estruturas de Dados II

(8)

8 DCC004 - Algoritmos e Estruturas de Dados II

Herança Simples

#ifndef PDS2_PESSOA_H

#define PDS2_PESSOA_H

#include

<string>

class

Pessoa {

private

:

const

std::string _nome;

public

:

Pessoa(std::string nome);

virtual

std::string

get_nome

()

const

;

};

#endif

#ifndef PDS2_ESTUDANTE_H

#define PDS2_ESTUDANTE_H

#include

"pessoa.h"

class

Estudante :

public

Pessoa {

private

:

const

int

_matricula;

public

:

Estudante(std::string nome,

int

matricula);

int

get_matricula

()

const

;

};

(9)

9 DCC004 - Algoritmos e Estruturas de Dados II

#ifndef PDS2_PESSOA_H

#define PDS2_PESSOA_H

#include

<string>

class

Pessoa {

private

:

const

std::string _nome;

public

:

Pessoa(std::string nome);

virtual

std::string

get_nome

()

const

;

};

#endif

#ifndef PDS2_ESTUDANTE_H

#define PDS2_ESTUDANTE_H

#include

"pessoa.h"

class

Estudante :

public

Pessoa {

private

:

const

int

_matricula;

public

:

Estudante(std::string nome,

int

matricula);

int

get_matricula

()

const

;

};

#endif

(10)

10 DCC004 - Algoritmos e Estruturas de Dados II

Uso

#include

<iostream>

#include

"estudante.h"

#include

"pessoa.h"

int

main

() {

Pessoa

pessoa

(

"Flavio F."

);

Estudante

estudante

(

"Jane Doe"

, 20180101);

std::cout <<

"A pessoa é: "

<< pessoa.get_nome() << std::endl;

std::cout <<

"O estudante é: "

<< estudante.get_nome() << std::endl;

return

0;

(11)

11 DCC004 - Algoritmos e Estruturas de Dados II

Note o uso de get_nome nos dois tipos

#include

<iostream>

#include

"estudante.h"

#include

"pessoa.h"

int

main

() {

Pessoa

pessoa

(

"Flavio F."

);

Estudante

estudante

(

"Jane Doe"

, 20180101);

std::cout <<

"A pessoa é: "

<< pessoa.get_nome() << std::endl;

std::cout <<

"O estudante é: "

<< estudante.get_nome() << std::endl;

return

0;

(12)

12 DCC004 - Algoritmos e Estruturas de Dados II

Implementação

Pessoa é uma classe normal

#include

"pessoa.h"

Pessoa::Pessoa(std::string nome):

_nome(nome) {}

std::string Pessoa::get_nome()

const

{

return

this

->_nome;

(13)

13 DCC004 - Algoritmos e Estruturas de Dados II

Estudante

#include

"estudante.h"

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

int

Estudante::get_matricula()

const

{

return

this

->_matricula;

}

Novamente uma classe quase normal

• Porém sem get_nome

(14)

14 DCC004 - Algoritmos e Estruturas de Dados II

Herança

Todo Estudante é uma Pessoa

Então:

Todo estudante tem um nome

Além de um método get_nome

(15)

15 DCC004 - Algoritmos e Estruturas de Dados II

Herança v. Interfaces

O método da interface é

virtual nome() = 0;

Em outras palavras:

Tem que ser implementado na

(16)

16 DCC004 - Algoritmos e Estruturas de Dados II

Herança v. Interfaces

Não temos get_nome abaixo

Foi herdado de Pessoa

#include

"estudante.h"

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

int

Estudante::get_matricula()

const

{

return

this

->_matricula;

(17)

17 DCC004 - Algoritmos e Estruturas de Dados II

Construtor "Initializer List"

Todo estudante é uma pessoa

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

Estudante

Pessoa

(18)

18 DCC004 - Algoritmos e Estruturas de Dados II

Construtor "Initializer List"

Temos que iniciar a memória da

Pessoa

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

Estudante

Pessoa

(19)

19 DCC004 - Algoritmos e Estruturas de Dados II

Construtor "Initializer List"

Ou seja, setar o nome nesse caso

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

Estudante

Pessoa

(20)

20 DCC004 - Algoritmos e Estruturas de Dados II

Construtor "Initializer List"

Depois do Estudante

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

Estudante

Pessoa

(21)

21 DCC004 - Algoritmos e Estruturas de Dados II

Construtor "Initializer List"

Setar o campo matricula

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

Estudante

Pessoa

(22)

22 DCC004 - Algoritmos e Estruturas de Dados II

Erro de compilação

Não iniciamos a parte pessoa

Estudante::Estudante(std::string nome,

int

matricula) {

this-

>_matricula = matricula;

}

Estudante

Pessoa

(23)

23 DCC004 - Algoritmos e Estruturas de Dados II

(Entendendo) Initializer List

Lembrando C++ a linha abaixo

chama

um construtor:

Pessoa p("Flavio F.");

Atalho para:

(24)

24 DCC004 - Algoritmos e Estruturas de Dados II

(Entendendo) Initializer List

Aqui é a mesma coisa:

Construa a Pessoa antes do Estudate

depois

Construa a matrícula

this->_matricula = matricula;

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

(25)

25 DCC004 - Algoritmos e Estruturas de Dados II

(26)

26 DCC004 - Algoritmos e Estruturas de Dados II

(27)

27 DCC004 - Algoritmos e Estruturas de Dados II

Herança simples

Métodos são sobrescritos (overriding)

Diferente de sobrecarga!

Mesma assinatura e tipo de retorno (!)

Métodos private não são sobrescritos

(28)

28 DCC004 - Algoritmos e Estruturas de Dados II

Herança simples

Métodos sobre escritos devem ser ‘virtuais’

Atributos não são redefiníveis

Se atributo de mesmo nome for definido na

subclasse, a definição na superclasse é ocultada

Membros estáticos

Não são redefinidos, mas ocultados

Como o acesso é feito pelo nome da classe,

estar ou não ocultado terá pouco efeito

(29)

29 DCC004 - Algoritmos e Estruturas de Dados II

Herança simples

Métodos sobre escritos devem ser

‘virtuais’

Lembre-se:

nomes iguais não definem uma conexão

(30)

30 DCC004 - Algoritmos e Estruturas de Dados II

Fonte de bugs

Dois métodos com o mesmo nome sem virtual

#ifndef PDS2_PESSOA_H

#define PDS2_PESSOA_H

#include

<string>

class

Pessoa {

private

:

const

std::string _nome;

public

:

Pessoa(std::string nome);

std::string

defina_meu_tipo

()

const

;

};

#endif

#ifndef PDS2_ESTUDANTE_H

#define PDS2_ESTUDANTE_H

#include

"pessoa.h"

class

Estudante :

public

Pessoa {

private

:

const

int

_matricula;

public

:

Estudante(std::string nome,

int

matricula);

int

get_matricula

()

const

;

std::string

defina_meu_tipo

()

const

;

};

(31)

31 DCC004 - Algoritmos e Estruturas de Dados II

Fonte de bugs

Mudando os .cpp (focando no método novo)

#include

"pessoa.h"

Pessoa::Pessoa(std::string nome):

_nome(nome) {}

std::string Pessoa::defina_meu_tipo()

const

{

return

"Sou uma pessoa!"

;

}

#include

"estudante.h"

Estudante::Estudante(std::string nome,

int

matricula):

Pessoa(nome), _matricula(matricula) {}

std::string Estudante::defina_meu_tipo()

const

{

return

"Sou um estudante"

;

(32)

32 DCC004 - Algoritmos e Estruturas de Dados II

Fonte de bugs

Qual a saída abaixo?!

#include

<iostream>

#include

"estudante.h"

#include

"pessoa.h"

void

f

(Pessoa

const

&pessoa) {

std::cout << "Na função: " << pessoa.defina_meu_tipo() << std::endl;

}

int

main

() {

Pessoa

pessoa

("Flavio F.");

Estudante

estudante

("Jane Doe",

20180101

);

std::cout << "A pessoa é: " << pessoa.defina_meu_tipo() << std::endl;

std::cout << "O estudante é: " << estudante.defina_meu_tipo() << std::endl;

f(pessoa);

f(estudante);

return

0

;

}

(33)

33 DCC004 - Algoritmos e Estruturas de Dados II

Fonte de bugs

Esquisito. Parece o oposto que vimos com Interfaces

$

./main

A pessoa é: Sou uma pessoa!

O estudante é: Sou um estudante

Na função: Sou uma pessoa!

(34)

34 DCC004 - Algoritmos e Estruturas de Dados II

Early Binding

Em tempo de compilação

$

./main

A pessoa é: Sou uma pessoa!

O estudante é: Sou um estudante

Na função: Sou uma pessoa!

Na função: Sou uma pessoa!

Sem virtual o compilador usa o tipo

mais próximo. Na função é Pessoa.

void

f

(Pessoa

const

&pessoa) {

std::cout << "Na função: " << pessoa.defina_meu_tipo() << std::endl;

}

(35)

35 DCC004 - Algoritmos e Estruturas de Dados II

Corrigindo

Usamos virtual

#ifndef PDS2_PESSOA_H

#define PDS2_PESSOA_H

#include

<string>

class

Pessoa {

private

:

const

std::string _nome;

public

:

Pessoa(std::string nome);

virtual

std::string

defina_meu_tipo

()

const

;

};

(36)

36 DCC004 - Algoritmos e Estruturas de Dados II

Corrigindo

Nos dois tipos

#ifndef PDS2_ESTUDANTE_H

#define PDS2_ESTUDANTE_H

#include

"pessoa.h"

class

Estudante :

public

Pessoa {

private

:

const

int

_matricula;

public

:

Estudante(std::string nome,

int

matricula);

int

get_matricula

()

const

;

virtual

std::string

defina_meu_tipo

()

const

;

};

(37)

37 DCC004 - Algoritmos e Estruturas de Dados II

Late Binding

Em tempo de execução

$

./main

A pessoa é: Sou um estudante

O estudante é: Sou um estudante

Na função: Sou uma pessoa!

Na função: Sou um estudante

O virtual faz o tipo ser definido em tempo

de execução. Ou seja, Estudante.

void

f

(Pessoa

const

&pessoa) {

std::cout << "Na função: " << pessoa.defina_meu_tipo() << std::endl;

}

(38)

38 DCC004 - Algoritmos e Estruturas de Dados II

Herança simples

(39)

39 DCC004 - Algoritmos e Estruturas de Dados II

Herança simples

(40)

40 DCC004 - Algoritmos e Estruturas de Dados II

Herança simples

(41)

41 DCC004 - Algoritmos e Estruturas de Dados II

Voltando para o caso das mensagens

Qual o comportamento comum?

(42)

42 DCC004 - Algoritmos e Estruturas de Dados II

Voltando para o caso das mensagens

Avatar, Datas

(43)

43 DCC004 - Algoritmos e Estruturas de Dados II

Redefinindo a Mensagem

3 tipos de métodos

#ifndef PDS2_MENSAGEM_H

#define PDS2_MENSAGEM_H

#include

<string>

#include

<ctime>

class

MensagemBase {

private

:

std::

time_t

_data;

std::string _avatar;

public

:

MensagemBase(std::string avatar);

std::

time_t

get_data()

const

;

virtual

std::string

get_avatar

()

const

;

virtual

void

exibir

()

const

= 0;

};

(44)

44 DCC004 - Algoritmos e Estruturas de Dados II

Redefinindo a Mensagem

time_t representa datas em C++ (segundos desde 01/01/1970)

#ifndef PDS2_MENSAGEM_H

#define PDS2_MENSAGEM_H

#include

<string>

#include

<ctime>

class

MensagemBase {

private

:

std::

time_t

_data;

std::string _avatar;

public

:

MensagemBase(std::string avatar);

std::

time_t

get_data()

const

;

virtual

std::string

get_avatar

()

const

;

virtual

void

exibir

()

const

= 0;

};

(45)

45 DCC004 - Algoritmos e Estruturas de Dados II

Redefinindo a Mensagem

Método que não é virtual, sem late binding

#ifndef PDS2_MENSAGEM_H

#define PDS2_MENSAGEM_H

#include

<string>

#include

<ctime>

class

MensagemBase {

private

:

std::

time_t

_data;

std::string _avatar;

public

:

MensagemBase(std::string avatar);

std::

time_t

get_data()

const

;

virtual

std::string

get_avatar

()

const

;

virtual

void

exibir

()

const

= 0;

};

(46)

46 DCC004 - Algoritmos e Estruturas de Dados II

Redefinindo a Mensagem

Nunca vamos redefinir, não precisamos de virtual

#ifndef PDS2_MENSAGEM_H

#define PDS2_MENSAGEM_H

#include

<string>

#include

<ctime>

class

MensagemBase {

private

:

std::

time_t

_data;

std::string _avatar;

public

:

MensagemBase(std::string avatar);

std::

time_t

get_data()

const

;

virtual

std::string

get_avatar

()

const

;

virtual

void

exibir

()

const

= 0;

};

(47)

47 DCC004 - Algoritmos e Estruturas de Dados II

Redefinindo a Mensagem

virtual, será re-definido

#ifndef PDS2_MENSAGEM_H

#define PDS2_MENSAGEM_H

#include

<string>

#include

<ctime>

class

MensagemBase {

private

:

std::

time_t

_data;

std::string _avatar;

public

:

MensagemBase(std::string avatar);

std::

time_t

get_data()

const

;

virtual

std::string

get_avatar

()

const

;

virtual

void

exibir

()

const

= 0;

};

(48)

48 DCC004 - Algoritmos e Estruturas de Dados II

Sobre o get_avatar

Note que as mensagens de texto não tem avatar.

Sobreescrever

(49)

49 DCC004 - Algoritmos e Estruturas de Dados II

Redefinindo a Mensagem

= 0; forçadamente tem que aparecer na sub-classe.

#ifndef PDS2_MENSAGEM_H

#define PDS2_MENSAGEM_H

#include

<string>

#include

<ctime>

class

MensagemBase {

private

:

std::

time_t

_data;

std::string _avatar;

public

:

MensagemBase(std::string avatar);

std::

time_t

get_data()

const

;

virtual

std::string

get_avatar

()

const

;

virtual

void

exibir

()

const

= 0;

};

(50)

50 DCC004 - Algoritmos e Estruturas de Dados II

Sobreescrevendo

A mensagem de texto "remove" o avatar

#include

"mensagemtexto.h"

#include

<iostream>

MensagemTexto::MensagemTexto(std::string avatar, std::string msg):

MensagemBase(avatar), _msg(msg) {}

void MensagemTexto::exibir() const {

std::cout << this->_msg;

std::cout << std::endl;

}

std::string MensagemTexto::get_avatar() const {

return

""

;

(51)

51 DCC004 - Algoritmos e Estruturas de Dados II

Sobreescrevendo

Porém é forçada a implementar o exibir (=0)

#include

"mensagemtexto.h"

#include

<iostream>

MensagemTexto::MensagemTexto(std::string avatar, std::string msg):

MensagemBase(avatar), _msg(msg) {}

void MensagemTexto::exibir() const {

std::cout << this->_msg;

std::cout << std::endl;

}

std::string MensagemTexto::get_avatar() const {

return

""

;

(52)

52 DCC004 - Algoritmos e Estruturas de Dados II

Mensagens de Audio

Usam o avatar default. Sobreescrevem o exibir apenas

#include

"mensagemvoz.h"

#include

<iostream>

MensagemVoz::MensagemVoz(std::string avatar, std::string arquivo):

MensagemBase(avatar), _arquivo(arquivo) {}

void

MensagemVoz::exibir()

const

{

std::cout <<

"Tocando o arquivo... "

;

std::cout <<

this

->_arquivo;

std::cout << std::endl;

}

(53)

53 DCC004 - Algoritmos e Estruturas de Dados II

Herança múltipla

Subclasse herda de mais de uma

superclasse

Nem todas as linguagens permitem isso

Problemas

Dificulta a manutenção do sistema

Também dificulta o entendimento

Reduz a modularização (super objetos)

Classes que herdam de todo mundo

Saída do preguiçoso

(54)

54 DCC004 - Algoritmos e Estruturas de Dados II

Imagens com Captions

(55)

55 DCC004 - Algoritmos e Estruturas de Dados II

Herança múltipla

MensagemBase

MensagemImagem

MensagemTexto

MensagemVoz

ImagemComCaptio

n

(56)

56 DCC004 - Algoritmos e Estruturas de Dados II

Herança múltipla

class ImagemComCaption : public MensagemImagem, public MensagemTexto {

};

Possível em C++

(57)

57 DCC004 - Algoritmos e Estruturas de Dados II

Herança múltipla

class ImagemComCaption : public MensagemImagem, public MensagemTexto {

};

Possível em C++

Nunca use.

(58)

58 DCC004 - Algoritmos e Estruturas de Dados II

Herança múltipla

+str getavatar()

MensagemBase

+str getavatar()

MensagemImagem

+str getavatar()

MensagemTexto

MensagemVoz

+str getavatar()

ImagemComCaptio

n

(59)

59 DCC004 - Algoritmos e Estruturas de Dados II

Herança múltipla

+str getavatar()

MensagemBase

+str getavatar()

MensagemImagem

+str getavatar()

MensagemTexto

MensagemVoz

+str getavatar()

ImagemComCaptio

n

(60)

60 DCC004 - Algoritmos e Estruturas de Dados II

Herança

Críticas

“Fere” o princípio do

encapsulamento

Membros fazem parte de várias classes

Cria interdependência entre classes

Mudanças em superclasses podem ser

difíceis

(61)

61 DCC004 - Algoritmos e Estruturas de Dados II

Herança

Críticas

“Fere” o princípio do encapsulamento

Membros fazem parte de várias classes

Cria interdependência entre classes

Mudanças em superclasses podem ser difíceis

Como resolver isso?

(62)

62 DCC004 - Algoritmos e Estruturas de Dados II

Herança vs. Composição

Herança

Relação do tipo “é um” (is-a)

Subclasse tratada como a superclasse

Estudante é uma Pessoa

Composição

Relação do tipo “tem um” (has-a)

Objeto possui objetos (≥1) de outras

classes

(63)

63 DCC004 - Algoritmos e Estruturas de Dados II

Composição

Técnica para criar um novo tipo não

pela derivação, mas pela junção de

outras classes de menor

complexidade

Não existe palavra-chave ou recurso

Conceito lógico de agrupamento

(64)

64 DCC004 - Algoritmos e Estruturas de Dados II

Composição

#ifndef PDS2_MENSAGEMCAPTION_H

#define PDS2_MENSAGEMCAPTION_H

#include

"mensagemimg.h"

#include

"mensagemtexto.h"

class

MensagemCaption :

public

MensagemBase {

private

:

MensagemImagem _img;

MensagemTexto _texto;

public

:

MensagemCaption(std::string avatar, MensagemImagem img,

MensagemTexto texto);

virtual

void

exibir

()

const

;

};

(65)

65 DCC004 - Algoritmos e Estruturas de Dados II

Composição

#ifndef PDS2_MENSAGEMCAPTION_H

#define PDS2_MENSAGEMCAPTION_H

#include

"mensagemimg.h"

#include

"mensagemtexto.h"

class

MensagemCaption :

public

MensagemBase {

private

:

MensagemImagem _img;

MensagemTexto _texto;

public

:

MensagemCaption(std::string avatar, MensagemImagem img,

MensagemTexto texto);

virtual

void

exibir

()

const

override;

};

#endif

Aind

a é

uma

me

nsa

gem

(66)

66 DCC004 - Algoritmos e Estruturas de Dados II

#include

"mensagemcaption.h"

MensagemCaption::MensagemCaption(std::string avatar,

MensagemImagem img,

MensagemTexto texto):

MensagemBase(avatar), _img(img), _texto(texto) {}

void

MensagemCaption::exibir()

const

{

this

->_img.exibir();

this

->_texto.exibir();

}

Composição

(67)

67 DCC004 - Algoritmos e Estruturas de Dados II

Composição

Ao invés de copiar o comportamento

Repassamos a responsabilidade

Boa prática!

Cada mensagem faz uma única coisa

(68)

68 DCC004 - Algoritmos e Estruturas de Dados II

Composição

Contexto de Objeto

Classe A

Classe B

Classe C

(69)

69 DCC004 - Algoritmos e Estruturas de Dados II

Composição

Ao invés de copiar o comportamento

Repassamos a responsabilidade

Boa prática!

Antes de usar herança pense:

(1) faz sentido a relação de é um (is-a)?

(2) a composição fica mais complicado?

Se qualquer um dos dois for não

Referências

Documentos relacionados

O quadro a seguir oferece uma visão geral das letras do alfabeto árabe, com sua forma isolada (podemos dizer que é a forma “plena” ou “original” da letra).

– Organize primary language tutors for student with limited proficiency (6 languages, 28 hours). – Monitor progress using ELPAC, ADEPT, District Assessment and

O Coletivo nega é mais uma dessas vozes que fala Salloma Salomão e que emerge na ilha da magia contra o branqueamento, higienização e gentrificação, mas que além da luta comum

As interseções com o eixo X representam as raízes

 O trabalho efetuado por um gás que se expande contra uma pressão externa

Os índices de diversidade de Shannon, Simpson e a equitatividade foram calculadas a partir dos indivíduos identificados utilizando os valores de densidade de organismos da classe

No caso de despesas com pessoal técnico do promotor e de entidades externas, o valor do Investimento resulta do somatório dos produtos resultantes da multiplicação do n.º de

Considerando as especificações e quantitativos estabelecidos para o objeto, informar, sempre que possível, os preços das últimas aquisições/contratações (se tiver