1 aula 6 classes que reservam recursos externos. 2003/2004 programação orientada para objectos 2...
TRANSCRIPT
1
Aula 6
Classes que reservam recursos externos
2003/2004 Programação Orientada para
Objectos2
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();
2003/2004 Programação Orientada para
Objectos3
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;
2003/2004 Programação Orientada para
Objectos4
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();
2003/2004 Programação Orientada para
Objectos5
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());}
2003/2004 Programação Orientada para
Objectos6
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];}
2003/2004 Programação Orientada para
Objectos7
PilhaDeInt: implementação
bool PilhaDeInt::estáVazia() const{ assert(cumpreInvariante());
return altura() == 0;}
int PilhaDeInt::altura() const{ assert(cumpreInvariante());
return número_de_itens;}
2003/2004 Programação Orientada para
Objectos8
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());}
2003/2004 Programação Orientada para
Objectos9
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; }
2003/2004 Programação Orientada para
Objectos10
Classes que reservam recursos externos
Princípios usados:1. Todas as variáveis dinâmicas construídas
devem ser destruídas
2. 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
Objectos11
Construtor por cópia
O que sucede depois de:
PilhaDeInt p1;PilhaDeInt p2 = p1;// Ou PilhaDeInt p2(p1);
2003/2004 Programação Orientada para
Objectos12
Construtor por cópia
itens[0]: int
itens[1]: int
itens[2]: int
itens[31]: int
:int[32]
…
0
número_de_itens: int
32
capacidade_actual: int
p1: PilhaDeInt
itens: int*
0
número_de_itens: int
32
capacidade_actual: int
P2: PilhaDeInt
itens: int*
As duas pilhas partilham orgãos internos.
2003/2004 Programação Orientada para
Objectos13
Construtor por cópia
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
Objectos14
Valor vs. Referência
Semântica de valor: Iguais, mas independentes
Semântica de referência: Um novo nome para a mesma coisa (identidade)
Igualdade ≠ Identidade
2003/2004 Programação Orientada para
Objectos15
Construtor por cópia: declaração
class PilhaDeInt { public: … /** Constrói pilha igual a original. @pre V. @post *this = original. */ PilhaDeInt(PilhaDeInt const& original); …
private: …};
Sempre por referência!
2003/2004 Programação Orientada para
Objectos16
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 ==.}
2003/2004 Programação Orientada para
Objectos17
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 ==.}
2003/2004 Programação Orientada para
Objectos18
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 ==.}
2003/2004 Programação Orientada para
Objectos19
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 ==.}
2003/2004 Programação Orientada para
Objectos20
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;
2003/2004 Programação Orientada para
Objectos21
3
número_de_itens: int
32
capacidade_actual: int
p2 PilhaDeInt
itens: int*
Atribuição por cópia
0
itens[0]: int
1
itens[1]: int
2
itens[2]: int
itens[31]: int
:int[32]
…
3
número_de_itens: int
32
capacidade_actual: int
p1: PilhaDeInt
itens: int*
0
número_de_itens: int
32
capacidade_actual: int
p2 PilhaDeInt
itens: int*
itens[0]: int
itens[1]: int
itens[2]: int
itens[31]: int
:int[32]
…
As duas pilhas partilham orgãos internos.
Fuga de memória.
2003/2004 Programação Orientada para
Objectos22
Atribuição por cópia
Inicialização ≠ Atribuição Já existe um objecto, que tem de mudar de valor
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 se existirem constantes ou referências de
instância este operador não é fornecido
2003/2004 Programação Orientada para
Objectos23
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: …};
2003/2004 Programação Orientada para
Objectos24
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 ==.}
2003/2004 Programação Orientada para
Objectos25
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 ==.}
2003/2004 Programação Orientada para
Objectos26
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 ==.}
2003/2004 Programação Orientada para
Objectos27
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 ==.}
2003/2004 Programação Orientada para
Objectos28
Atribuição por cópia
O que deveria acontecer depois de:
PilhaDeInt p;
p.põe(1);p.põe(2);
p = p; Nada!
2003/2004 Programação Orientada para
Objectos29
Mas o que acontece é…
1
itens[0]: int
2
itens[1]: int
itens[31]: int
:int[32]
…
2
número_de_itens: int
32
capacidade_actual: int
p1: PilhaDeInt
itens: int*
?
itens[0]: int
?
itens[1]: int
itens[31]: int
:int[32]
…
Lixo!
2003/2004 Programação Orientada para
Objectos30
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 ==.}
Não está definido!
Mas, como comparar pilhas?
2003/2004 Programação Orientada para
Objectos31
Igualdade vs. Identidade
Identidade - Alteridade Se duas coisas são a mesma, então são iguais
Igualdade - Desigualdade 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
Objectos32
Igualdade vs. Identidade
Sejam i e j dois nomes de int
int i = 0;int& j = i;
ou
int i = 0;int j = i;
Como saber se i e j são a mesma variável?
2003/2004 Programação Orientada para
Objectos33
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
2003/2004 Programação Orientada para
Objectos34
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 ==.}
& e * são o inverso um do outro.
2003/2004 Programação Orientada para
Objectos35
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 ==.}
2003/2004 Programação Orientada para
Objectos36
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];
capacidade_actual = modelo.capacidade_actual; número_de_itens = modelo.número_de_itens; }
assert(cumpreInvariante()); // assert(*this == modelo) se definirmos o operador ==.}
Reciclagem da matriz.
2003/2004 Programação Orientada para
Objectos37
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
2003/2004 Programação Orientada para
Objectos38
Aula 6: Sumário
Classes que reservam recursos externos 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