Uma função de destruição pode ser uma função virtual .

17
ma função de destruição pode ser uma função virtual 3.4. Destrutor virtual (virtual destrutor) Vamos considerar o seguinte programa: ss B int* a; lic: B() { a = new int[2]; cout << "constr_B\n"; } ~B(){ delete[] a; cout << "destr_B\n"; } class D : public B { int* b; public: D() { b = new int[4]; cout << "constr_D\n"; ~D(){ delete[] b; cout << "destr_D\n"; }; main(int argc, char* argv[]) B *pb = new D; delete pb; return 0; } constr_B constr_D destr_B Os resultados:

description

Uma função de destruição pode ser uma função virtual. 3.4. Destrutor virtual ( virtual destrutor ). Vamos considerar o seguinte programa:. class B { int* a; public: B() { a = new int[2]; cout

Transcript of Uma função de destruição pode ser uma função virtual .

Page 1: Uma função de destruição pode ser uma função  virtual .

Uma função de destruição pode ser uma função virtual.

3.4. Destrutor virtual (virtual destrutor)

Vamos considerar o seguinte programa:

class B { int* a;public: B() { a = new int[2];

cout << "constr_B\n"; } ~B(){ delete[] a;

cout << "destr_B\n"; }};

class D : public B { int* b;public: D() { b = new int[4];

cout << "constr_D\n"; } ~D(){ delete[] b;

cout << "destr_D\n"; }};

int main(int argc, char* argv[]){ B *pb = new D;

delete pb;return 0; }

constr_Bconstr_Ddestr_B

Os resultados:

Page 2: Uma função de destruição pode ser uma função  virtual .

constr_Bconstr_Ddestr_B

a = new int[2];memória

b = new int[4];

delete[] a;

A ordem pela qual os construtores são chamados é a seguinte:

os primeiros construtores a seremchamados são os da classe base e só depoisos construtores da classe derivada.

Os destrutores devem ser chamadosexactamente pela ordem inversa.

Neste exemplo temos o problema comas chamadas dos destrutores.

Page 3: Uma função de destruição pode ser uma função  virtual .

Este problema é completamente resolvido se o destrutor fossevirtual.

class B { int* a;public: B() { a = new int[2];

cout << "constr_B\n"; } virtual ~B(){ delete[] a;

cout << "destr_B\n"; }};

class D : public B { int* b;public: D() { b = new int[4];

cout << "constr_D\n"; } virtual ~D(){ delete[] b;

cout << "destr_D\n"; }};

constr_Bconstr_Ddestr_Ddestr_B

Os resultados:

Page 4: Uma função de destruição pode ser uma função  virtual .

constr_Bconstr_Ddestr_Ddestr_B

a = new int[2];memória

b = new int[4];

delete[] a;

Os construtores são chamados pelaseguinte ordem:

os primeiros construtores a seremchamados são os da classe base e só depoisos construtores da classe derivada.

Os destrutores são chamadosexactamente pela ordem inversa.

delete[] b;

Page 5: Uma função de destruição pode ser uma função  virtual .

Como se pode ver, a destruição foi feita adequadamente. Isto aconteceporque o objecto tem o que se chama tabela de funções virtuais.

Esta tabela é criada para todos os objectos definidos dentro de umaclasse base, e contêm ponteiros para as funções que usam o objecto.

Se o objecto pertencer a uma classe derivada, este contêm umatabela adicional para as funções usadas na classe derivada. O que é

preciso reter é que o mecanismo que chama automaticamente odestrutor baseia-se em endereços fornecidos por aquela tabela e

quando o destrutor é virtual, esse mecanismo automático procuraa tabela de funções virtuais que está no fim (ou seja, a tabela

correspondente à classe derivada), executa esse destrutor passandode seguida para o destrutor indicado na tabela de funções virtuais

que está directamente acima.

Geralmente, é bom princípio fornecer um destrutor virtual em todasas classes que funcionam como classes base dado que os objectos

da classe derivada são tipicamente manipulados (e possivelmenteapagados) através de um ponteiro para a base.

Page 6: Uma função de destruição pode ser uma função  virtual .

Um construtor não pode ser virtual porque necessita informaçãoacerca do tipo exacto do objecto a ser criado para o poder

construir correctamente. Para além disso, um construtor não é umafunção normal. Esta pode interagir com as rotinas de gestão de

memória de uma forma que funções membro normais não podem, eé diferente das funções membro normais já que não pode serinvocada para um objecto já existente. Por consequência não

podemos ter um ponteiro para um construtor.

Podemos definir uma função que chama um construtor e retorna oobjecto construído. Isto é útil porque pode haver necessidade decriar um objecto sem sabermos o tipo exacto deste.

Vamos considerar um exemplo onde objectos de uma classe podemfornecer ao utilizador uma cópia de si próprios ou um objecto do

seu tipo.

Page 7: Uma função de destruição pode ser uma função  virtual .

class expressao { public: virtual expressao* expressao_nova() { return new expressao(); } expressao(const expressao&); expressao(); };

class condicao : public expressao { public:

expressao* expressao_nova() { return new condicao(); }condicao(const condicao&);condicao(); };

void utilizador(expressao* p){ expressao* p2 = p->expressao_nova(); }

Isto significa que dado um objecto da classe expressao, umutilizador pode criar um novo objecto “que é realmente do

mesmo tipo”.

Page 8: Uma função de destruição pode ser uma função  virtual .

Sumário de construtores

1. Construtores são as rotinas utilizadas em C++ para construirobjectos.2. Todas as classes têm um construtor.3. Se numa classe não estiver declarado um construtor o compiladorencarrega-se de implementar um.4. Os construtores implementados pelo compilador são públicos.5. O construtor é uma função com o mesmo nome da classe a quepertence.6. O construtor pode receber parâmetros.7. Um construtor da classe X não pode ter parâmetros da classe X,mas pode ter como parâmetro uma referência à classe X (X&).8. Um construtor declarado como X::X(const X&) é o construtor decópia.9. O construtor pode ter valores para serem usados por defeito.10. O construtor não pode devolver qualquer valor, nem mesmovoid.

Page 9: Uma função de destruição pode ser uma função  virtual .

11.Para que se possa definir um array de objectos de uma classe comobjectos membros declarados constantes, essa classe tem que ter,no construtor, parâmetros indicados para serem usados por defeito.12. Não é possível obter um ponteiro para o construtor.13. Um construtor por defeito é um construtor que pode ser chamadosem argumentos.14. O construtor de uma classe é chamado automaticamente quandoum objecto dessa classe é declarado.15. É possível fazer a sobrecarga (overloading) do nome doconstrutor.16. O construtor não pode ser herdado por classes derivadas; noentanto as classes derivadas podem chamar o construtor da classebase.17. O construtor não pode ser declarado como virtual.18. Se o construtor, por alguma razão, não termina o seu serviço, oobjecto não é automaticamente destruído.19. Um objecto com construtor não pode ser membro de uma união.

Page 10: Uma função de destruição pode ser uma função  virtual .

Sumário de destrutores

1. Destrutores são as rotinas utilizadas em C++ para destruirobjectos.2. Todas as classes tem um destrutor.3. Se numa classe não estiver declarado um destrutor o compiladorencarrega-se de implementar um.4. Os destrutores implementados pelo compilador são públicos.5. O destrutor é uma função com o mesmo nome da classe a quepertence, precedido por “~”.6. O destrutor não pode receber parâmetros (nem mesmo void).7. O destrutor não pode devolver qualquer valor (nem mesmo void).8. Não é possível obter um ponteiro para um destrutor.9. O destrutor de uma classe é chamado automaticamente quando oprograma sai de um bloco (scope) onde um objecto dessa classe foideclarado.10. O destrutor pode ser chamado.11. O destrutor pode ser declarado como virtual.

Page 11: Uma função de destruição pode ser uma função  virtual .

12. O destrutor não pode ser herdado por classes derivadas, noentanto as classes derivadas podem chamar os destrutores dasclasses base.13. Um objecto com um destrutor declarado não pode pertencera uma união.14. Para destruir um objecto que esteja na zona de memóriafree store deve usar-se o operador delete.

Page 12: Uma função de destruição pode ser uma função  virtual .

O que é importante:

1. Perceber o que são tipos da memória.

2. Perceber o que são construtores de cópia (copy construtors).

3. Perceber construção e destruição em classes derivadas.

4. Perceber o que é destrutor virtual.

5. Perceber as respectivas regras da linguagem C++.

6. Estar apto a construir programas que utilizem as respectivas construções de POO.

Page 13: Uma função de destruição pode ser uma função  virtual .

class my_class { char* s;

int b;int a;

public:void display() {cout << a << '\t' << b << '\t' << s << endl;}my_class(int A, int B, char *S) : a(A), b(B), s(S) {}virtual ~my_class(); };

void fun(my_class M){ M.display(); }

int main(int argc, char* argv[]){ my_class mc=my_class(19,95,"How are you?");

my_class MC(50,2000,"Aveiro");mc.display(); MC.display();fun( my_class(1,2,"Regards") );funR( my_class(3,4,"Hello") );return 0; }

void funR(my_class& M){ M.display(); }

19 95 How are you50 2000 Aveiro1 2 Regards3 4 Hello

Agora vamos considerar alguns exemplos quevão demonstrar algumas construções

diferentes da linguagem C++

Page 14: Uma função de destruição pode ser uma função  virtual .

class my_class { char* s;

int b;int a;

public:void display() {cout << a << '\t' << b << '\t' << s << endl;}void display_hello() {cout << "hello\n"; }my_class(int A, int B, char *S) : a(A), b(B), s(S) {}virtual ~my_class(); };

void f(my_class& M, void (my_class::*p)()=my_class::display){ M.display();

(M.*p)(); };

int main(int argc, char* argv[]){ //......................

f(mc);f(MC,my_class::display_hello);return 0; }

19 25 How are you19 25 How are you50 2000 Aveirohello

Page 15: Uma função de destruição pode ser uma função  virtual .

class B { //................public:

virtual ~B(){ cout << "destr_B\n"; }protected:

B(int);};

int main(int argc, char* argv[]){B my_b(3); // cannot access protected member declared in class 'B'// .................

Page 16: Uma função de destruição pode ser uma função  virtual .

class D : public B { //.....public: D(int); ~D(){ cout << "destr_D\n"; }};

B::B(int for_b){ cout << "class B: " << for_b << endl; }

D::D(int for_d) : B(for_d){ cout << "class D: " << for_d << endl; }

int main(int argc, char* argv[]){

D my_D(3);return 0;

}

class B: 3class D: 3Destr_DDestr_B

Os resultados:

Page 17: Uma função de destruição pode ser uma função  virtual .

DD

int main(int argc, char* argv[]){

DD my_DD(3);return 0;

}

class DD : public D {public:

DD(int);~DD();

};

DD::DD(int for_dd) : D(for_dd){ cout << "class DD: " << for_dd << endl; }

DD::~DD(){ cout << "destr_DD\n"; } class B: 3

class D: 3class DD: 3Destr_DDDestr_DDestr_B

Os resultados:

D

B

Con

stru

tore

s

Des

tru

tore

s