Aula 6
Classes que reservam recursos
externos
1
PilhaDeInt: interface
/** Representa pilhas de int.
@invariant itens aponta matriz com capacidade_actual itens e
capacidade_inicial <= capacidade_actual e
0 <= número_de_itens <= capacidade_actual. */
class PilhaDeInt {
public:
typedef int Item;
/** Constrói pilha vazia.
@pre V.
@post estáVazia(). */
PilhaDeInt();
/** Destrói a pilha.
@pre V.
@post recursos externos reservados foram libertados. */
~PilhaDeInt();
2
2003/2004
Programação Orientada para
Objectos
PilhaDeInt: interface
/** Devolve o item que está no topo da pilha.
@pre ¬estáVazia().
@post topo idêntico ao item no topo de *this. */
Item const& topo() const;
/** Indica se a pilha está vazia.
@pre V.
@post estáVazia = *this está vazia. */
bool estáVazia() const;
/** Devolve altura da pilha.
@pre V.
@post altura = altura de *this. */
int altura() const;
3
2003/2004
Programação Orientada para
Objectos
PilhaDeInt: interface
/** Põe um novo item na pilha (no topo).
@pre V.
@post *this contém um item adicional no topo igual a novo_item. */
void põe(Item const& novo_item);
/** Tira o item que está no topo da pilha.
@pre ¬estáVazia().
@post *this contém os itens originais menos o do topo. */
void tiraItem();
4
2003/2004
Programação Orientada para
Objectos
PilhaDeInt: implementação
private:
static int const capacidade_inicial = 32;
int capacidade_actual;
Item* itens;
int número_de_itens;
bool cumpreInvariante() const;
};
inline PilhaDeInt::PilhaDeInt()
: capacidade_actual(capacidade_inicial),
itens(new Item[capacidade_actual]),
número_de_itens(0)
{
assert(cumpreInvariante());
}
5
2003/2004
Programação Orientada para
Objectos
PilhaDeInt: implementação
inline PilhaDeInt::~PilhaDeInt()
{
assert(cumpreInvariante());
delete[] itens;
}
PilhaDeInt::Item const& PilhaDeInt::topo() const
{
assert(cumpreInvariante());
return itens[número_de_itens - 1];
}
6
2003/2004
Programação Orientada para
Objectos
PilhaDeInt: implementação
bool PilhaDeInt::estáVazia() const
{
assert(cumpreInvariante());
return altura() == 0;
}
int PilhaDeInt::altura() const
{
assert(cumpreInvariante());
return número_de_itens;
}
7
2003/2004
Programação Orientada para
Objectos
PilhaDeInt: implementação
void PilhaDeInt::põe(Item const& novo_item)
{
assert(cumpreInvariante());
if(número_de_itens == capacidade_actual) {
Item* novos_itens = new Item[capacidade_actual * 2];
for(int i = 0; i != número_de_itens; ++i)
novos_itens[i] = itens[i];
capacidade_actual *= 2;
delete[] itens;
itens = novos_itens;
}
itens[número_de_itens] = novo_item;
++número_de_itens;
assert(cumpreInvariante());
}
8
2003/2004
Programação Orientada para
Objectos
PilhaDeInt: implementação
void PilhaDeInt::tiraItem()
{
assert(cumpreInvariante());
assert(not estáVazia());
--número_de_itens;
assert(cumpreInvariante());
}
bool PilhaDeInt::cumpreInvariante() const
{
return capacidade_inicial <= capacidade_actual and
0 <= número_de_itens <= capacidade_actual;
}
9
2003/2004
Programação Orientada para
Objectos
Classes que reservam recursos externos
Princípios usados:
1.
2.
10
Todas as variáveis dinâmicas construídas
devem ser destruídas
A entidade encarregue de construir deve
tipicamente responsabilizar-se pela destruição:
política quem constrói, destrói
Recursos externos: memória, ficheiros, …
2003/2004
Programação Orientada para
Objectos
Construtor por cópia
O que sucede depois de:
PilhaDeInt p1;
PilhaDeInt p2 = p1;
// Ou PilhaDeInt p2(p1);
11
2003/2004
Programação Orientada para
Objectos
Construtor por cópia
p1: PilhaDeInt
itens: int*
capacidade_actual: int
32
:int[32]
itens[31]: int
…
itens[2]: int
número_de_itens: int
0
P2: PilhaDeInt
itens: int*
capacidade_actual: int
32
número_de_itens: int
itens[1]: int
0
itens[0]: int
As duas pilhas partilham
orgãos internos.
12
2003/2004
Programação Orientada para
Objectos
Construtor por cópia
13
O C++ fornece um construtor por cópia
implícito que se limita a construir os atributos
de instância da classe, copiando-os um a um
2003/2004
Programação Orientada para
Objectos
Valor vs. Referência
Semântica de valor:
Semântica de referência:
14
Iguais, mas independentes
Um novo nome para a mesma coisa (identidade)
Igualdade ≠ Identidade
2003/2004
Programação Orientada para
Objectos
Construtor por cópia: declaração
class PilhaDeInt {
public:
…
/** Constrói pilha igual a original.
@pre V.
@post *this = original. */
PilhaDeInt(PilhaDeInt const& original);
…
Sempre por referência!
private:
…
};
15
2003/2004
Programação Orientada para
Objectos
Construtor por cópia: definição
PilhaDeInt::PilhaDeInt(PilhaDeInt const& original)
: capacidade_actual(?),
itens(?),
número_de_itens(?)
{
assert(original.cumpreInvariante());
?
assert(cumpreInvariante());
// assert(*this == original) se definirmos o operador ==.
}
16
2003/2004
Programação Orientada para
Objectos
Construtor por cópia: definição
PilhaDeInt::PilhaDeInt(PilhaDeInt const& original)
: capacidade_actual(?),
itens(?),
número_de_itens(original.número_de_itens)
{
assert(original.cumpreInvariante());
?
assert(cumpreInvariante());
// assert(*this == original) se definirmos o operador ==.
}
17
2003/2004
Programação Orientada para
Objectos
Construtor por cópia: definição
PilhaDeInt::PilhaDeInt(PilhaDeInt const& original)
: capacidade_actual(original.capacidade_actual),
itens(new Item[capacidade_actual]),
número_de_itens(original.número_de_itens)
{
assert(original.cumpreInvariante());
?
assert(cumpreInvariante());
// assert(*this == original) se definirmos o operador ==.
}
18
2003/2004
Programação Orientada para
Objectos
Construtor por cópia: definição
PilhaDeInt::PilhaDeInt(PilhaDeInt const& original)
: capacidade_actual(original.capacidade_actual),
itens(new Item[capacidade_actual]),
número_de_itens(original.número_de_itens)
{
assert(original.cumpreInvariante());
for(int i = 0; i != número_de_itens; ++i)
itens[i] = original.itens[i];
assert(cumpreInvariante());
// assert(*this == original) se definirmos o operador ==.
}
19
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia
O que acontece depois de:
PilhaDeInt p1;
for(int i = 0; i != 3; ++i)
p1.põe(i);
PilhaDeInt p2;
p2 = p1;
20
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia
Fuga de memória.
:int[32]
:int[32]
itens[31]: int
itens[31]: int
…
…
32
itens[2]: int
itens[2]: int
número_de_itens: int
2
3
itens[1]: int
p1: PilhaDeInt
itens: int*
capacidade_actual: int
p2 PilhaDeInt
itens: int*
capacidade_actual: int
32
número_de_itens: int
itens[1]: int
3
0
1
itens[0]: int
itens[0]: int
0
As duas pilhas partilham
orgãos internos.
21
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia
Inicialização ≠ Atribuição
O C++ fornece implicitamente às classes um
operador de atribuição por cópia que atribui
cada uma das variáveis membro de instância
22
Já existe um objecto, que tem de mudar de valor
se existirem constantes ou referências de
instância este operador não é fornecido
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: declaração
class PilhaDeInt {
public:
…
/** Torna *this igual a modelo.
@pre V.
@post *this = modelo. */
PilhaDeInt& operator = (PilhaDeInt const& modelo);
…
private:
…
};
23
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
?
assert(cumpreInvariante());
// assert(*this == original) se definirmos o
operador ==.
}
24
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
?
capacidade_actual = modelo.capacidade_actual;
número_de_itens = modelo.número_de_itens;
assert(cumpreInvariante());
// assert(*this == original) se definirmos o
operador ==.
}
25
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
delete[] itens;
itens = new Item[modelo.capacidade_actual];
?
capacidade_actual = modelo.capacidade_actual;
número_de_itens = modelo.número_de_itens;
assert(cumpreInvariante());
// assert(*this == original) se definirmos o operador ==.
}
26
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
delete[] itens;
itens = new Item[modelo.capacidade_actual];
for(int i = 0; i != modelo.número_de_itens; ++i)
itens[i] = modelo.itens[i];
capacidade_actual = modelo.capacidade_actual;
número_de_itens = modelo.número_de_itens;
assert(cumpreInvariante());
// assert(*this == original) se definirmos o operador ==.
}
27
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia
O que deveria acontecer depois de:
PilhaDeInt p;
p.põe(1);
p.põe(2);
p = p;
28
Nada!
2003/2004
Programação Orientada para
Objectos
Mas o que acontece é…
p1: PilhaDeInt
itens: int*
capacidade_actual: int
:int[32]
:int[32]
itens[31]: int
itens[31]: int
…
…
itens[1]: int
itens[1]: int
2
?
itens[0]: int
itens[0]: int
1
?
32
número_de_itens: int
2
29
2003/2004
Lixo!
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
if(*this != modelo) {
Não está definido!
delete[] itens;
itens = new Item[modelo.capacidade_actual];
Mas, como
comparar pilhas?
for(int i = 0; i != modelo.número_de_itens; ++i)
itens[i] = modelo.itens[i];
capacidade_actual = modelo.capacidade_actual;
número_de_itens = modelo.número_de_itens;
}
assert(cumpreInvariante());
// assert(*this == modelo) se definirmos o operador ==.
}
30
2003/2004
Programação Orientada para
Objectos
Igualdade vs. Identidade
Identidade - Alteridade
Igualdade - Desigualdade
31
Se duas coisas são a mesma, então são iguais
Se duas coisas são diferentes, então são outras
Se duas coisas são iguais podem ou não ser a mesma
O endereço é que marca a identidade das instâncias
2003/2004
Programação Orientada para
Objectos
Igualdade vs. Identidade
Sejam i e j dois nomes de int
int i = 0;
int& j = i;
ou
Como saber se i e j
são a mesma variável?
int i = 0;
int j = i;
32
2003/2004
Programação Orientada para
Objectos
Igualdade vs. Identidade
Duas instâncias são a mesma se e só se
tiverem o mesmo endereço!
&i == &j é o mesmo que dizer que i e j
são o mesmo indivíduo ou instância
i == j não implica &i == &j
&i == &j implica i == j
33
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
if(&*this != &modelo) {
delete[] itens;
itens = new Item[modelo.capacidade_actual];
for(int i = 0; i != modelo.número_de_itens; ++i)
itens[i] = modelo.itens[i];
& e * são o
inverso um
do outro.
capacidade_actual = modelo.capacidade_actual;
número_de_itens = modelo.número_de_itens;
}
assert(cumpreInvariante());
// assert(*this == modelo) se definirmos o operador ==.
}
34
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
if(this != &modelo) {
delete[] itens;
itens = new Item[modelo.capacidade_actual];
for(int i = 0; i != modelo.número_de_itens; ++i)
itens[i] = modelo.itens[i];
capacidade_actual = modelo.capacidade_actual;
número_de_itens = modelo.número_de_itens;
}
assert(cumpreInvariante());
// assert(*this == modelo) se definirmos o operador ==.
}
35
2003/2004
Programação Orientada para
Objectos
Atribuição por cópia: definição
PilhaDeInt& PilhaDeInt::operator = (PilhaDeInt const& modelo)
{
assert(cumpreInvariante() and modelo.cumpreInvariante());
if(this != &modelo) {
if(capacidade_actual != modelo.capacidade_actual) {
delete[] itens;
itens = new Item[modelo.capacidade_actual];
}
for(int i = 0; i != modelo.número_de_itens; ++i)
itens[i] = modelo.itens[i];
Reciclagem
da matriz.
capacidade_actual = modelo.capacidade_actual;
número_de_itens = modelo.número_de_itens;
}
assert(cumpreInvariante());
// assert(*this == modelo) se definirmos o operador ==.
}
36
2003/2004
Programação Orientada para
Objectos
Classes que reservam recursos externos
Construção (Construtor por cópia)
Destruição (Destrutor)
Cópia (Operador de atribuição por cópia)
Igualdade ≠ Identidade
Semântica de valor vs. semântica de referência
37
2003/2004
Programação Orientada para
Objectos
Aula 6: Sumário
Classes que reservam recursos externos
38
Problemas comuns
Construtores e destrutores
Construção por cópia
Semântica de valor vs. semântica de referência
Atribuição por cópia
O exemplo das pilhas
2003/2004
Programação Orientada para
Objectos