quarta-feira, 9 de agosto de 2006

Dica C++: Destrutor virtual abstrato

Em uma classe base, métodos virtuais são aqueles que podem ter sua implementação sobrescrita por uma classe filha.
Isto é uma verdade para métodos, mas não para destrutores. A implementação de um destrutor virtual em uma classe filha não sobrescreve a implementação da classe base. Ela estende.
Primeiro é executado o código do destrutor da classe filha, depois o código do destrutor da classe base.

Exemplo:


class Base
{
public:
virtual ~Base()
{
cout<< "\nDestrutor da classe base." << endl;
};

virtual void Metodo()
{
cout << "\nMétodo da classe base." << endl;
};
};

class Derivada : public Base
{
public:
virtual ~Derivada()
{
cout<< "\nDestrutor da classe derivada." << endl;
};

virtual void Metodo()
{
cout << "\nMétodo da classe derivada." << endl;
};
};

// ...

int main()
{
Base *obj = new Derivada;

obj->Metodo();

delete obj;
}


No exemplo acima, se um destrutor virtual não fosse declarado, o destrutor da classe filha não seria executado.

O destrutor virtual da classe filha extender o código do destrutor da classe base,claro, tem sua razão de ser. Se não fosse esse mecanismo, por exemplo, para uma classe base que tem objetos que são desalocados no momento de sua destruição, a classe filha teria que fazer todo o trabalho novamente...

E quando desejarmos criar uma classe puramente abstrata, ou seja, uma interface ?
O destrutor dela provavelmente teria de ser virtual, mas sendo abstrata não poderia ter código. Bom, e como não vai ter código se há a necessidade de executar o código de destruição, pelo destrutor ser virtual ???

Simples, declare um destrutor virtual abstrato com implementação.
Mas se é abstrato como terá implementação ?¿?
Bom, infelizmente C++ não foi bem planejado nesta parte... :(

No arquivo .h, declare normalmente:


class BasePura
{
public:
virtual ~BasePura() = 0; // destrutor virtual abstrato

virtual void Metodo() = 0;
};


No arquivo .cpp (implementação), implemente o destrutor:


BasePura::~BasePura()
{
// implementacao normalmente vazia
}


Esta é uma das partes mal planejadas do C++, que devem ser corrigidas futuramente
pelos novos padrões da linguagem, definidas pelo ISO C++ Standards Commitee.