C# - Ereditarietà (Inheritance)
Cos'è l'Ereditarietà
• In C# una classe può ereditare al massimo da una sola classe, ma può ereditare da una o più interfacce.
• Riguardo la classe derivata, si dice che è una specializzazione della classe base.
• Quando di crea un oggetto della classe derivata, la classe base è istanziata prima della classe derivata e quindi il costruttore della classe base è eseguito prima del costruttore della classe derivata.
• Altri linguaggi di programmazione permettono l’eredità multipla delle classi risolvendo o gestendo in qualche modo le ambiguità che possono nascere; a questo proposito si veda il "Diamond Problem".
Esempio con ereditarietà tra classi
• In questo esempio si ha la classe base ‘Persona’ e le due classi derivate ‘Dipendente’ e ‘Collaboratore’.
• È utilizzata la sintassi breve, sia nelle definizioni delle classi che nell’inizializzazione degli oggetti.
• Come si vede, le classi derivate estendono la classe base. La classe ‘Dipendende’ aggiunge le proprietà ‘Matricola’ e ‘Retribuzione’ mentre la classe ‘Collaboratore’ aggiunge la proprietà ‘Azienda’.
class Program
{
static void Main(string[] args)
{
Persona p = new Persona() {
Badge = 1,
Cognome = "Da Vinci",
Nome = "Leonardo" };
Dipendente d = new Dipendente() {
Badge = 2, Cognome = "Buonarroti",
Nome = "Michelangelo",
Matricola = 1,
Rettribuzione = 100
};
Collaboratore c = new Collaboratore() {
Badge = 3,
Cognome = "Vecellio",
Nome = "Tiziano",
Azienda = "Abc" };
}
}
// Classe base.
class Persona
{
public int Badge { get; set; }
public string Cognome { get; set; }
public string Nome { get; set; }
}
// Prima classe derivata.
class Dipendente : Persona
{
public int Matricola { get; set; }
public int Rettribuzione { get; set; }
}
// Seconda classe derivata.
class Collaboratore : Persona
{
public string Azienda { get; set; }
}
• L’aggiunta di un metodo alla classe base, rende il metodo visibile a tutti gli oggetti delle tre classi.
• Per esempio, se si aggiunge il metodo ‘StampaInformazioni()’ alla classe base, si può utilizzare questo metodo su tutti e tre gli oggetti: ‘p’, ‘d’ e ‘c’.
// Classe base.
class Persona
{
public int Badge { get; set; }
public string Cognome { get; set; }
public string Nome { get; set; }
public void StampaInformazioni()
{
Console.WriteLine("Badge: {0} Cognome: {1} Nome: {2} ", Badge.ToString(), Cognome, Nome);
}
}
p.StampaInformazioni();
d.StampaInformazioni();
c.StampaInformazioni();
Hiding
• Le classi derivate possono avere metodi con lo stesso nome e la stessa firma dei corrispondenti metodi della classe base. Questo è l’hiding: un metodo della classe derivata che nasconde il metodo della classe base.
• Nell’esempio seguente, le classi derivate ‘Dipendente’ e ‘Collaboratore’ definiscono anch’esse il metodo ‘StampaInformazioni()’ già presente nella classe base. È importante la parola chiave ‘new’ nell’instestazione di questi metodi, altrimenti il compilatore dà un warning.
// Prima classe derivata.
class Dipendente : Persona
{
public int Matricola { get; set; }
public int Rettribuzione { get; set; }
new public void StampaInformazioni()
{
Console.WriteLine("Badge: {0} Cognome: {1} Nome: {2} Matricola: {3} Retribuzione: {4} ", Badge.ToString(), Cognome, Nome, Matricola, Rettribuzione);
}
}
// Seconda classe derivata.
class Collaboratore : Persona
{
public string Azienda { get; set; }
new public void StampaInformazioni()
{
Console.WriteLine("Badge: {0} Cognome: {1} Nome: {2} Azienda; {3} ", Badge.ToString(), Cognome, Nome, Azienda);
}
}
Override
• L’Override di un metodo è un concetto molto simile all’Hiding: un metodo di una classe derivata ha lo stesso nome e la stessa firma di un metodo della classe base. La classe base deve essere ‘virtual’.
• Nell’esempio seguente, le classi derivate ‘Dipendente’ e ‘Collaboratore’ definiscono anch’esse il metodo ‘StampaInformazioni()’ già presente nella classe base. È importante la parola chiave ‘override’ nell’instestazione di questi metodi e la parola chiave ‘virtual’ nell’instestazione del metodo nella classe base, altrimenti il compilatore dà un errore.
// Classe base.
class Persona
{
public int Badge { get; set; }
public string Cognome { get; set; }
public string Nome { get; set; }
public virtual void StampaInformazioni()
{
Console.WriteLine("Badge: {0} Cognome: {1} Nome: {2} ", Badge.ToString(), Cognome, Nome);
}
}
// Prima classe derivata.
class Dipendente : Persona
{
public int Matricola { get; set; }
public int Rettribuzione { get; set; }
public override void StampaInformazioni()
{
Console.WriteLine("Badge: {0} Cognome: {1} Nome: {2} Matricola: {3} Retribuzione: {4} ", Badge.ToString(), Cognome, Nome, Matricola, Rettribuzione);
}
}
// Seconda classe derivata.
class Collaboratore : Persona
{
public string Azienda { get; set; }
public override void StampaInformazioni()
{
Console.WriteLine("Badge: {0} Cognome: {1} Nome: {2} Azienda; {3} ", Badge.ToString(), Cognome, Nome, Azienda);
}
}
Differenza tra Hiding e Override
• Apparentemente l’Hiding e l’Override sono uguali: entrambi sovrascrivono il metodo della classe base con il metodo della classe derivata. In realtà c’è una differenza.
• Per vedere la differenza tra l’Hiding e l’Override bisogna ricorrere al Polimorfismo. Esso permette di considerare un oggetto di una classe derivata, come oggetto della classe base.
• Se per esempio si ha la classe ‘Dipendente’ derivata dalla classe base ‘Persona’, l’oggetto ‘d’ di tipo ‘Dipendente’ può essere considerato di tipo ‘Persona’.
class Program
{
static void Main(string[] args)
{
Dipendente d = new Dipendente() {
Badge = 2, Cognome = "Buonarroti",
Nome = "Michelangelo",
Matricola = 1,
Rettribuzione = 100
};
Persona p = d;
p.StampaInformazioni();
Console.ReadKey();
}
}
• Il metodo ‘StampaInformazioni()’ è presente sia nella classe base, che nella classe derivata. Quale dei due metodi viene eseguito in un oggetto che ha cambiato forma?
• Se c’è l’Override del metodo (quindi metodo ‘virtual’ nella classe base e ‘override’ nella classe derivata) allora è eseguito il metodo della classe derivata. In altre parole si ‘scavalca’ l’implementazione di default della classe base.
• Se c’è l’Hiding del metodo (quindi metodo ‘new’ nella classe derivata) allora è eseguito il metodo della classe base.