L'herència virtual és una tècnica C++ que garanteix que només una còpia de les variables membres ' una classe base sigui heretada per les classes derivades dels néts. Sense herència virtual, si dues classes B i C hereten d'una classe A i una classe D hereta tant de B com de C, aleshores D contindrà dues còpies de les variables membres ' A : una a través de B i una altra a través C Aquests seran accessibles de manera independent, utilitzant la resolució d'abast.[1]
En canvi, si les classes B i C hereten virtualment de la classe A, aleshores els objectes de la classe D només contindran un conjunt de variables membres de la classe A.[2]
Aquesta característica és molt útil per a l'herència múltiple, ja que fa que la base virtual sigui un subobjecte comú per a la classe derivada i totes les classes que se'n deriven. Això es pot utilitzar per evitar el problema del diamant aclarint l'ambigüitat sobre quina classe ancestra s'ha d'utilitzar, ja que des de la perspectiva de la classe derivada (D a l'exemple anterior) la base virtual (A ) actua com si fos la classe base directa de D, no una classe derivada indirectament a través d'una base (B o C ).[3][4]
S'utilitza quan l'herència representa la restricció d'un conjunt en lloc de la composició de parts. En C++, una classe base destinada a ser comuna a tota la jerarquia es denota com a virtual amb la paraula clauvirtual.
Considereu la següent jerarquia de classes.
structAnimal{virtual~Animal()=default;// Explicitly show that the default class destructor will be made.virtualvoidEat(){}};structMammal:Animal{virtualvoidBreathe(){}};structWingedAnimal:Animal{virtualvoidFlap(){}};// A bat is a winged mammalstructBat:Mammal,WingedAnimal{};
Com s'ha dit més amunt, una crida al bat.Eat és ambigu perquè hi ha dues classes base Animal (indirectes) a Bat, de manera que qualsevol objecte Bat té dos subobjectes diferents de classe base Animal. Per tant, un intent d'enllaçar directament una referència al subobjecte Animal d'un objecte Bat fallaria, ja que la vinculació és inherentment ambigua:
Batbat;Animal&animal=bat;// error: which Animal subobject should a Bat cast into, // a Mammal::Animal or a WingedAnimal::Animal?
Per desambiguar, caldria convertir explícitament bat a qualsevol subobjecte de classe base:
Per trucar a Eat, cal la mateixa desambiguació o qualificació explícita: static_cast<Mammal&>(bat).Eat() o static_cast<WingedAnimal&>(bat).Eat() o alternativament bat.Mammal::Eat() i bat.WingedAnimal::Eat(). La qualificació explícita no només utilitza una sintaxi més fàcil i uniforme tant per als punters com per als objectes, sinó que també permet l'enviament estàtic, de manera que podria ser el mètode preferible.