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
Download

Aula teórica - iscte-iul