Vai al contenuto

Parco Auto 3: ereditarietร  e polimorfismo

Auto elettriche e sportive senza riscrivere codice: classi figlie, virtual e override, e una sola List per tutti i tipi di auto.

Ultima tappa del Parco Auto. Riparti dal progetto delle lezioni Parco Auto 1 e Parco Auto 2: la classe Automobile c'รจ giร , e ora le diamo dei figli.

Ereditarietร : Le Classi Figlie

Hai creato la classe Automobile. Ma cosa succede se vuoi gestire anche AutoElettrica o AutoSportiva? Hanno molte cose in comune con Automobile, ma anche caratteristiche diverse. Devi riscrivere tutto da capo? No! Esiste l'ereditarietร .

๐Ÿค” Il Problema Senza Ereditarietร 

โŒ SENZA Ereditarietร  - Codice Duplicato

// Devi scrivere due classi SEPARATE con tutto il codice ripetuto
class Automobile
{
    private string _modello;
    private int _cilindrata;
    private string _carburante;
    // ... costruttore, proprietร , metodi ...
}

class AutoElettrica
{
    private string _modello;       // โ† DUPLICATO!
    private int _cilindrata;       // โ† DUPLICATO!
    private string _carburante;    // โ† DUPLICATO!
    private int _autonomiaKm;      // Nuovo campo specifico
    // ... tutto il costruttore duplicato ...
    // ... tutte le proprietร  duplicate ...
}

// ๐Ÿ˜ฑ Problemi:
// 1. Codice identico scritto due volte โ†’ errori facilissimi
// 2. Se devi correggere un bug, devi farlo in ENTRAMBE le classi
// 3. Non รจ scalabile: per 10 tipi di auto, 10 classi duplicate!

โœ… CON Ereditarietร  - Codice Riutilizzato

โœ… CON Ereditarietร  - DRY (Don't Repeat Yourself)

// La classe BASE ha tutto il codice comune
class Automobile
{
    private string _modello;
    private int _cilindrata;
    private string _carburante;
    // ... proprietร  e metodi comuni a TUTTE le auto ...
}

// La classe FIGLIA eredita tutto e aggiunge solo il nuovo
class AutoElettrica : Automobile   // โ† Il ":" significa "estende"
{
    private int _autonomiaKm;      // Solo la parte NUOVA!
    // tutto il resto lo prende GRATIS da Automobile!
}

// โœ… Vantaggi:
// 1. AutoElettrica ha giร  Modello, Cilindrata, Carburante
// 2. Correggi un bug in Automobile โ†’ fix automatico per tutti
// 3. Aggiungi 10 tipi di auto senza duplicare nulla

๐ŸŽฏ Analogia del Mondo Reale

Pensa alla biologia:

  • Animale (classe base) โ†’ respira, si muove, ha un nome
  • Cane (classe figlia) โ†’ eredita tutto da Animale + abbaia, ha una razza
  • Gatto (classe figlia) โ†’ eredita tutto da Animale + fa le fusa, รจ indipendente

Il Cane non deve "reimparare" a respirare: lo eredita dall'Animale!

              Automobile (CLASSE BASE / GENITORE)
              โ”œโ”€โ”€ Modello
              โ”œโ”€โ”€ Cilindrata
              โ”œโ”€โ”€ Carburante
              โ””โ”€โ”€ ToString()
                      โ”‚
          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
          โ†“           โ†“           โ†“
    AutoElettrica  AutoSportiva  AutoLusso
    (FIGLIA)       (FIGLIA)      (FIGLIA)
    + AutonomiaKm  + Cavalli     + Prezzo
    + Batteria     + Turbo       + Brand

Come Si Scrive una Classe Figlia

  1. Modificare la Classe Base: aggiungere protected

Prima di creare classi figlie, devi modificare la classe Automobile. Le classi figlie non possono accedere ai campi private del genitore. Devi usare protected:

Automobile.cs - Campi diventano protected

public class Automobile
{
    // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    // PRIMA usavi "private" โ†’ SOLO questa classe poteva vederli
    // ORA usi "protected" โ†’ anche le classi FIGLIE possono vederli
    // Dall'esterno (Form, altri) rimangono comunque nascosti!
    // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    protected string _modello;        // โ† protected, non private
    protected int _cilindrata;        // โ† protected, non private
    protected string _carburante;     // โ† protected, non private

    // Le PROPRIETร€ e i METODI pubblici rimangono uguali
    public string Modello
    {
        get { return _modello; }
        set { if (!string.IsNullOrEmpty(value)) _modello = value; }
    }
    public int Cilindrata
    {
        get { return _cilindrata; }
        set { if (value >= 500 && value <= 10000) _cilindrata = value; }
    }
    public string Carburante
    {
        get { return _carburante; }
        set { if (!string.IsNullOrEmpty(value)) _carburante = value; }
    }

    // Il costruttore rimane uguale
    public Automobile(string modello, int cilindrata, string carburante)
    {
        Modello = modello;
        Cilindrata = cilindrata;
        Carburante = carburante;
    }

    // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    // IMPORTANTE: aggiungi "virtual" ai metodi che le figlie
    // potranno personalizzare (override)
    // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public virtual string Stampa()
    {
        return $"{Modello} - {Cilindrata}cc - {Carburante}";
    }

    public override string ToString()
    {
        return Stampa();
    }
}

๐Ÿ”‘ I Tre Livelli di Visibilitร 

Parola chiave Chi puรฒ accedere? Quando usarla
private Solo la classe stessa Se non hai classi figlie
protected La classe + le classi figlie Quando usi l'ereditarietร  โœ…
public Tutti (Form, altre classi...) Proprietร  e metodi pubblici
  1. Creare la Classe Figlia: AutoElettrica

Aggiungi un nuovo file AutoElettrica.cs al progetto (come hai fatto per Automobile.cs).

AutoElettrica.cs - Classe Figlia Completa

using System;
using System.Windows.Forms;

namespace ParcoAuto
{
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    //  AutoElettrica ESTENDE Automobile
    //  Il ":" indica "eredita da"
    //  Leggi: "AutoElettrica รจ un tipo di Automobile"
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    public class AutoElettrica : Automobile
    {
        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // CAMPI PRIVATI propri di AutoElettrica
        // (quelli di Automobile li ha giร  ereditati!)
        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        private int _autonomiaKm;
        private int _percentualeBatteria;

        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // PROPRIETร€ proprie di AutoElettrica
        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        public int AutonomiaKm
        {
            get { return _autonomiaKm; }
            set
            {
                if (value >= 50 && value <= 1000) { _autonomiaKm = value; } else { MessageBox.Show("Autonomia deve essere tra 50 e 1000 km!", "ERRORE", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } public int PercentualeBatteria { get { return _percentualeBatteria; } set { if (value >= 0 && value <= 100)
                    _percentualeBatteria = value;
                else
                    MessageBox.Show("Percentuale batteria deve essere tra 0 e 100!",
                                  "ERRORE", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // PROPRIETร€ CALCOLATA: km rimasti con la carica attuale
        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        public double KmRimasti
        {
            get { return _autonomiaKm * (_percentualeBatteria / 100.0); }
        }

        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // COSTRUTTORE della classe figlia
        // Deve chiamare il costruttore del GENITORE con "base(...)"
        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        public AutoElettrica(string modello, int autonomiaKm, int percentualeBatteria)
            : base(modello, 0, "Elettrica")   // โ† chiama Automobile(modello, 0, "Elettrica")
        {
            // Dopo che il costruttore base ha fatto il suo lavoro,
            // impostiamo le proprietร  specifiche di AutoElettrica
            AutonomiaKm = autonomiaKm;
            PercentualeBatteria = percentualeBatteria;
        }

        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // OVERRIDE di Stampa() โ†’ versione personalizzata
        // Sostituisce la versione del genitore
        // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        public override string Stampa()
        {
            return $"{Modello} [โšก Elettrica] - Autonomia: {AutonomiaKm}km - " +
                   $"Batteria: {PercentualeBatteria}% ({KmRimasti:F0}km rimasti)";
        }
        // ToString() NON serve riscriverlo! Chiama giร  Stampa()
        // che ora รจ la versione override di AutoElettrica โœ…
    }
}

๐Ÿ” Analisi del Costruttore Figlia

public AutoElettrica(string modello, int autonomiaKm, int percentualeBatteria)
    : base(modello, 0, "Elettrica")
//  โ†‘
//  "base(...)" = chiama il costruttore di AUTOMOBILE
//  Gli passo:  modello (dall'utente), 0 (cilindrata 0 per elettrica),
//              "Elettrica" (carburante fisso)
//
// ORDINE di esecuzione:
// 1. Prima viene eseguito il costruttore di Automobile (base)
//    โ†’ imposta _modello, _cilindrata, _carburante
// 2. Poi viene eseguito il corpo di AutoElettrica
//    โ†’ imposta _autonomiaKm, _percentualeBatteria
  1. Creare una Seconda Figlia: AutoSportiva

AutoSportiva.cs

namespace ParcoAuto
{
    public class AutoSportiva : Automobile
    {
        private int _cavalliVapore;
        private bool _hasTurbo;

        public int CavalliVapore
        {
            get { return _cavalliVapore; }
            set
            {
                if (value >= 100 && value <= 2000)
                    _cavalliVapore = value;
                else
                    MessageBox.Show("Cavalli vapore devono essere tra 100 e 2000!",
                                  "ERRORE", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public bool HasTurbo
        {
            get { return _hasTurbo; }
            set { _hasTurbo = value; }
        }

        // Costruttore: chiama base per modello, cilindrata, carburante
        public AutoSportiva(string modello, int cilindrata, string carburante,
                            int cavalliVapore, bool hasTurbo)
            : base(modello, cilindrata, carburante)
        {
            CavalliVapore = cavalliVapore;
            HasTurbo = hasTurbo;
        }

        // Override personalizzato per AutoSportiva
        public override string Stampa()
        {
            string turbo = HasTurbo ? " [TURBO]" : "";
            return $"{Modello} [๐ŸŽ๏ธ Sport]{turbo} - {Cilindrata}cc - " +
                   $"{CavalliVapore}cv - {Carburante}";
        }
    }
}

Override: Personalizzare i Metodi Ereditati

override significa letteralmente "sostituire". Una classe figlia puรฒ riscrivere un metodo del genitore per dargli un comportamento diverso, piรน adatto al suo tipo specifico.

๐Ÿ”‘ Le Tre Parole Chiave: virtual, override, base

Parola chiave Dove si mette Cosa significa
virtual Nel metodo della classe BASE "Questo metodo puรฒ essere riscritto dalle figlie"
override Nel metodo della classe FIGLIA "Sostituisco la versione del genitore con la mia"
base.Metodo() Dentro l'override della FIGLIA "Richiama anche il metodo originale del genitore"

Esempio completo - virtual, override, base

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// CLASSE BASE
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
public class Automobile
{
    public virtual string Stampa()          // โ† virtual: "puรฒ essere overridato"
    {
        return $"{Modello} - {Cilindrata}cc - {Carburante}";
    }
}

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// CLASSE FIGLIA - Override completo
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
public class AutoElettrica : Automobile
{
    public override string Stampa()        // โ† override: "sostituisco la versione base"
    {
        // Versione completamente nuova, ignora quella di Automobile
        return $"{Modello} [โšก] - Autonomia: {AutonomiaKm}km";
    }
}

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// CLASSE FIGLIA - Override con base (estende senza perdere)
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
public class AutoSportiva : Automobile
{
    public override string Stampa()
    {
        // Richiama il metodo del genitore e CI AGGIUNGE qualcosa
        string testoBase = base.Stampa();  // โ† "base." chiama Automobile.Stampa()
        // testoBase = "Ferrari 488 - 3900cc - Benzina"

        return testoBase + $" | {CavalliVapore}cv";
        // Risultato: "Ferrari 488 - 3900cc - Benzina | 660cv"
    }
}

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// Risultato nelle listbox:
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// Automobile normale:  "Fiat 500 - 1200cc - Benzina"
// AutoElettrica:       "Tesla [โšก] - Autonomia: 500km"
// AutoSportiva:        "Ferrari 488 - 3900cc - Benzina | 660cv"

โš ๏ธ Errore Comune: dimenticare "virtual"

// โŒ SBAGLIATO: metodo nella base senza "virtual"
public class Automobile
{
    public string Stampa()   // โ† manca "virtual"!
    {
        return $"{Modello} - {Cilindrata}cc";
    }
}

public class AutoElettrica : Automobile
{
    public override string Stampa()   // ๐Ÿ’ฅ ERRORE di compilazione!
    // "non si puรฒ fare override di un metodo non-virtual"
    { ... }
}

// โœ… SOLUZIONE: aggiungi "virtual" nella classe base
public class Automobile
{
    public virtual string Stampa()   // โ† ora le figlie possono overridarlo
    { ... }
}

Polimorfismo: Un'Unica Lista per Tutti i Tipi

Polimorfismo viene dal greco: "molte forme". รˆ il concetto piรน potente dell'ereditarietร : puoi trattare oggetti di tipo diverso come se fossero tutti dello stesso tipo base.

๐Ÿค” Il Problema: Tre Liste Separate

โŒ SENZA Polimorfismo - Devi gestire tre liste

// Devi tenere tre liste separate:
private List<Automobile>   listaAuto;
private List<AutoElettrica> listaElettriche;
private List<AutoSportiva>  listaSportive;

// Tre foreach per aggiornare la ListBox:
foreach (Automobile a in listaAuto)       lstAuto.Items.Add(a);
foreach (AutoElettrica e in listaElettriche) lstAuto.Items.Add(e);
foreach (AutoSportiva s in listaSportive)  lstAuto.Items.Add(s);

// Tre cicli per salvare su file:
// ... idem ...

// ๐Ÿ˜ฑ Il codice esplode di complessitร !

โœ… CON Polimorfismo - Una sola lista, tutto funziona

โœ… CON Polimorfismo - Elegante e semplice

// UNA SOLA lista di tipo Automobile
// ma puรฒ contenere anche AutoElettrica e AutoSportiva!
// Perchรฉ AutoElettrica e AutoSportiva SONO Automobile (ereditarietร )
private List<Automobile> listaAuto;

// Aggiungi tutti i tipi nella stessa lista:
listaAuto.Add(new Automobile("Fiat 500", 1200, "Benzina"));
listaAuto.Add(new AutoElettrica("Tesla Model 3", 500, 85));
listaAuto.Add(new AutoSportiva("Ferrari 488", 3900, "Benzina", 660, true));

// UN SOLO foreach per aggiornarla:
foreach (Automobile auto in listaAuto)
{
    // C# chiama automaticamente il Stampa() GIUSTO per ogni oggetto!
    // - Se รจ Automobile normale โ†’ usa Automobile.Stampa()
    // - Se รจ AutoElettrica     โ†’ usa AutoElettrica.Stampa() (override)
    // - Se รจ AutoSportiva      โ†’ usa AutoSportiva.Stampa()  (override)
    lstAuto.Items.Add(auto);   // ToString() โ†’ Stampa() corretto!
}

// Risultato nella ListBox:
// Fiat 500 - 1200cc - Benzina
// Tesla Model 3 [โšก Elettrica] - Autonomia: 500km - Batteria: 85%
// Ferrari 488 [๐ŸŽ๏ธ Sport][TURBO] - 3900cc - 660cv - Benzina

๐ŸŽฌ Come Funziona il Polimorfismo - Dietro le Quinte

// La lista contiene oggetti di tipo diverso, MA la variabile รจ Automobile:
Automobile auto = listaAuto[1];   // Prendo il secondo elemento

// Questo oggetto รจ in realtร  un'AutoElettrica (era il Tesla)
// Ma C# SA che tipo รจ realmente (lo ricorda in memoria)

// Quando chiami Stampa()...
string testo = auto.Stampa();
//             โ†‘
// C# non chiama Automobile.Stampa()
// C# chiama AutoElettrica.Stampa()  โ† quello giusto!
//
// Questo si chiama DISPATCH DINAMICO:
// la versione del metodo da chiamare viene scelta
// a RUNTIME (mentre il programma gira) non a compilazione

// รˆ come se l'oggetto dicesse:
// "Sรฌ, mi chiami Automobile, ma io so CHI SONO davvero!"

๐Ÿ”Ž Riconoscere il Tipo Reale: is e as

A volte hai bisogno di sapere il tipo reale di un oggetto nella lista e accedere alle proprietร  specifiche.

foreach (Automobile auto in listaAuto)
{
    // "is" controlla se l'oggetto รจ di quel tipo
    if (auto is AutoElettrica)
    {
        // "as" converte l'oggetto al tipo specifico
        AutoElettrica elettrica = auto as AutoElettrica;

        // Ora puoi accedere alle proprietร  di AutoElettrica
        MessageBox.Show($"Autonomia: {elettrica.AutonomiaKm}km");
    }
    else if (auto is AutoSportiva)
    {
        AutoSportiva sportiva = auto as AutoSportiva;
        MessageBox.Show($"Potenza: {sportiva.CavalliVapore}cv");
    }
    else
    {
        // รˆ un'Automobile normale
        MessageBox.Show($"Auto standard: {auto.Modello}");
    }
}

Esempio Pratico: Aggiungere le Classi Figlie al Form

Vediamo come modificare il Form del Parco Auto per gestire anche AutoElettrica e AutoSportiva con la stessa lista.

  1. Aggiungere una ComboBox per il Tipo di Auto

Aggiungi una ComboBox chiamata cmbTipoAuto con le voci: "Standard", "Elettrica", "Sportiva".

Form1.cs - Inizializzazione

private void InizializzaTipiAuto()
{
    cmbTipoAuto.Items.Add("Standard");
    cmbTipoAuto.Items.Add("Elettrica");
    cmbTipoAuto.Items.Add("Sportiva");
    cmbTipoAuto.SelectedIndex = 0;
}
  1. Logica di Aggiunta: creare il tipo giusto in base alla scelta

Form1.cs - btnAggiungi_Click con Polimorfismo

private void btnAggiungi_Click(object sender, EventArgs e)
{
    if (!ControllaCampi()) return;
    if (!ValidaCilindrata(txtCilindrata.Text)) return;

    string modello    = txtModello.Text;
    int cilindrata    = Convert.ToInt32(txtCilindrata.Text);
    string carburante = cmbCarburante.SelectedItem.ToString();
    string tipoScelto = cmbTipoAuto.SelectedItem.ToString();

    // Variabile di tipo BASE โ†’ puรฒ contenere qualsiasi figlia
    Automobile nuovaAuto;

    // Crea il tipo giusto in base alla scelta dell'utente
    if (tipoScelto == "Elettrica")
    {
        // Chiedi i dati specifici per l'elettrica
        int autonomia = 400;     // Potresti leggerli da una TextBox dedicata
        int batteria = 100;
        nuovaAuto = new AutoElettrica(modello, autonomia, batteria);
    }
    else if (tipoScelto == "Sportiva")
    {
        int cv = 300;            // Anche questi da TextBox dedicate
        bool turbo = false;
        nuovaAuto = new AutoSportiva(modello, cilindrata, carburante, cv, turbo);
    }
    else
    {
        // Standard
        nuovaAuto = new Automobile(modello, cilindrata, carburante);
    }

    // Aggiunge alla lista (polimorfismo: sempre List<Automobile>!)
    listaAuto.Add(nuovaAuto);

    // Aggiorna - funziona per TUTTI i tipi grazie al polimorfismo
    AggiornaListaAuto();
    AggiornaStatistiche();
    PulisciCampi();
}
  1. Statistiche per Tipo - Usare is per contare

Form1.cs - AggiornaStatistiche con tipi

private void AggiornaStatistiche()
{
    int totale      = listaAuto.Count;
    int standard    = 0;
    int elettriche  = 0;
    int sportive    = 0;

    foreach (Automobile auto in listaAuto)
    {
        if (auto is AutoElettrica) elettriche++;
        else if (auto is AutoSportiva) sportive++;
        else standard++;
    }

    lblTotaleAuto.Text = $"Totale: {totale} " +
                         $"(Standard: {standard} | " +
                         $"โšก Elettriche: {elettriche} | " +
                         $"๐ŸŽ๏ธ Sportive: {sportive})";
}

Schema Riassuntivo: Ereditarietร  e Polimorfismo

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    AUTOMOBILE (Classe Base)                     โ”‚
โ”‚  protected: _modello, _cilindrata, _carburante                  โ”‚
โ”‚  public:    Modello, Cilindrata, Carburante (proprietร )         โ”‚
โ”‚  virtual:   Stampa()  โ† puรฒ essere sostituito dalle figlie      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           โ”‚  eredita con ":"
             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
             โ†“             โ†“             โ†“
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚AutoElettrica โ”‚ โ”‚ AutoSportiva โ”‚ โ”‚  AutoLusso   โ”‚
   โ”‚ (figlia)     โ”‚ โ”‚  (figlia)    โ”‚ โ”‚  (figlia)    โ”‚
   โ”‚              โ”‚ โ”‚              โ”‚ โ”‚              โ”‚
   โ”‚ +AutonomiaKm โ”‚ โ”‚ +CavalliVap. โ”‚ โ”‚ +Prezzo      โ”‚
   โ”‚ +Batteria%   โ”‚ โ”‚ +HasTurbo    โ”‚ โ”‚ +Brand       โ”‚
   โ”‚ +KmRimasti   โ”‚ โ”‚              โ”‚ โ”‚              โ”‚
   โ”‚              โ”‚ โ”‚              โ”‚ โ”‚              โ”‚
   โ”‚ override     โ”‚ โ”‚ override     โ”‚ โ”‚ override     โ”‚
   โ”‚ Stampa()     โ”‚ โ”‚ Stampa()     โ”‚ โ”‚ Stampa()     โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

POLIMORFISMO in azione:
  List<Automobile> lista = new List<Automobile>();
  lista.Add(new Automobile(...));      // โœ… Standard
  lista.Add(new AutoElettrica(...));   // โœ… Figlia accettata!
  lista.Add(new AutoSportiva(...));    // โœ… Figlia accettata!

  foreach (Automobile a in lista)
  {
      lstAuto.Items.Add(a);   // Chiama Stampa() GIUSTO per ognuno โœ…
  }

REGOLA FONDAMENTALE:
  "Una figlia PUร’ essere usata dove si aspetta il genitore"
  AutoElettrica IS-A Automobile  โ†’ true โœ…
  Automobile IS-A AutoElettrica  โ†’ false โŒ

๐ŸŽฏ Riepilogo: Tre Concetti in Tre Frasi

๐Ÿงฌ Ereditarietร 

La classe figlia riceve gratis tutto quello che ha la classe genitore. Aggiungi solo le parti nuove. Si scrive con : NomeGenitore.

class AutoElettrica : Automobile
{ /* eredita tutto! */ }

๐Ÿ” Override

La figlia puรฒ riscrivere un metodo del genitore per adattarlo al suo caso. Il genitore marca il metodo virtual, la figlia usa override.

public override string Stampa()
{ return "versione mia!"; }

๐ŸŽญ Polimorfismo

Puoi mettere tipi diversi nella stessa lista (di tipo base). Ogni oggetto risponde con il metodo giusto per il suo tipo.

List<Automobile> lista;
lista.Add(new AutoElettrica(...));
// funziona! โœ…

Riepilogo: Cosa Hai Imparato

1๏ธโƒฃ Ereditarietร 

Le classi figlie ricevono gratis tutto il codice del genitore con : NomeClasse. Scrivi meno, riusa di piรน: niente piรน codice duplicato!

2๏ธโƒฃ Override

Con virtual nel genitore e override nella figlia, ogni classe puรฒ personalizzare un metodo mantenendo la stessa firma. Puoi anche richiamare l'originale con base.Metodo().

3๏ธโƒฃ Polimorfismo

Una sola List<Automobile> puรฒ contenere Automobile, AutoElettrica, AutoSportiva. Ogni oggetto risponde con il metodo giusto per il suo tipo, automaticamente.

๐Ÿ† Con le tre lezioni del Parco Auto hai imparato a progettare classi, rendere i dati permanenti e costruire gerarchie di classi: la base di qualsiasi applicazione seria.

Esercizi per Fare Pratica

๐Ÿš— Parco Auto con Ereditarietร : la sfida!

  • Parti dal progetto Parco Auto delle lezioni precedenti
  • Crea la classe figlia AutoElettrica con AutonomiaKm e PercentualeBatteria
  • Crea la classe figlia AutoSportiva con CavalliVapore e HasTurbo
  • Overrida Stampa() in entrambe per mostrare i dati specifici
  • Usa una sola List<Automobile> per contenere tutti i tipi
  • Nelle statistiche, mostra il conteggio separato per tipo (is)

๐Ÿ“ฑ Livello Base: Device Elettronici con suggerimenti

๐Ÿ’ก Suggerimento: Inizia con una classe base Device con marca, modello e prezzo

  • Crea una classe base Device con: Marca, Modello, Prezzo (virtual per calcolo sconto)
  • Crea classi derivate:
    • Smartphone con SistemaOperativo e MemoriaGB
    • Tablet con HasPenna e PolliciSchermo
    • Laptop con RamGB e Processore
  • ๐Ÿ” Override del metodo Descrizione() in ogni classe figlia
  • Aggiungi CalcolaPrezzoScontato() nella base e overridalo in Smartphone (sconto 10%) e Laptop (sconto 15%)
  • Usa List<Device> per gestire tutti i dispositivi

๐Ÿ’ฐ Livello Facile: App Pagamenti Digitali

๐ŸŒ Ispirato a Satispay, PayPal, carte di credito

  • Classe base MetodoPagamento con: Intestatario, Saldo
  • Classi derivate:
    • CartaCredito: Numero, Scadenza, CVV, Massimale
    • PayPal: Email, CashbackPercentuale
    • AppBancaria: IBAN, Banca, HasBiometricAuth
  • Override di EseguiPagamento(decimal importo):
    • CartaCredito: verifica massimale
    • PayPal: applica cashback se importo > 50โ‚ฌ
    • AppBancaria: richiede conferma biometrica
  • ๐ŸŽฏ Extra: Override di CalcolaCostoTransazione() diverso per ogni metodo

๐Ÿ  Livello Intermedio: Casa Intelligente

๐Ÿท๏ธ Dispositivi smart che comunicano come nella vita reale

  • Classe base astratta SmartDevice con: Nome, Stanza, Stato, Consumo
  • Interfaccia ITimerSupport per dispositivi con timer
  • Classi derivate:
    • LampadinaSmart: ColoreRGB, Luminositร , ITimerSupport
    • Termostato: TemperaturaAttuale, TemperaturaTarget
    • TapparellaElettrica: PercentualeApertura
  • Override obbligatorio di EseguiComando(string comando) per ogni dispositivo
  • Gestisci tutto con List<SmartDevice> (polimorfismo)

๐Ÿ›ต Livello Avanzato: App di Delivery

๐Ÿ“ฆ Ispirato a Glovo/JustEat - diversi tipi di consegna

  • Classe base Ordine con: ID, Cliente, Indirizzo
  • Interfacce:
    • IConsegnaFresco per catena del freddo
    • IConsegnaUrgente per consegne prioritarie
    • ITracciabile per tracking GPS
  • Classi con interfacce multiple:
    • OrdineCibo: TipoCucina, Temperatura โ†’ IConsegnaFresco, IConsegnaUrgente
    • OrdineFarmacia: RicettaMedica โ†’ IConsegnaUrgente, ITracciabile
    • OrdineRegalo: Messaggio โ†’ ITracciabile
  • Override di CalcolaCostoConsegna() con regole diverse per ogni tipo
  • ๐Ÿ† Challenge: Sistema di prioritร  - ordini urgenti processati prima

๐ŸŽฎ Livello Esperto: Personaggi RPG

โš”๏ธ Gerarchia complessa con override a catena

  • Classe base astratta Personaggio con: Nome, Livello, PV, Mana
  • Metodi virtual: Attacca(), Difendi(), UsaAbilita()
  • Gerarchia a 3 livelli:
    • Liv1: Guerriero, Mago, Arciere
    • Liv2: Paladino (da Guerriero), Negromante (da Mago)
    • Liv3: CavaliereDrago (da Paladino)
  • Override a catena con base.Attacca() per accumulare bonus
  • Pattern Observer: quando un personaggio muore, tutti i nemici reagiscono

โญ BONUS: Gestione Dipendenti Aziendale

Simula ruoli aziendali con diverse regole di stipendio - Confronto tra didattica e realtร 

  • Classe base Dipendente: Nome, Cognome, Matricola, Anzianitร 
  • Classi derivate:
    • Impiegato: Livello, Straordinari (override stipendio con bonus)
    • Manager: BudgetTeam, Progetti (override bonus progetti)
    • Dirigente: StockOptions (override partecipazione utili)
    • Stagista: Tutor, Durata (override stipendio = rimborso spese)
  • Interfaccia IConsulente per chi lavora su progetti esterni
  • Override di ToString() per riepilogo completo

CONFRONTO: Come funziona nel programma vs Come funziona davvero

1๏ธโƒฃ IMPIEGATO
Aspetto Nel PROGRAMMA Nella VITA REALE
Livello Numero da 1 a 10 che dร  100โ‚ฌ in piรน al mese per ogni livello รˆ il tuo inquadramento (es. apprendista, impiegato semplice, impiegato senior). Ogni livello ha uno stipendio minimo diverso stabilito dal contratto nazionale
Straordinari 25โ‚ฌ per ogni ora, pagati subito nello stipendio del mese Si pagano con una maggiorazione: +15% se sono in settimana, +30% se di sabato, +50% se di notte. Di solito li pagano il mese dopo
Calcolo base + (livelloร—100) + (straordinariร—25) Minimo del contratto + aumenti per anzianitร  + straordinari con percentuali
2๏ธโƒฃ MANAGER
Aspetto Nel PROGRAMMA Nella VITA REALE
Budget Team Prende il 5% del budget TUTTI I MESI Il budget รจ per tutto l'anno. Il premio (bonus) lo riceve a fine anno se ha raggiunto gli obiettivi, e puรฒ essere dal 10% al 50% del suo stipendio annuale
Progetti 500โ‚ฌ per ogni progetto finito, pagati subito I progetti fanno parte degli obiettivi annuali. Non รจ "tot progetti fatti" ma "come li hai fatti" (rispettato tempi? budget? qualitร ?)
Esempio Budget 100.000โ‚ฌ โ†’ 5.000โ‚ฌ in piรน ogni mese (60.000โ‚ฌ in piรน all'anno di soli bonus) Stipendio 50.000โ‚ฌ all'anno + premio 10.000โ‚ฌ a fine anno se obiettivi raggiunti
3๏ธโƒฃ DIRIGENTE
Aspetto Nel PROGRAMMA Nella VITA REALE
Stock Options รˆ solo un numero, non viene usato per calcolare lo stipendio รˆ il diritto di comprare azioni della societร  a un prezzo scontato. Se il valore delle azioni sale, puoi rivenderle e guadagnare la differenza
Utile Aziendale Prende il 2% dell'utile TUTTI I MESI L'utile si calcola sul bilancio di fine anno. Il dirigente riceve una percentuale sugli utili una volta all'anno
Esempio Utile 2 milioni โ†’ 40.000โ‚ฌ in piรน ogni mese (480.000โ‚ฌ in piรน all'anno) Utile 2 milioni โ†’ premio di 40.000โ‚ฌ una volta a fine anno
4๏ธโƒฃ STAGISTA
Aspetto Nel PROGRAMMA Nella VITA REALE
Tutor รˆ solo un nome associato allo stagista รˆ la persona che segue lo stagista, gli insegna il lavoro, firma i documenti e alla fine lo valuta
Durata Mesi di stage (da 1 a 6) Di solito 3 o 6 mesi. A volte si puรฒ allungare. La legge dice quanto puรฒ durare al massimo
Rimborso 600โ‚ฌ fissi al mese per tutti Se รจ stage per scuola/universitร  spesso non pagano. Se รจ stage dopo gli studi, danno un rimborso che puรฒ essere 300-800โ‚ฌ in base al contratto
5๏ธโƒฃ CONSULENZA (chi lavora su progetti esterni)
Aspetto Nel PROGRAMMA Nella VITA REALE
Tariffa oraria Moltiplica per le ore e paga subito Chi fa consulenza di solito ha partita IVA. Emette fattura e viene pagato dopo 30-60-90 giorni, deve pagarci le tasse sopra

LE DIFFERENZE PIร™ IMPORTANTI

Concetto Nel programma Nella realtร 
Premio per progetti Pagato subito, ogni mese Si valuta a fine anno
Percentuale sul budget 5% tutti i mesi Premio una volta all'anno se raggiungi obiettivi
Percentuale sugli utili 2% tutti i mesi Una volta all'anno a bilancio chiuso
Stock options Solo un numero Possibilitร  di guadagnare in futuro se le azioni salgono

PROGRAMMA

Il nostro codice รจ fatto per imparare a programmare, non per fare paghe vere. Serve a capire:

  • Override - Come le classi figlie possono cambiare i metodi del padre
  • Polimorfismo - Lo stesso metodo (CalcolaStipendio()) funziona in modo diverso per ogni tipo
  • Incapsulamento - I dati sono protetti ma accessibili alle classi che servono

Se dovessimo fare un programma vero per paghe, sarebbe molto piรน complicato: bisognerebbe distinguere mensile da annuale, calcolare tasse, contributi, e mille altre cose. Ma per imparare l'ereditarietร  e il polimorfismo, cosรฌ va benissimo!

Mappa dei Concetti negli Esercizi:

Esercizio Ereditarietร  Polimorfismo Override Extra
Device โœ… Base โœ… List โœ… Virtual Suggerimenti
Pagamenti โœ… Singola โœ… Metodi โœ… Con logica Contesto reale
Smart Home โœ… Astratta โœ… Comandi โœ… Obbligatorio Interfacce
Delivery โœ… Multipla โœ… Pattern โœ… Complesso Interfacce multiple
RPG โœ… Multi-livello โœ… Avanzato โœ… A catena Observer
Aziendale โœ… Gerarchica โœ… Oggetti โœ… ToString Mondo reale

๐Ÿ–ฅ๏ธ Suggerimenti per l'Interfaccia Grafica:

  • ComboBox per selezionare il tipo di oggetto da creare
  • Campi che cambiano dinamicamente in base al tipo selezionato
  • DataGridView con colonne specifiche usando polimorfismo
  • Pannello statistiche che conta i tipi con 'is'
  • Per RPG: barre della vita visive che si aggiornano

Prossimi Passi

Nelle Prossime Lezioni Imparerai:

  • โšก Eventi Multipli: Un solo metodo per gestire tanti controlli
  • ๐ŸŽฏ Il Parametro sender: Scoprire QUALE controllo ha generato l'evento
  • โœ… Validazione in Tempo Reale: Controllare mentre l'utente digita
  • ๐ŸŽจ Feedback Visivo: Cambiare colori per guidare l'utente

๐ŸŽฏ Scriverai codice piรน elegante e programmi piรน user-friendly!

โœ… Nelle tre lezioni del Parco Auto hai affrontato:

  • ๐Ÿ—๏ธ Classi con campi private/protected e proprietร  con validazione
  • ๐Ÿ“‹ CRUD completo su List<Automobile>
  • ๐Ÿ’พ Salvataggio e lettura da file TXT e CSV
  • ๐Ÿ”„ Ordinamento con Sort() e lambda
  • ๐Ÿงฌ Ereditarietร  con classi figlie (: NomeClasse)
  • ๐Ÿ” Override di metodi (virtual + override + base)
  • ๐ŸŽญ Polimorfismo: una lista, tanti tipi, ogni oggetto risponde correttamente

๐Ÿ“š Teoria collegata (percorso C# โ€“ il linguaggio, esempi in console): Ereditarietร , polimorfismo, classi astratte e interfacce.