C++ Eredità virtuale


Esempio

Quando si utilizza l'ereditarietà, è possibile specificare la parola chiave virtual :

struct A{};
struct B: public virtual A{};

Quando la classe B ha una base virtuale A , significa che A risiederà nella maggior parte della classe derivata dell'albero di ereditarietà, e quindi che la maggior parte della classe derivata è anche responsabile dell'inizializzazione di quella base virtuale:

struct A
{
    int member;
    A(int param)
    {
        member = param;
    }
};

struct B: virtual A
{
    B(): A(5){}
};

struct C: B
{
    C(): /*A(88)*/ {}
};

void f()
{
    C object; //error since C is not initializing it's indirect virtual base `A`
}

Se cancelliamo un commento /*A(88)*/ non riceveremo alcun errore dal momento che C sta inizializzando la sua base virtuale indiretta A

Inoltre, quando creiamo object variabili, la maggior parte della classe derivata è C , quindi C è responsabile della creazione (chiamante costruttore di) A e quindi il valore di A::member è 88 , non 5 (come sarebbe se fossimo noi creando oggetto di tipo B ).

È utile quando si risolve il problema dei diamanti .:

  A                                        A   A
 / \                                       |   |
B   C                                      B   C
 \ /                                        \ /
  D                                          D
virtual inheritance                   normal inheritance

B e C ereditano entrambi da A , e D eredita da B e C , quindi ci sono 2 istanze di A in D ! Ciò si traduce in ambiguità quando si accede ai membri di A a D , in quanto il compilatore non ha modo di sapere da quale classe si desidera accedere a quel membro (quello che B eredita, o quello che è ereditato da C ?) .

L'ereditarietà virtuale risolve questo problema: poiché la base virtuale risiede solo nella maggior parte degli oggetti derivati, ci sarà solo un'istanza di A in D

struct A
{
    void foo() {}
};

struct B : public /*virtual*/ A {};
struct C : public /*virtual*/ A {};

struct D : public B, public C
{
    void bar()
    {
        foo(); //Error, which foo? B::foo() or C::foo()? - Ambiguous
    }
};

La rimozione dei commenti risolve l'ambiguità.