= 0
alla dichiarazione di essa, naturalmente senza fornire il corpo della funzione12.1. Non appena una classe contiene almeno una funzione virtuale pura, essa è astratta:
// ex12_5_5.cpp #include <iostream.h> // classe astratta class Corda { public: virtual void suona() = 0; // funzione virtuale pura void f() { cout << "Corda::f()\n"; } virtual void g() { cout << "Corda::g()\n"; } }; class Chitarra : public Corda { public: void suona() { cout << "Chitarra::suona()\n"; f(); g(); } }; class Acustica : public Chitarra { public: void suona() { cout << "Acustica::suona()\n"; f(); g(); } void f() { cout << "Acustica::f()\n"; } void g() { cout << "Acustica::g()\n"; } }; void main() { // Corda* c = new Corda; // NO Corda* c1 = new Chitarra; Corda* c2 = new Acustica; c1->suona(); c2->suona(); }
output:
Chitarra::suona() Corda::f() Corda::g() Acustica::suona() Acustica::f() Acustica::g()
La classe Corda
è astratta, per cui il compilatore ci impedisce di istanziare un oggetto di tale tipo, mentre è lecito effettuare degli upcast a essa. Vediamo le funzioni membro delle nostre classi:
suona()
: è una funzione virtuale pura, che forza il programmatore dunque a derivare una classe dalla Corda
e a sovrapporre tale funzione, la cui definizione in realtà non esiste nella classe base astratta; chiaramente essa è virtuale: non esistono in C++ funzioni pure non virtuali;f()
: funzione non virtuale: sia che essa non venga sovrapposta (come in Chitarra
) sia che lo sia (come in Acustica
) sarà sempre la versione della classe base ad essere chiamata;g()
: funzione virtuale non pura: siccome non è possibile istanziare oggetti di tipo Corda
, la definizione è inutile se avviene l'overriding nella classe immediatamente sottostante; datosi che nel nostro esempio non si verifica questa condizione, la chiamata avviene sulla Chitarra
; naturalmente la Acustica
possiede una propria funzione g()
, alla quale si risale a tempo di esecuzione grazie al runtime binding.