Aula 7
Herança
1
Programação Orientada para Objectos

Conceitos fundamentais:



2
Herança
Polimorfismo
Ligação dinâmica
2003/2004
Programação Orientada para
Objectos
Empregado
class Empregado {
public:
Empregado(string const& nome, Sexo const sexo);
string const& nome() const;
Sexo sexo() const;
void mostra() const;
private:
string nome_;
Sexo sexo_;
};
inline Empregado::Empregado(string const& nome, Sexo const sexo)
: nome_(nome), sexo_(sexo)
{}
3
2003/2004
Programação Orientada para
Objectos
Empregado
inline string const& Empregado:: nome() const
{
return nome_;
}
inline Sexo Empregado:: sexo() const
{
return sexo_;
}
inline void Empregado:: mostra() const
{
cout << "Nome: " << nome() << endl
<< "Sexo: " << sexo() << endl;
}
4
2003/2004
Programação Orientada para
Objectos
Chefe
class Chefe {
public:
Chefe(string const& nome, Sexo const sexo, int const nível);
string const& nome() const;
Sexo sexo() const;
int nível() const;
void mostra() const;
private:
string nome_;
Sexo sexo_;
int nível_;
};
inline Chefe::Chefe(string const& nome, Sexo const sexo, int const nível)
: nome_(nome), sexo_(sexo), nível_(nível)
{ }
5
2003/2004
Programação Orientada para
Objectos
Chefe
inline string const& Chefe::nome() const
{
return nome_;
}
inline Sexo Chefe::sexo() const
{
return sexo_;
}
inline int Chefe::nível() const
{
return nível_;
}
inline void
{
cout <<
<<
<<
}
6
Chefe::mostra() const
"Nome: " << nome() << endl
"Sexo: " << sexo() << endl
"Nível: " << nível() << endl;
2003/2004
Programação Orientada para
Objectos
Problemas

Repetição de código


Não há relação explícita entre as duas
classes (o que é conceptualmente falso)

7
Quase tudo igual entre Empregado e Chefe
Empregado e Chefe são totalmente
independentes, embora se saiba que um chefe é
um empregado!
2003/2004
Programação Orientada para
Objectos
Instanciação vs. especialização

Eu sou um humano

Instanciação


Um humano é um mamífero

Especialização (ou generalização)

8
Relação entre uma instância ou objecto e a sua classe:
eu sou um objecto da classe dos humanos
Relação entre duas classes: os humanos são
mamíferos
2003/2004
Programação Orientada para
Objectos
Conceitos e implementações
Língua natural
C++
Classe:
Humano
Nome comum: “humano”
Definida como:
class Humano {
// ...
};
Nome próprio: "Zé"
"O Zé é um humano."
9
Variável: zé
Definição de variável:
Humano zé;
2003/2004
Programação Orientada para
Objectos
Relação de generalização
Empregado
Atributos
e operações
omitidos.
Relação de
generalização.
Chefe
10
2003/2004
Programação Orientada para
Objectos
Impacto da modelação da relação

Corte (ou slicing)
Chefe ana_maria(“Ana Maria”, feminino, 4);
Empregado sósia_da_ana_maria_como_empregado = ana_maria;


11
Cópia da Ana Maria cortando tudo aquilo que
a torna chefe.
Não é muito útil: a evitar!
2003/2004
Programação Orientada para
Objectos
Impacto da modelação da relação
list<Empregado*> empregados;
empregados.push_back(new Empregado("João Maria", masculino));
empregados.push_back(new Chefe("Ana Maria", feminino, 4));
...
for(list<Empregado*>::const_iterator i = empregados.begin();
i != empregados.end();
++i) {
(*i)->mostra();
cout << endl;
}
12
2003/2004
Programação Orientada para
Objectos
Representação da lista em UML
pessoal: list<Empregado*>
!
13
: Empregado*
: Empregado*
: Empregado
: Chefe
nome_ = “João Maria”
sexo_ = masculino
nome_ = “Ana Maria”
sexo_ = feminino
nível_ = 4
2003/2004
!
Ligação.
Programação Orientada para
Objectos
Impacto da modelação da relação:
Resultado desejado
Nome: João Maria
Sexo: masculino
Nome: Ana Maria
Sexo: feminino
Nível: 4
14
2003/2004
Programação Orientada para
Objectos
Solução 1:
distinção interna do tipo de Empregado
class Empregado {
public:
enum Tipo {empregado, chefe};
Empregado(Tipo const tipo,
string const& nome,
Sexo const sexo,
int const nível = 0);
string const& nome() const;
Sexo sexo() const;
int nível() const;
void mostra() const;
15
2003/2004
Programação Orientada para
Objectos
Solução 1:
distinção interna do tipo de Empregado
private:
string nome_;
Sexo sexo_;
int nível_;
Tipo tipo;
}
inline void Empregado::mostra() const
{
cout << “Nome: ” << nome() << endl
<< “Sexo: ” << sexo() << endl;
if(tipo == chefe)
cout << “Nível: “ << nível() << endl;
}
16
2003/2004
Uma só classe
representa todos os
tipos de empregados.
Programação Orientada para
Objectos
Problemas da solução 1



Construtor teria de prever todos os casos e verificar
todas as combinações impossíveis.
Todos os métodos com especializações para cada
tipo de empregado seriam monstruosos, dominados
por inúmeros e gigantescos switch…
Código:




17
difícil de compreender
difícil de estender
difícil de alterar
difícil de depurar
2003/2004
Programação Orientada para
Objectos
Solução 2:
um Empregado dentro de um Chefe
class Chefe {
public:
Chefe(string const& nome, Sexo const sexo, int const nível);
string const& nome() const;
Sexo sexo() const;
int nível() const;
void mostra() const;
private:
Empregado empregado;
int nível_;
};
18
2003/2004
Programação Orientada para
Objectos
Solução 2:
um Empregado dentro de um Chefe
...
inline void Chefe::mostra() const
{
empregado.mostra();
cout << "Nível: " << nível()
<< endl;
}
Duas classes:
• Chefe delega em empregado.
• Permite poupar código.
19
2003/2004
Programação Orientada para
Objectos
Problemas da solução 2



20
Ainda não é possível tratar um chefe como se
de um empregado se tratasse
Dá a sensação que os chefes possuem
fisicamente um pequenino homúnculo dentro
deles encarregue de trabalhar por eles...
O nosso código não corresponde ao que
queremos modelar, o que é sempre má ideia
2003/2004
Programação Orientada para
Objectos
Solução: herança pública
class Chefe : public Empregado {
public:
Chefe(string const& nome, Sexo const sexo, int const nível);
int nível() const;
void mostra() const;
private:
int nível_;
};
inline int Chefe::nível() const
{
return nível_;
}
21
2003/2004
Programação Orientada para
Objectos
Solução: herança pública

Ocultação (e especialização do método da classe base)
inline void Chefe::mostra() const
{
Empregado::mostra();
cout << "Nível: " << nível() << endl;
}

Construtor
inline Chefe::Chefe(string const& nome,
Sexo const sexo,
int const nível)
: ????
{}
22
2003/2004
Programação Orientada para
Objectos
Solução: herança pública

Ocultação (e especialização do método da classe base)
inline void Chefe::mostra() const
{
Empregado::mostra();
cout << "Nível: " << nível() << endl;
}

Construtor
inline Chefe::Chefe(string const& nome,
Sexo const sexo,
int const nível)
: nome_(nome), sexo_(sexo), nível_(nível)
{}
23
2003/2004
Programação Orientada para
Objectos
Solução: herança pública

Ocultação (e especialização do método da classe base)
inline void Chefe::mostra() const
{
Empregado::mostra();
cout << "Nível: " << nível() << endl;
}

Construtor
inline Chefe::Chefe(string const& nome,
Sexo const sexo,
int const nível)
: Empregado(nome, sexo), nível_(nível)
{}
24
2003/2004
Programação Orientada para
Objectos
Construção e destruição


25
Ordem de construção:

Primeiro as classes base, por ordem de
declaração no cabeçalho da classe derivada

Depois os atributos, por ordem de declaração no
corpo da classe

Finalmente é executado o corpo do construtor
Destruição ocorre pela ordem inversa!
2003/2004
Programação Orientada para
Objectos
Construção e destruição
class Z {
// ...
};
class D : public A, public B {
public:
D(int i, Z const& z);
~D();
...
private:
static int const dim = 10;
int i;
Z const z;
float m[dim];
int* pi;
};
26
D::D(int i, Z const& z)
: i(i), z(z), pi(new int(10))
{
for(int i = 0; i != dim; ++i)
m[i] = 0;
}
D::~D()
{
delete pi;
}
2003/2004
Programação Orientada para
Objectos
Ordem de construção

Construtor de A, para inicialização dos atributos herdados de A

Construtor de B, para inicialização dos atributos herdados de B

Construtor de int, para inicialização do atributo i

Construtor de Z, para inicialização do atributo constante z

Construtor de pi, para inicialização do atributo pi com o endereço de
uma nova variável dinâmica

Atributos de tipos básicos ou deles derivados não têm quaisquer
construtores invocados implicitamente (é o caso do atributo m)

Corpo do construtor, onde se inicializa a matriz m
27
2003/2004
Programação Orientada para
Objectos
Ordem de destruição

Primeiro é executado o corpo do destrutor

Depois são invocados os destrutores de todos os atributos de
instância da classe derivada, por ordem inversa de
declaração

Finalmente são invocados os destrutores de todas as classes
base por ordem inversa à do seu aparecimento na
especificação das heranças na definição da classe derivada
28
2003/2004
Programação Orientada para
Objectos
Conceitos e implementações
Língua natural
C++
Classe:
Humano
Nome comum: “humano”
Definida como:
class Humano {};
Nome próprio: "Zé"
"O Zé é um humano."
"Um humano é um mamífero", ou
"Qualquer humano é um mamífero".
29
Variável: zé
Definição de variável:
Humano zé;
Derivação de classe:
class Humano : public Mamífero {
};
2003/2004
Programação Orientada para
Objectos
Herança pública: questões



Qual é a base e qual é a derivada?
Qual o sentido (direcção) da relação é um?
Categorias de acesso




Ambas têm método mostra(). Que significa?


30
O que é privado na classe base não pode ser mexido na classe
derivada
O que é público na classe base pode ser mexido por toda a gente,
mesmo a classe derivada
Classe derivada tem acesso directo ao nome?
Classe derivada herdou da classe base, acrescentou inspector para o
nível e tem de especializar método mostra()
Fornece versão, ocultando e especializando a versão da classe base
2003/2004
Programação Orientada para
Objectos
Herança pública: questões
class D : public A, public B, public C {
...
};



Cria nova classe D derivada das classes base A, B e C
Classe derivada herda todos os membros das classes base
Membros privados da classe base não ficam acessíveis
directamente a partir dos métodos da classe derivada

31
Se não fosse assim, estar-se-ia a abrir a porta da parte privada de
uma classe a quem quer que definisse uma classe sua derivada,
violando-se com isso o princípio do encapsulamento
2003/2004
Programação Orientada para
Objectos
Herança pública

A herança ou derivação fez-se usando a
palavra chave public:


32
Membros públicos da classe base são herdados
como membros públicos da classe derivada (daí
que não seja necessário redefinir as operações
nome() e sexo())
Quaisquer instâncias da classe derivada são
compatíveis com instâncias da classe base, o
mesmo se passando com ponteiros e referências
2003/2004
Programação Orientada para
Objectos
Herança em C++

Possibilita
Chefe o_zé("Zé Maria", masculino, 4);
Empregado& de_novo_o_zé = o_zé;
Empregado* ponteiro_para_o_zé = &zé;
ou
void pagaSalário() // capaz de lidar com qualquer tipo específico de empregado.
{
// ...
}
33
2003/2004
Programação Orientada para
Objectos
Solução: completa?

Problema ainda não resolvido:
list<Empregado*> empregados;
empregados.push_back(new Empregado("João Maria", masculino));
empregados.push_back(new Chefe("Ana Maria", feminino, 4));
// ...
for(list<Empregado*>const_iterator i = empregados.begin();
i != empregados.end();
++i) {
(*i)->mostra();
cout << endl;
}
34
2003/2004
Programação Orientada para
Objectos
Diagrama UML
pessoal: list<Empregado*>
!
35
: Empregado*
: Empregado*
: Empregado
: Chefe
nome_ = “João Maria”
sexo_ = masculino
nome_ = “Ana Maria”
sexo_ = feminino
nível_ = 4
2003/2004
!
Ligação.
Programação Orientada para
Objectos
Solução: incompleta
Nome: João Maria
Sexo: masculino
Nome: Ana Maria
Sexo: feminino

36
Método mostra() executado aquando da invocação da
operação mostra() depende do ponteiro através do qual se
faz a invocação e não do tipo do objecto apontado!
2003/2004
Programação Orientada para
Objectos
Solução: incompleta


Ligação entre operação invocada e método
executado é estática (decidida pelo compilador)
Falta polimorfismo


37
Permite que operações realizadas sobre objectos
apontados por ponteiros de um único tipo terem
comportamentos diversos consoante o objecto apontado
Falta ligação dinâmica entre a operação invocada e
o método executado (decidida durante a execução
do programa)
2003/2004
Programação Orientada para
Objectos
Hierarquias de classes
Veículo
VeículoTerrestre
VeículoAéreo
Helicóptero
VeículoNaval
Avião
Hidroavião
38
2003/2004
Programação Orientada para
Objectos
Herança privada (I)



Métodos públicos da classe base tornam-se
privados da classe derivada!
Não é estabelecida relação é um entre a classe
derivada e a classe base
Estabelece tipo especial de relação: funciona como
um… mas…

39
Conceito a implementar diferente de outro com pequenas
variações (normalmente, restrições da interface)
2003/2004
Programação Orientada para
Objectos
Herança privada (II)
class PilhaDeInt {
public:
typedef ListaDeInt::Item Item;
class PilhaDeInt : private ListaDeInt {
public:
typedef ListaDeInt::Item Item;
int altura() const;
bool estáVazia() const;
int altura() const;
bool estáVazia() const;
Item const& topo() const;
Item const& topo() const;
Item& topo();
Item& topo();
void põe(Item const& novo_item);
void tiraItem();
private:
ListaDeInt lista;
};
40
void põe(Item const& novo_item);
void tiraItem();
};
2003/2004
Programação Orientada para
Objectos
Herança privada (III)
class PilhaDeInt : private ListaDeInt {
public:
using ListaDeInt::Item;
class PilhaDeInt : private ListaDeInt {
public:
using ListaDeInt::Item;
int altura() const;
using ListaDeInt::comprimento;
using ListaDeInt::estáVazia;
using ListaInt::estáVazia;
using ListaDeInt::trás;
Item const& topo() const;
using ListaDeInt::põeAtrás;
using ListaDeInt::tiraDeTrás;
Item& topo();
};
void põe(Item item);
void tiraItem();
};
41
2003/2004
Programação Orientada para
Objectos
Conceitos e implementações:
relações entre classes
Língua natural
C++
Associação simples:
“Os empregados têm
(estão associados a) um
chefe.”
class Empregado {
private:
Chefe* chefe;
};
Agregação:
“Uma turma tem (agrega)
alunos.”
class Turma {
private:
list<Aluno*> alunos;
};
Composição:
“Um humano tem (é
composto por) cabeça.”
42
class Humano {
private:
Cabeça cabeça;
};
2003/2004
Não há conceito
de posse:
tempos de vida
independentes
Relação possui um:
pode implicar o
controlo do tempo
de vida de um
objecto por outro
Relação é composto
por um: tempos de
vida relacionados
Programação Orientada para
Objectos
Aula 7: Sumário











43
Herança pública: relação é um.
A relação tem um. A relação é composto por um.
Ponteiros, referências e corte (slicing).
Derivação: classe base e classe derivada.
Construtores e destrutores com herança.
Ocultação.
Hierarquias de classes: derivações de derivações.
Possibilidade de herança múltipla.
Problemas por resolver: necessidade de polimorfismo.
Herança privada: redução/alteração de interfaces.
Políticas de acesso.
2003/2004
Programação Orientada para
Objectos
Download

Aula teórica - iscte-iul