Virtuellt arv är en typ av arv där implementeringen av en superklass är ofullständig och en underklass krävs för fullständig definition av ett objekt. Denna typ av arv kan användas i samband med både enkel- och multipelarv, men används oftast vid multipelarv. Varje klass som ärver från en virtuell basklass blir en direkt underklass till den basklassen. En virtuell basklass kan förlita sig på en underklass för att implementera alla dess metoder, men detta är inte ett krav.
C++ är det vanligaste datorspråket för att använda virtuellt arv. För att deklarera virtuellt arv i C++ används nyckelordet ”virtuellt”. Både superklassen och underklassen måste deklarera virtuella metoder med nyckelordet ”virtuell”. Detta talar om för C++-kompilatorn att superklassen är ofullständig, och den måste få information från underklassen för att den ska kunna slutföras. Att använda underklassen för att slutföra superklassen betyder inte att underklasser skriver över varandra om de har samma basklass, och istället tar C++-kompilatorn hand om att bestämma vilka bitar som går med varje objekt.
Eftersom en virtuell basklass krävs för virtuellt arv, kan inte globala funktioner i C++ deklareras som virtuella. Denna arvstyp kan endast användas när man följer principerna för objektorienterad programmering (OOP). Anledningen till detta är att globala funktioner inte är associerade med en viss klass, och därför är vanligtvis fristående på egen hand. Utan en superklass och underklass kan arv inte ske, så globala funktioner och virtuellt arv utesluter varandra. Globala funktioner kan i teorin användas i virtuella funktioner, men det omvända kanske inte alltid fungerar.
Virtuellt arv används för att lösa många programmeringsproblem, och ett av de mest användbara är att lösa tvetydigheter. Vid multipelarv kan man ha en basklass A som har två underklasser, B och C, och sedan en klass D som ärver från både klass B och C. Detta mönster kallas vanligtvis ”dödens diamant” eftersom om klasserna A, B och C har alla implementeringar av samma metod, det är inte möjligt för klass D att bestämma vilken implementering den ska använda. Virtuellt arv löser detta problem eftersom varje klasss implementering förblir distinkt och därför entydig. Denna distinktion hanteras av specialiserade interna objekt som kallas virtuella tabeller (vtables) som håller reda på varje objekttyp, men dessa tabeller behöver inte explicit manipuleras av en programmerare eftersom de är inbyggda i språket.