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