Ereditarietà e Metodi Virtuali
Per costruire un’Interfaccia, purtroppo il C++ non ha una parola chiave esplicita interface come Java o C#. Dobbiamo servirci degli antichi meccanismi dell’Ereditarietà (Inheritance).
Ereditarietà di Base (Base Class Inheritance)
Section titled “Ereditarietà di Base (Base Class Inheritance)”Possiamo far ereditare una classe (Subclass o classe derivata) da un’altra (Superclass o classe base). La sintassi usa i due punti (:).
struct BaseClass { int the_answer() const { return 42; }};
// DerivedClass eredita da BaseClassstruct DerivedClass : BaseClass { // Possiede automaticamente il metodo the_answer()};Un grande vantaggio dell’ereditarietà è che puoi trattare un’istanza della classe derivata come se fosse un’istanza della classe base, passandone ad esempio la referenza a una funzione:
void funzione(BaseClass& base) { }
DerivedClass derived;funzione(derived); // OK! Una DerivedClass *è* una BaseClass.(L’ereditarietà porta con sé anche l’ereditarietà dei campi dati, un concetto noto come “Implementation Inheritance”. Oggigiorno nella programmazione moderna questo approccio si tende a scoraggiare perché porta a gerarchie fragili. È preferibile usare l’Ereditarietà solo per le interfacce, come vedremo.)
I Metodi virtual e la keyword override
Section titled “I Metodi virtual e la keyword override”Se una classe derivata eredita un metodo dalla base, può decidere di sovrascriverne il comportamento (Overriding). Per permettere questo aggancio polimorfico a runtime, il metodo nella classe base DEVE essere marcato con la parola chiave virtual.
Nella classe derivata, pur non essendo obbligatorio per la compilazione, è importantissimo indicare che stiamo rimpiazzando un metodo tramite la parola chiave override posta in coda alla firma del metodo. Questo fa in modo che il compilatore controlli se stiamo effettivamente sovrascrivendo un metodo virtuale valido.
Se togliessi virtual dalla classe base, il puntatore/referenza risolverebbe la funzione basandosi strettamente sul tipo “statico” del puntatore stesso in compilazione (stamperà BASE).
Mantenendo virtual, il programma aspetta di esaminare la tabella dei metodi a runtime (vtable) ed esegue l’implementazione reale dell’oggetto sottostante (stamperà DERIVATA).