2016-05-14 19 views
7

Il seguente codice funziona solo se si rimuove il commento dalla linea diinterfacce gerarchiche e implementazioni

virtual void FuncA() { ImplA::FuncA(); } 

in classe ImplB, altrimenti ottengo errore del compilatore:

cannot instantiate abstract class ... FuncA(void)' : is abstract

domanda è: perché non è vero ottiene il implementare per FuncA() dal ereditato ImplA?

class InterfaceA { 
public: 
    virtual void FuncA()=0; 
}; 

class InterfaceB : public InterfaceA { 
public: 
    virtual void FuncB()=0; 
}; 

class ImplA : public InterfaceA { 
public: 
    virtual void FuncA() { printf("FuncA()\n"); } 
}; 

class ImplB : public ImplA, public InterfaceB { 
public: 
    // virtual void FuncA() { ImplA::FuncA(); } 
    virtual void FuncB() { printf("FuncB()\n"); } 
}; 

{ 
    ImplB *b = new ImplB(); 
    InterfaceA *A= b; 
    A->FuncA(); 
    InterfaceB *B= b; 
    B->FuncB(); 
    B->FuncA(); 
} 
+0

Poiché si eredita da 'InterfaceB', che è astratto con due funzioni puramente virtuali che è necessario eseguire l'override. –

+0

class ImplA: public InterfaceA { public: virtual void FuncA() {printf ("FuncA() \ n"); } }; – perry

+0

nota che la classe ImplA viene corretta come sotto il risultato è la stessa – perry

risposta

3

hai colpito un'istanza del problema "diamante" di ereditarietà multipla. È necessario utilizzare l'ereditarietà "virtuale" (che equivale ad aggiungere la parola chiave virtuale quando si eredita)

Il problema è che ImplB ha due percorsi per la classe base InterfaceA. Tuttavia, l'intenzione è che le interfacce non forniscano alcuna implementazione. Pertanto, è necessario indicarlo al compilatore, in modo che possa unificare le pure funzioni virtuali.

Per una spiegazione molto migliore: http://www.cprogramming.com/tutorial/virtual_inheritance.html

ho modificato il codice per aggiungere virtuale quando si eredita dalle interfacce. Ora compila, anche con la linea commentata. Inoltre, penso che ti mancano i distruttori virtuali, quindi avrai altri problemi in futuro. Questo codice viene compilato, senza decommentare FuncA.

#include <cstdio> 

class InterfaceA { 
public: 
    virtual void FuncA()=0; 
}; 

class InterfaceB : public virtual InterfaceA { 
public: 
    virtual void FuncB()=0; 
}; 

class ImplA : public virtual InterfaceA { 
public: 
    virtual void FuncA() { printf("FuncA()\n"); } 
}; 

class ImplB : public ImplA, public virtual InterfaceB { 
public: 
    // virtual void FuncA() { ImplA::FuncA(); } 
    virtual void FuncB() { printf("FuncB()\n"); } 
}; 

int main() 
{ 
    ImplB *b = new ImplB(); 
    InterfaceA *A= b; 
    A->FuncA(); 
    InterfaceB *B= b; 
    B->FuncB(); 
    B->FuncA(); 
} 
+1

Molte molte grazie! Questo mi ha infastidito da un po 'di tempo, sei totalmente inchiodato. Sono in debito con te. – perry

0

ereditarietà multipla non è "mixin"

È possibile ereditare da più classi che hanno metodi con lo stesso nome, ma che non li rende la stessa.

La cosa che eredita da una classe virtuale deve implementare le pure funzioni virtuali dei suoi genitori.

Se i nomi dei metodi non erano ambiti, si potrebbe finire con combinazioni di classi padre che erano mutuamente esclusive da ereditare perché le implementazioni del metodo con il nome condiviso non sarebbero compatibili.

Sono un po 'sorpreso che mettere in using ImplA::FuncA; ImplB non lo risolve, però: https://gcc.godbolt.org/