Vad är en virtuell funktion?

En virtuell funktion är en funktion, definierad i en superklass, som måste finnas i en underklass för att den underklassen ska ha en fullständig klassdefinition. Virtuella funktioner förlitar sig på ett objektorienterat programmeringsparadigm som kallas virtuellt arv, vilket oftast ses i C++ med nyckelordet ”virtuella”. För att definiera en virtuell funktion krävs två klasser, en superklass och en underklass. Superklassen är där funktionen först deklareras och eventuellt definieras. Underklassen är där funktionen definieras – eller åsidosätts, beroende på om funktionen definierades i superklassen.

Den virtuella funktionen kan definieras på ett av två sätt. För det första kan den definieras som en stubbe, där den har en tom kropp och inte gör någonting. För det andra kan den definieras som en ren virtuell funktion, där den definieras som NULL i superklassens header-fil.

Det finns fördelar och nackdelar med båda metoderna. Att definiera en funktion som en stubb säkerställer att alla underklasser har någon implementering av den, även om den inte gör någonting. Om man glömmer att åsidosätta funktionen och implementera den korrekt i en underklass, kommer dock inga fel eller varningar att påpeka detta. Att definiera en ren virtuell funktion kräver å andra sidan att varje underklass har sin egen definition av funktionen, och fel kommer att dyka upp om så inte är fallet.

Virtuella funktioner är dock föremål för samma arvsregler som icke-virtuella funktioner, så arvshierarkier med fler än två nivåer kanske inte kräver explicita definitioner av virtuella funktioner. Till exempel kan man överväga en klass A som deklarerar en virtuell funktion, som är implementerad i underklass B. Klass B har en egen underklass, klass C. Klass C kräver ingen explicit definition av klass A:s funktion, eftersom den ärver definitionen från klass B. Vid behov kan klass C åsidosätta klass B:s funktion, eller så kan den åsidosätta klass B:s funktion samtidigt som den anropas.

I den andra ytterligheten behöver virtuella funktioner inte definieras i en underklass om de deklareras virtuella i den underklassen. Till exempel kan man betrakta en klass A som deklarerar en virtuell funktion och har två underklasser, B och C. Dessutom skulle man kunna tänka sig att klass B har underklasserna D och E, och underklass C har underklasserna F och G.

Klasserna B till G måste alla ha klass A:s virtuella funktion definierad på något sätt. Om klass B har en implementering av A:s funktion behöver klasserna D och E inte göras om. Kanske C:s underklasser behöver implementera A:s funktion, men de gör båda något annorlunda, så att definiera funktionen i själva klass C skulle inte vara användbart. I så fall kan funktionen deklareras virtuell i klass C, och en implementering är inte nödvändig.
Virtuella funktioner kan vara skrämmande att lära sig, men när de används på rätt sätt kan de minska kodduplicering och göra koden mycket lättare att förstå i allmänhet. Det finns dock många fallgropar med virtuella funktioner, särskilt när det gäller multipelt arv. Vid multipelarv är det möjligt för tvetydigt definierade virtuella funktioner att komma i konflikt med varandra, så de bör användas med försiktighet i det sammanhanget.