8
PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N. Muto) Approfondimento EREDITARIETA' In questa lezione trattiamo il terzo ed ultimo fattore caratteristico della programmazione a oggetti, ossia la possibilità di implementare classi a partire da altre classi implementate in precedenza. Oltre al vantaggio di poter riutilizzare codice già scritto, l'ereditarietà consente una organizzazione efficientissima del codice, potendo creare delle gerarchie di classi, estendibile finché si vuole oltre semplici e veloci da manutenere. Come già anticipato nella lezione XXX la classe creata prima viene denominata classe “base” o “madre” mentre la classe derivata prende il nome di “derivata” o “figlia” e quest'ultima può diventare a sua volta classe base per una successiva classe derivata e così via. Una delle differenze del linguaggio C# con altri linguaggi OOP riguardo all'ereditarietà è che in C# una classe figlia può avere SOLO una classe base e non più di una. Rappresentando il concetto in forma grafica quindi si ha che la soluzione a sinistra è ammessa mentre quella a destra no. Invece è possibile per una classe base avere più classi derivate nello stesso livello. CLASSE BASE CLASSE DERIVATA CLASSE BASE1 CLASSE BASE2 CLASSE DERIVATA

PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

  • Upload
    lyquynh

  • View
    232

  • Download
    0

Embed Size (px)

Citation preview

Page 1: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N. Muto)

Approfondimento EREDITARIETA'In questa lezione trattiamo il terzo ed ultimo fattore caratteristico della programmazione a

oggetti, ossia la possibilità di implementare classi a partire da altre classi implementate in

precedenza.

Oltre al vantaggio di poter riutilizzare codice già scritto, l'ereditarietà consente una

organizzazione efficientissima del codice, potendo creare delle gerarchie di classi, estendibile

finché si vuole oltre semplici e veloci da manutenere. Come già anticipato nella lezione XXX la

classe creata prima viene denominata classe “base” o “madre” mentre la classe derivata

prende il nome di “derivata” o “figlia” e quest'ultima può diventare a sua volta classe base per

una successiva classe derivata e così via. Una delle differenze del linguaggio C# con altri

linguaggi OOP riguardo all'ereditarietà è che in C# una classe figlia può avere SOLO una

classe base e non più di una.

Rappresentando il concetto in forma grafica quindi si ha che la soluzione a sinistra è

ammessa mentre quella a destra no.

Invece è possibile per una classe base avere più classi derivate nello stesso livello.

CLASSE BASE

CLASSE DERIVATA

CLASSE BASE1 CLASSE BASE2

CLASSE DERIVATA

Page 2: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

La classe derivata “eredita” tutti i membri della classe base ma possono essere imposte

delle condizioni per motivi di sicurezza e praticità usando gli stessi modificatori di accesso o

visibilità già incontrati finora con l'aggiunto di uno nuovo: “protected”; in particolare sono valide

le regole riassunte dalla seguente tabella:

Modificatore di visibilità Descrizione

publicLe classi derivate hanno accesso a questi membri, come tutto il codice esterno alla classe.

protectedLe classi derivate hanno accesso ai membri dichiarati “protected” ma il codice esterno no.

privateLe classi derivate NON hanno accesso a questi membri, così come il codice esterno.

Una classe base potrebbe essere creata solo per motivi organizzativi, senza contenere

nessuna implementazione di metodi, in questo caso occorre usare la parola chiave “abstract”, sarà poi la classe derivata a implementare i metodi in modo corretto. Ad esempio se dobbiamo

creare una raccolta di codice per gestire delle figure geometriche piane, potremmo decidere

per motivi organizzativi di creare una classe base “FiguraGeometrica” che conterrà dei metodi

“CalcolaArea” e “CalcolaPerimetro” anche se di fatto non sapremo come fare a calcolarli

perché abbiamo solo creato il concetto di “figura geometrica”, e quindi siamo rimasti ad un

livello “astratto” appunto!

Quando avremo derivato la classe “Quadrilatero” oppure la classe “Triangolo” dalla classe

base, allora potremo definire il metodo “CalcolaPerimetro” mentre non è detto che sappiamo

come calcolare l'area, per la quale dovremo aspettare di avere un ulteriore livello di

derivazione, come ad esempio “Rettangolo”, oppure TriangoloRettangolo”. In questo esempio

possiamo anche capire quindi come l'ereditarietà consenta una organizzazione che dal

generale scende mano a mano nello specifico, permettendo di definire in modo più dettagliato

le proprietà degli oggetti derivati.

Un altra situazione che potremmo avere è quella di una classe base che contiene dei

metodi implementati, da cui si deriva una classe derivata che ha bisogno di personalizzare

qualcuno dei metodi ereditati dalla classe base. Questo si può fare usando le parole chiave

Page 3: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

“virtual” ed “override”, come vedremo nell'esempio di codice che seguirà a breve. Qui

possiamo intanto anticipare che “virtual” si userà nella classe base in corrispondenza del

metodo che potrà essere “riscritto” dalla classe derivata, invece “override” si userà nella classe

derivata quando andremo a riscrivere il metodo suddetto.

Per inciso possiamo notare che questa situazione altro non è se non un caso di

“polimorfismo”, applicato all'ereditarietà. Infatti classe base e classe derivata usano sempre lo

stesso nome per indicare codice differente, sarà poi il compilatore ad eseguire il giusto

collegamento poiché conosce da dove è derivato l'oggetto chiamato.

Ora è arrivato il momento di mettere in pratica quanto finora definito per cui decidiamo di

realizzare un codice per gestire le figure geometriche piane organizzando il suo sviluppo

usando le classi con l'ereditarietà. Decidiamo di partire da una classe base che rappresenti il

concetto astratto di “Figura Geometrica” ma che contengo comunque dei dati membro, da

questa deriveremo due classi figlie ossia “Triangolo” e” “Rettangolo”. Successivamente dalla

classe “Triangolo” deriveremo una ulteriore classe specializzata, ossia “TriangoloRettangolo”

//classe base astratta per definire una figura geometrica piana

public abstract class FiguraGeometrica2D { //dati membro utilizzabili dalle classi derivate ma non dal codice esterno alla classe protected float Area; public float Perimetro; public int NumeroLati;

//questa è un metodo astratto e si può evitare di definirne il corpo public abstract float CalcolaArea();

public FiguraGeometrica2D() { Console.WriteLine("\n Stai creando una figura geometrica 2D"); }

}//fine della classe FiguraGeometrica

La scritta “Console.WriteLine("\n Stai creando una figura geometrica 2D");” nel costruttore è stata

inserita per facilitare allo studente nel seguire le varie fasi di creazione degli oggetti.

Nella prossima pagina vedremo l'esempio di una prima classe derivata, ossia la classe

“Triangolo”.

Definendo una funzione “abstract” si può evitare di definirne il corpo. In effetti non sapremmo cosa scrivere in questo metodo perché la classe non rappresenta al momento NESSUNA figura specifica.

La classe “FiguraGeometrica” definisce una organizzazione, una base comune e condivisa fra tutte le figure piane che vogliamo rappresentare.

Page 4: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

public class Triangolo : FiguraGeometrica2D {

//definisco i dati membro per i lati //invece Area, Perimetro e NumeroLati vengono ereditate public float a; public float b; public float c;

//Scrivo il costruttore public Triangolo(float pa, float pb, float pc) {

//controlliamo che ogni lato sia minore della somma degli altri due, altrimenti il programma termina if (!((pa < pb + pc) && (pb < pa + pc) && (pc < pb + pa))) { Console.WriteLine("\n I dati inseriti non consentono la creazione di un triangolo!"); Console.ReadLine(); Environment.Exit(-1); } Console.WriteLine("\n Stai creando un TRIANGOLO generico"); this.a = pa; this.b = pb; this.c = pc; Perimetro = a + b + c; this.NumeroLati = 3; }

//la funzione per calcolare l'area posso scriverla usando la formula di Erone public override float CalcolaArea() {

float p = Perimetro / 2; Area = (float)Math.Sqrt(p*(p-a)*(p-b)*(p-c)); return Area; }

public virtual void CheckRetto() { Console.WriteLine("Metodo che deve essere sovrascritto dalla classe derivata"); }

}//fine della classe Triangolo

In questo esempio vediamo quindi anche come si “sovrascrive” una funzione avente lo

stesso nome di un'altra (altro esempio di polimorfismo) e come ci si predispone a crearne una

“segnaposto” da far scrivere realmente alla classe figlia.

Nella prossima pagina vedremo l'ultima classe derivata: TriangoloRettangolo”, arrivando

così a ben 3 livelli gerarchici!

Poiché ora so che sto creando un triangolo, è corretto definire i dati membro per rappresentarne i 3 lati.

Questa funzione “sovrascrive” quella definita nella classe base, occorre perciò avvisare il compilatore che ciò è voluto, questo si fa con la parola chiave “override”.

Questo metodo invece è destinato ad essere sovrascritto nella classe “TriangoloRetto” che sarà derivato dalla classe “Triangolo”, per cui viene dichiarato “virtual” nella classe base.

La parola chiave “this” identifica l'oggetto stesso. In questo caso avremmo anche potuto scrivere a= pa; b = pb; c = pc;

Page 5: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

public class TriangoloRettangolo : Triangolo {

public TriangoloRettangolo(float pra, float prb, float prc) : base(pra, prb, prc) //questa istruzione richiama il costruttore della classe base di TriangoloRettangolo { Console.WriteLine("\n Stai creando un TRIANGOLO RETTANGOLO, i primi due lati si considerano cateti"); } //In questa classe posso riscrivere il metodo per calcolare l'Area public override float CalcolaArea() { float A = a * b/2; return A; }

public override void CheckRetto() {

Console.WriteLine("\n Metodo della classe derivata"); if(!((a*a == b*b+c*c)||(b*b == a*a+c*c)||(c*c == a*a+b*b))){ Console.WriteLine("\n I dati inseriti non sono di un triangolo rettangolo!"); Console.ReadLine(); Environment.Exit(-1); } }

}// fine della classe TriangoloRettangolo

Vediamo ora, per completezza, una classe Rettangolo creat a partire dalla classe base astratta "FiguraGeometrica"; non mettiamo alcun commento per stimolare il lettore a comprenderla da solo usando le informazioni già abbondantemente fornite negli esempi precedenti.public class Rettangolo : FiguraGeometrica2D

{ //definisco i dati membro per i lati //invece Area, Perimetro e NumeroLati vengono ereditate public float a; public float b; //Scrivo il costruttore public Rettangolo(float pa, float pb) { Console.WriteLine("\n Stai creando un RETTANGOLO "); this.a = pa; this.b = pb; Perimetro = 2*(a + b); this.NumeroLati = 4; }

public override float CalcolaArea() { Area = a * b; return Area; } }//fine della classe Rettangolo

Questa funzione “sovrascrive” quella definita nella classe base, occorre perciò avvisare il compilatore che ciò è voluto, questo si fa con la parola chiave “override”.

Notiamo che con questa notazione “: base...” abbiamo richiamato il costruttore della classe base di TriangoloRettangolo, che altrimenti non avrebbe potuto inizializzare correttamente l'oggetto stesso.

La funzione “CalcolaArea()” viene come al solito sovrascritta per usare una formula specifica dell'oggetto in questione.

Page 6: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

Come esercizio si propone di derivare una classe Quadrilatero dalla classe FiguraGeometrica2D e

poi dalla classe Quadrilatero derivare una classe Quadrato.

Aggiungiamo a questa lezione il modificatore “sealed”, applicabile alla dichiarazione di una

classe, quando si vuole che da tale classe NON sia possibile derivarne altre:sealed class TriangoloEquilatero : Triangolo {

}Se provassimo infatti a scrivere class TriangoloPippo : TriangoloEquilatero, il compilatore ci

darebbe un messaggio in cui ci avvisa che TriangoloPippo non può derivare da

TriangoloEquilatero. Anche questa è una caratteristica che risulta utile per l'organizzazione e

la sicurezza del codice, specie quando il codice deve girare fra vari programmatori.

Analizziamo infine il codice scritto per creare concretamente gli oggetti e vederli in azione: using System;

using System.Collections.Generic;using System.Linq;using System.Text;namespace Ereditarieta{ class Program { static void Main(string[] args) { //Faccio scegliere all'utente le misure dei lati del triangolo Console.WriteLine("\n Inserisci i tre lati del triangolo: "); Console.Write("\n a: "); float La = Convert.ToSingle(Console.ReadLine()); Console.Write("\n b: "); float Lb = Convert.ToSingle(Console.ReadLine()); Console.Write("\n c: "); float Lc = Convert.ToSingle(Console.ReadLine()); //Creo un'oggetto Triangolo Triangolo myTg = new Triangolo(La, Lb, Lc); Console.WriteLine("\n Il perimetro vale: {0} e l'area vale: {1}", myTg.Perimetro, myTg.CalcolaArea()); Console.ReadLine(); }

In questo primo "runtime" ci limiteremo a creare un triangolo generico per cui, una volta

lanciato, il programma chiederà i dati e produrrà la seguente uscita:

Le scritte

"Stai creando... 2D"

e "Stai creando..."

ci mostrano i costruttori

in azione.

Page 7: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

Modificando il main con altri oggetti, possiamo vedere la gerarchia completa di classi in

azione: static void Main(string[] args)

{ //Faccio scegliere all'utente le misure dei lati del triangolo Console.WriteLine("\n Inserisci i tre lati del triangolo: "); Console.Write("\n a: "); float La = Convert.ToSingle(Console.ReadLine()); Console.Write("\n b: "); float Lb = Convert.ToSingle(Console.ReadLine()); Console.Write("\n c: "); float Lc = Convert.ToSingle(Console.ReadLine()); //Creo un'oggetto Triangolo Triangolo myTg = new Triangolo(La, Lb, Lc);

Console.WriteLine("\n Il perimetro vale: {0} e l'area vale: {1}", myTg.Perimetro, myTg.CalcolaArea());

//Ora creo un triangolo Rettangolo

TriangoloRettangolo myTr = new TriangoloRettangolo(La,Lb,Lc);

myTr.CheckRetto(); Console.WriteLine("\n Il perimetro vale: {0} e l'area vale: {1}\n\n", myTr.Perimetro, myTr.CalcolaArea());

//Ora creo un Rettangolo Console.WriteLine("\n Inserisci base e altezza del rettangolo: "); Console.Write("\n a: "); La = Convert.ToSingle(Console.ReadLine()); Console.Write("\n b: "); Lb = Convert.ToSingle(Console.ReadLine());

Rettangolo myR = new Rettangolo(La, Lb); Console.WriteLine("\n Il perimetro vale: {0} e l'area vale: {1}", myR.Perimetro, myR.CalcolaArea());

Console.ReadLine() }

La pagina seguente mostra l'output completo del programma, notare le scritte didattiche

che indicano quando i costruttori agiscono e a chi appartengono i metodi chiamati.

Per il primo oggetto triangolo chiedo i lati. Inseriremo i lati di un triangolo rettangolo(3,4,5), in modo che possiamo passare tali valori direttamente al secondo oggetto, senza doverli chiedere ancora.

Come premesso usiamo gli stessi lati già inseriti per motivi di praticità.

In questo caso invece chiediamo i lati di un rettangolo e lo creiamo.

Page 8: PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj …elearning.cardano.pv.it/e-learn/courses/MESAPROJECT/document/... · PROGRAMMAZIONE A OGGETTI (OOP) Lezione 8 prj Mesa (Prof. Ing N

Le tre scritte sono rispettivamente: del costruttore della classe base astratta, del costruttore della prima classe derivata Triangolo e del costruttore della seconda classe derivata “TriangoloRettangolo”

Scritta del costruttore della classe base e del costruttore della derivata