tuttavia questo è solo overload delle funzioni membro. La clausola "virtual" che vedi nella classe base però permette anche di fare una cosa così(chiamata appunto polimorfismo)
OUTPUT: sono un cane
questo perché, nonostante io stia chiamando il metodo partendo dalla classe base, la key virtual mi salva in memoria un puntatore ad una tabella virtuale che mi tiene conto di che tipo è in realà quel puntatore.
Quindi verrà chiamato il metodo corretto.
Prova a ragionarci su e pensa a come fare il tuo esercizio