domingo, 1 de junho de 2014

Herança Virtual em C++

Antes de falar sobre a herança virtual em C++, é preciso esclarecer o motivo de seu uso, que está intimamente ligado com uma das complicações da herança múltipla.

Algumas linguagens orientada a objeto resolveram não implementar a herança múltipla, substituindo esse recurso pelo uso de interfaces. Por exemplo em Java, uma classe não pode herdar duas classes ou mais, porém pode implementar quantas interfaces desejar. Em C++ como foi feito a implementação da herança múltipla, não existe a necessidade das interfaces, já que uma classe pode herdas diversas outras classes.

Em Java, se duas interfaces diferentes tiverem métodos com a mesma assinatura e uma classe qualquer implementar as duas interfaces, não existirá problema algum, afinal a implementação dos métodos é responsabilidade da classe que está “herdando” estas interfaces.

Em C++ é possível que uma classe herde de outras duas, que possuam métodos ou até mesmo atributos com os mesmos nomes, isso se torna algo conflitante, ainda por cima é possível que as duas classes herdadas já façam herança de outras classes, podendo ter até uma classe em comum.

Imagine a seguinte situação, classe A sem nenhuma herança, classes B e C herdando de A e uma classe D herdando de B e C. Neste caso há alguns questionamentos, uma instância de D equivale a quantas instâncias de A? Afinal ela herda A por B e por C. Acredito que exista casos em que a intenção seja duas instâncias, já alguns outros que seja apenas uma.

Para isso o C++ utiliza a herança virtual, com ela pode ser especificado como resolver esse tipo de herança. No exemplo abaixo foi feita a herança de forma normal, sem a utilização da herança virtual.

#include <iostream>

using namespace std;

class A {
private:
    static int contador;
public:
    A(){
        A::contador++;
        cout << "Construtor do A  ("<< A::contador <<")"<< endl;
    }
    virtual ~A(){
        cout << "Destrutor do A (" << A::contador << ")" << endl;
        A::contador--;
    }
};

int A::contador = 0;

class B : public A {
public:
    B(){
        cout << "Construtor do B" << endl;
    }
    virtual ~B(){
        cout << "Destrutor do B " << endl;
    }
};

class C : public A {
public:
    C(){
        cout << "Construtor do C" << endl;
    }
    virtual ~C(){
        cout << "Destrutor do C " << endl;
    }
};


class D : public B,C {
public:
    D(){
        cout << "Construtor do D" << endl;
    }
    virtual ~D(){
        cout << "Destrutor do D" << endl;
    }
};


int main(int argc, char ** argv){
    D d;
}

Se observada a saída deste programa, pode ser percebido que uma instância da classe D é na verdade duas instâncias da classe A, como se D fosse composto por uma instância da classe B e uma instância da classe C.
No próximo exemplo a herança de B e C para A foi feita de forma virtual, tornando a saída do programa um pouco diferente.
#include <iostream>

using namespace std;

class A {
private:
    static int contador;
public:
    A(){
        A::contador++;
        cout << "Construtor do A  ("<< A::contador <<")"<< endl;
    }
    virtual ~A(){
        cout << "Destrutor do A (" << A::contador << ")" << endl;
        A::contador--;
    }
};

int A::contador = 0;

class B : virtual public A {
public:
    B(){
        cout << "Construtor do B" << endl;
    }
    virtual ~B(){
        cout << "Destrutor do B " << endl;
    }
};

class C : virtual public A {
public:
    C(){
        cout << "Construtor do C" << endl;
    }
    virtual ~C(){
        cout << "Destrutor do C " << endl;
    }
};


class D : public B,C {
public:
    D(){
        cout << "Construtor do D" << endl;
    }
    virtual ~D(){
        cout << "Destrutor do D" << endl;
    }
};


int main(int argc, char ** argv){
    D d;
}

Neste caso uma instância de D representa apenas uma instância de A, como se a instância de B e de C que compõem a instância de D, fossem compostas pela mesma instância de A.

Obrigado!

3 comentários :