Come pratica si dovrebbe usare l'ereditarietà virtuale per definire le interfacce in quanto sono di solito utilizzati con l'ereditarietà multipla per garantire che solo una versione della classe è presente nella classe derivata. E le interfacce pure sono la forma più sicura di ereditarietà multipla. Naturalmente se sai cosa stai facendo puoi usare l'eredità multipla come preferisci, ma può risultare in un codice fragile se non stai attento.
Il più grande svantaggio con l'ereditarietà virtuale è se i loro costruttori accettano parametri. Se devi passare parametri al costruttore di una classe base virtuale, imponi a tutte le classi derivate di chiamare esplicitamente il costruttore (non possono fare affidamento su una classe base che chiama il costruttore).
L'unico motivo che posso vedere per il vostro avviso esplicito è che i dati nella vostra classe base virtuale potrebbero richiedere parametri di costruzione.
Modifica Ho fatto un po 'di lavoro a casa dopo il commento di Martin, grazie a Marin. La prima linea non è del tutto vero:
Come pratica si dovrebbe usare eredità virtuale per definire interfacce in quanto sono di solito utilizzati con l'ereditarietà multipla per garantire che solo una versione della classe è presente nella classe derivata.
L'ereditarietà virtuale non fa alcuna differenza se la classe base è un'interfaccia pura (eccetto per errori del compilatore leggermente diversi, in vc8, se tutti i metodi non sono implementati). Si fa solo una reale differenza, se la classe base contiene dati, in questo caso si finisce con un diamante piuttosto che una figura di U
Non virtual virtual
A A A
| | / \
B C B C
\ / \ /
D D
Nel caso virtuale, B e C condividono la stessa copia della A.
Tuttavia sono ancora d'accordo con tutto il resto sulle interfacce pure che sono la forma più sicura di ereditarietà multipla, anche se non richiedono l'ereditarietà virtuale. E il fatto che i parametri del costruttore e l'ereditarietà virtuale siano un dolore.
Potresti fornire un link o una citazione per il consiglio? vedere molto punto nel contrassegnare una classe base virtuale se non ha membri dati, poiché lo scopo più comune dell'ereditarietà virtuale è impedire la duplicazione dei membri della classe base. Per esempio nelle librerie standard, ios_base ha membri dati, ed è unclasse base virtuale (via ios) di entrambi i istream e ostream. Quindi direi quasi (ma non proprio) il contrario: se hai intenzione di avere una classe base virtuale, allora dovrebbe avere membri dei dati, o ereditare non virtualmente. –