Programmazione orientata agli oggetti Ivan Lanese
Argomenti Programmazione orientata agli oggetti Classi Oggetti Costruttori
Scrivere grosse applicazioni La gran parte delle applicazioni sono GROSSE Windows XP: 40 milioni LoC Google Chrome: 4,5 milioni LoC Scrivere grosse applicazioni è complesso Programmatori diversi scrivono parti diverse della stessa applicazione Un programmatore non può conoscere tutto il codice Importante definire i confini tra diverse parti del codice La programmazione orientata agli oggetti semplifica questo compito
Programmazione orientata agli oggetti È un paradigma di programmazione Diverso da quello imperativo visto fin ora Consente di scrivere le stesse applicazioni, ma in modo diverso Molto usato in pratica (C++, Java, C#, Python, ) Pensato per grosse applicazioni, ma utile anche per applicazioni piccole Nato col Simula67 Occorre ragionare in modo diverso L entità base non sono variabili e funzioni, ma gli oggetti Un oggetto contiene dei dati e le funzioni che usano questi dati Un oggetto pila contiene sia i dati della pila che le funzioni top, push, pop e empty Il codice risulta organizzato meglio e più facile da riusare
Incapsulamento Un oggetto contiene una parte pubblica e una parte privata La parte pubblica è visibile da chi usa l oggetto La parte privata no Si dice che la parte privata è incapsulata Se un programmatore modifica la parte privata lasciando inalterata quella pubblica gli altri programmatori non se ne accorgono Qualunque sia il programma che scrivono Gli altri programmatori possono ignorare completamente la parte privata Pensate al televisore e al telecomando Se sapete usare il telecomando (parte pubblica), potete usare il televisore senza sapere come è fatto dentro (parte privata)
Classi Sono tipi di dato definiti dal programmatore Definiscono sia i valori (campi) che il comportamento (metodi) del dato Un dato il cui tipo è una classe si chiama oggetto Estendono le strutture Consentendo di definire il comportamento del dato Consentendo di nascondere l'implementazione (incapsulamento) L incapsulamento consente di modificare l'implementazione di un tipo di dato (classe) senza dover modificare i programmi che lo usano Per una classe coda posso passare da implementazione con array a implementazione con puntatori
Classe rettangolo: progettazione Una classe rappresenta un tipo di entità Esempio, le entità rettangolo Per definirla bisogna decidere Quali sono le informazioni importanti (campi) Quali sono le operazioni su di esso (metodi) Da queste scelte dipende cosa sarà possibile fare con gli oggetti di quel tipo Viceversa, queste scelte dipendono da cosa si vorrà fare con oggetti rettangolo Per la classe rettangolo possiamo scegliere, ad esempio Campi: l (lunghezza), h (altezza) Metodi: perimetro, area Avremmo anche potuto aggiungere Campi: x, y, colore, bordo, orientazione, Metodi: disegna, interseca, sposta,
Classe rettangolo: definizione Per definire le classi dobbiamo imparare la loro sintassi I campi si definiscono come nelle strutture (tipo e nome) I metodi (member functions) si definiscono come normali funzioni class rettangolo{ public: int l, h; int perimetro() { return (2*(l+h));} int area() {return (l*h);} }; All interno dei metodi di una classe posso accedere ai campi e agli altri metodi semplicemente col loro nome In questo esempio tutti gli elementi del rettangolo sono public, quindi non si ha incapsulamento: a breve daremo definizioni più raffinate
Classe rettangolo: uso Definisco oggetti rettangolo usando il nome della classe come tipo rettangolo r1,r2; Accedo ai campi come a elementi di strutture r1.h = 10; if (r1.l > r1.h) Accedo ai metodi in modo simile cout << r1.perimetro(); if (r2.area() > 5)
Esercizio Definire una classe cerchio (ispirandosi alla classe rettangolo) Scrivere un programma che crea un cerchio e ne stampa l area
Esercizio (cont) Nel definire la classe cerchio avete dovuto scegliere se memorizzare in un campo il raggio o il diametro Modificare la classe cerchio precedentemente definita cambiando questa scelta (usare il diametro al posto del raggio o viceversa) Il programma precedente funziona anche con la nuova classe cerchio? O dovete cambiare anche altre parti del programma?
Incapsulamento Nell esercizio precedente un cambio alla struttura interna del cerchio richiede un cambio del programma che usa il cerchio Questo non va bene Rende il programma difficile da modificare Non posso far sviluppare la classe e il codice che lo usa a persone diverse proprio le cose che la programmazione orientata agli oggetti deve consentire Dipende dal fatto che non abbiamo separato parte pubblica e parte privata L incapsulamento consente ad una classe di nascondere l implementazione (o una sua parte)
Public e protected I campi e i metodi di un oggetto possono essere Public: visibili dall esterno Protected: non visibili dall esterno, ma incapsulati dentro class rettangolo{ protected: int l, h; public: void crea(int lun, int alt) {l=lun; h=alt;} int perimetro() { return (2*(l+h));} int area() {return (l*h);} }; Il metodo crea ora è necessario perchè da fuori non vedo più l e h r1.l = 5; ora dà errore
Cosa mettere public e cosa mettere protected Dall esterno posso usare solo campi e metodi public Tutto quello che serve all esterno deve essere public Posso modificare campi e metodi protected senza dover modificare i programmi che usano la classe Vorrei avere meno campi e metodi public possibile (information hiding) Ho un trade of Solitamente devono essere protected tutte le informazioni legate all implementazione Tutti i campi I metodi ausiliari In questo caso si parla anche di abstract data type
Usare l incapsulamento Modificare la classe cerchio precedente scegliendo il raggio come campo e usando l incapsulamento Cambiare la classe usando il diametro al posto del raggio Nota: questo richiede di cambiare anche i metodi Il programma precedente funziona anche con la nuova classe cerchio? O dovete cambiare anche altre parti del programma?
Costruttori Quando si crea un oggetto è necessario inizializzare i suoi campi Se i campi sono public (deprecated!) si può fare dal programma principale Come fare con i campi protected? Notare che solitamente tutti i campi sono protected Occorre un metodo public che li inizializzi In pratica (quasi) ogni oggetto ha bisogno di un metodo che lo inizializzi In C++ questo metodo si chiama costruttore e segue regole particolari
Costruttori (cont) Il costruttore ha lo stesso nome della classe Il costruttore non ha nessun tipo di ritorno (neanche void) rettangolo(int lun, int alt) {l=lun; h=alt;} Posso invocare il costruttore in due modi: rettangolo r1=rettangolo(5,6); //normale rettangolo r1(5,6); //abbreviato Da notare che NON posso scrivere r1.rettangolo(5,6); Il costruttore deve essere invocato al momento della dichiarazione dell oggetto
Classi: esercizi Definire una classe persona con un opportuno costruttore e metodi presentati e compianno Definire una classe frazione con un opportuno costruttore e metodi stampa, moltiplica e inverso Il metodo moltiplica prende come parametri due frazioni e mette il risultato nella frazione su cui è invocato Il metodo inverso inverte la frazione su cui è invocato Nota: all interno di un metodo di una classe posso usare i campi protected di altri oggetti della stessa classe (ad esempio ricevuti come parametri)