Ce este o funcție virtuală?

O funcție virtuală este o funcție, definită într-o superclasă, care trebuie să fie prezentă într-o subclasă pentru ca acea subclasă să aibă o definiție completă a clasei. Funcțiile virtuale se bazează pe o paradigmă de programare orientată pe obiecte numită moștenire virtuală, care este cel mai frecvent întâlnită în C++ folosind cuvântul cheie „virtual”. Pentru a defini o funcție virtuală, sunt necesare două clase, o superclasă și o subclasă. Superclasa este locul unde funcția este mai întâi declarată și, eventual, definită. Subclasa este locul în care funcția este definită – sau suprascrisă, în funcție de dacă funcția a fost definită în superclasă.

Funcția virtuală poate fi definită în unul din două moduri. În primul rând, poate fi definit ca un ciot, în care are un corp gol și nu face nimic. În al doilea rând, ar putea fi definită ca o funcție virtuală pură, unde este definită ca NULL în fișierul antet al superclasei.

Ambele metodologii au avantaje și dezavantaje. Definirea unei funcții ca un stub asigură că toate subclasele au o anumită implementare a acesteia, chiar dacă nu face nimic. Dacă cineva uită să suprascrie funcția și să o implementeze corect într-o subclasă, totuși, nu vor apărea erori sau avertismente care să indice acest lucru. Definirea unei funcții virtuale pur, pe de altă parte, necesită ca fiecare subclasă să aibă propria definiție a funcției, iar erorile vor apărea dacă nu este cazul.

Cu toate acestea, funcțiile virtuale sunt supuse acelorași reguli de moștenire ca și funcțiile non-virtuale, astfel încât ierarhiile de moștenire cu mai mult de două niveluri ar putea să nu necesite definiții explicite ale funcțiilor virtuale. De exemplu, se poate considera o clasă A care declară o funcție virtuală, care este implementată în subclasa B. Clasa B are o subclasă proprie, clasa C. Clasa C nu necesită o definiție explicită a funcției clasei A, deoarece moștenește definiția din clasa B. Dacă este necesar, clasa C ar putea suprascrie funcția clasei B sau ar putea suprascrie funcția clasei B în timp ce o apelează.

La cealaltă extremă, funcțiile virtuale nu trebuie să fie definite într-o subclasă dacă sunt declarate virtuale în acea subclasă. De exemplu, se poate considera o clasă A care declară o funcție virtuală și are două subclase, B și C. În plus, s-ar putea imagina că clasa B are subclasele D și E, iar subclasa C are subclasele F și G.

Toate clasele de la B la G trebuie să aibă funcția virtuală a clasei A definită cumva. Dacă clasa B are o implementare a funcției lui A, clasele D și E nu au nevoie să fie refăcută. Poate că subclasele lui C trebuie să implementeze funcția lui A, dar ambele fac ceva diferit, așa că definirea funcției în clasa C în sine nu ar fi utilă. În acest caz, funcția poate fi declarată virtuală în clasa C, iar o implementare nu este necesară.
Funcțiile virtuale pot fi descurajatoare de învățat, dar atunci când sunt utilizate corespunzător, pot reduce duplicarea codului și pot face codul mult mai ușor de înțeles în general. Cu toate acestea, există multe capcane cu funcțiile virtuale, în special în ceea ce privește moștenirea multiplă. În moștenirea multiplă, este posibil ca funcțiile virtuale definite ambiguu să intre în conflict între ele, așa că ar trebui utilizate cu prudență în acest context.