1 / 49

Fondamenti di Informatica 2 Ingegneria Informatica Docente: Giovanni Macchia a.a. 2002-2003

Fondamenti di Informatica 2 Ingegneria Informatica Docente: Giovanni Macchia a.a. 2002-2003. Classi ed Oggetti. Il C++ è un linguaggio di programmazione che fornisce gli strumenti per la programmazione ad oggetti. In C++ le unità fondamentali sono le classi .

Download Presentation

Fondamenti di Informatica 2 Ingegneria Informatica Docente: Giovanni Macchia a.a. 2002-2003

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Fondamenti di Informatica 2Ingegneria InformaticaDocente: Giovanni Macchiaa.a. 2002-2003

  2. Classi ed Oggetti Il C++ è un linguaggio di programmazione che fornisce gli strumenti per la programmazione ad oggetti. In C++ le unità fondamentali sono le classi. Le classi implementano gli ADT. Gli oggetti sono istanze delle classi. Vengono create considerando le classi come il loro tipo base.

  3. Classi ed Oggetti La definizione di classe avviene tramite la parola chiave class e la forma è simile alla struct, di cui rappresenta l’evoluzione: class nome_classe { public: variabili e funzioni pubbliche; private: variabili e funzioni private; protected: variabili e funzioni protette; };

  4. Classi ed Oggetti Le variabili e funzioni definite dopo la parola chiave public e prima dell’inizio della parola chiave successiva sono accessibili da altre parti del programma. Le variabili e funzioni definite dopo la parola chiave private e prima dell’inizio della parola chiave successiva sono nascoste ad altre parti del programma e possono essere usate solo da funzioni membro della classe. Vedremo più avanti il significato della parola chiave protected. Le parole chiave protected, public e private si chiamano specificatori di accesso ai membri

  5. Classi ed Oggetti Es: class Persona { private: int stipendio; public: char cognome[30]; char indirizzo[30]; }; Persona Ugo; // si istanzia un oggetto avente // come tipo dato la classe Persona; Altre parti del programma possono accedere a Ugo.cognome e Ugo.indirizzo ma non direttamente a Ugo.Stipendio

  6. Classi ed Oggetti E’ possibile per altre parti del programma accedere e/o manipolare i membri protetti tramite le funzioni membro della classe. Le funzioni membro di una classe definiscono il comportamento che esibiscono gli oggetti appartenenti a quella stessa classe. In C++ implementano i metodi dell’ OOP. La classe è una evoluzione della struct di C. La differenza è che i membri senza specificatore di accesso in una classe sono privati, mentre in una struttura sono pubblici.

  7. Classi ed Oggetti Es: class counter { public: void reset( ); void incr (); void decr ( ); int get( ); private: int val; }; funzioni membro

  8. Classi ed Oggetti In alcuni casi, è importante avere la possibilità di definire dei membri di una classe comuni a tutti gli oggetti della stessa classe. Per fare questo, si usa il modificatore static per dichiarare una variabile statica della classe, ovvero condivisa da tutti gli oggetti della classe. Es: class counter { public: void reset( ); …. private: static int val; };

  9. E’ possibile dichiarare una funzione non membro o una classe come friend di una classe. In questo modo si consente alla funzione o classe friend di accedere ai membri privati delle classe. Es; class counter { public: friend void print(int); ……...}; Classi ed Oggetti

  10. Classi ed Oggetti: l’operatore :: Una volta definiti i prototipi delle funzioni membro, occorre scrivere il codice delle funzioni e far riconoscere al compilatore che la funzione è un metodo di una determinata classe. Per questo si usa l’operatore di risoluzione di ambito:: . Es: void contatore::reset ( ) { val = 0;}; void contatore::incr ( ) { val++;}; void contatore::decr ( ) { val--;}; int contatore::get ( ) { return val;};

  11. Classi ed Oggetti: l’operatore :: Tramite l’operatore di risoluzione di ambito il compilatore riconosce di quale classe la funzione membro è un metodo e distingue tra metodi aventi lo stesso nome ma appartenenti a classi differenti. Quando una funzione membro chiama una funzione che appartiene alla stessa classe, può farlo direttamente senza ricorrere all’operatore di risoluzione di ambito.

  12. Classi ed Oggetti:dichiarazione di oggetti Una volta definita una classe, è possibile istanziare un numero qualsiasi di oggetti appartenenti alla classe. Questi oggetti saranno distinti tra loro, avranno la stessa rappresentazione e potranno usare gli stessi metodi forniti dalla classe. Es: contatore c1, c2; definisce due oggetti c1 e c2 di tipo contatore ognuno dei quali ha la propria copia di val e può eseguire solo le operazioni definite nella classe contatore.

  13. Classi ed Oggetti: accesso ai membri Per usare i membri di un oggetto si usano l’operatore freccia e l’operatore punto con le stesse modalità usate per le struct. Es: c1.reset( ); Questa istruzione ha il significato di invio di messaggio all’oggetto c1 di eseguire l’operazione reset( ) che azzera la variabile privata val. Un oggetto può inoltre accedere al proprio indirizzo tramite un puntatore di nome this

  14. Classi ed Oggetti: Costruttori e Distruttori • Nella maggior parte dei casi occorre inizializzare alcune parti dell’oggetto prima che siano utilizzate. Il C++ consente agli oggetti di inizializzarsi al momento della loro creazione tramite i costruttori. • Un costruttore è una funzioni membro pubblica di una classe che ha le seguenti caratteristiche • ha lo stesso nome della classe di appartenenza • non deve avere un tipo di ritorno (neanche void) • può avere argomenti di default

  15. Classi ed Oggetti: Costruttori e Distruttori Es: class counter { public: counter (int n=0) {val = n; }; void reset( ); void incr (); void decr ( ); int get( ); private: int val; }; Costruttore

  16. Classi ed Oggetti: Costruttori e Distruttori I costruttori sono invocati automaticamente quando gli oggetti vengono istanziati. Es: contatore c1, c2(6); Quando viene eseguita l’istruzione sopra descritta, c1 viene creato con val = 0 (valore di default) mentre c2 viene istanziato con val = 6. Il costruttore viene invocato quando viene allocata memoria all’oggetto: contatore *p; //il costruttore non è eseguito p = new contatore(2) ; //il costruttore è eseguito

  17. Classi ed Oggetti: Costruttori e Distruttori Se un costruttore ammette argomenti non di default, questi devono essere specificati nella dichiarazione dell’oggetto. Es. class counter { public: counter (int n, int p) {val = n; sem = p; }; … private: int val,sem}; counter c1(2,0), c2(6,3), c3(7,4);

  18. Classi ed Oggetti: Costruttori e Distruttori • Il distruttore è complementare al costruttore e viene usato ogni volta che un oggetto viene distrutto, cosa che avviene quando si esce dall’ambito dell’oggetto. • Un distruttore è una funzioni membro pubblica di una classe che ha le seguenti caratteristiche • ha lo stesso nome della classe di appartenenza preceduto dal carattere ~. • non deve avere un tipo di ritorno (neanche void) • non può avere argomenti

  19. Classi ed Oggetti: Costruttori e Distruttori Es: class counter { public: counter (int n=0) {val = n; }; ~counter ( ) {cout << “contatore distrutto\n”; }; void reset( ); void incr (); void decr ( ); int get( ); private: int val; }; Distruttore

  20. Classi ed Oggetti: Costruttori e Distruttori Un esempio della necessità di distruttore si ha quando un oggetto viene rilasciato ma non tutta la memoria occupata da esso viene rilasciata Es: class stringa { char *str; public: stringa (char *str) {str = new char[80]; }; set (char *str); show( ); }; Quando viene rilasciato un oggetto di tipo stringa, l’area di memoria creata con new non è rilasciata e non è più disponibile sull’heap!!!!

  21. Classi ed Oggetti: Costruttori e Distruttori Modificando la classe introducendo un distruttore si ha class stringa { char *str; public: stringa (char *str) {str = new char[80]; }; ~stringa( ) {if (str != NULL) delete[ ] str; } set (char *str); show( ); }; e si risolve il problema, poiché viene rilasciata l’area di memoria heap tramite la delete[ ].

  22. Classi ed Oggetti: Costruttori e Distruttori • Un oggetto può essere raggruppato in array • Es: • contatore cont[4]; • Si può accedere ad un oggetto tramite puntatore. Per un oggetto vale l’aritmetica dei puntatori, l’operatore &, l’operatore di dereferenza, l’operatore punto, l’operatore freccia • I reference a oggetti sono possibili come i reference a variabili • si possono passare degli oggetti a funzioni come qualsiasi altra variabile e le funzioni possono restituire un oggetto

  23. Classi ed Oggetti: Costruttori e Distruttori Vi sono comunque dei problemi: 1) quando un oggetto viene passato ad una funzione ne viene fatta una copia bit a bit che viene data al parametro della funzione. Se l’oggetto contiene un puntatore a una locazione di memoria allocata dinamicamente, allora la copia punterà alla medesima regione di memoria, ed ogni modifica si rifletterà sull’originale. L’oggetto originale ne viene pertanto influenzato.

  24. Classi ed Oggetti: Costruttori e Distruttori Area di memoria per str Oggetto stringa in main() Copia dell’oggetto stringa nel passaggio a funzione

  25. Classi ed Oggetti: Costruttori e Distruttori 2) quando un funzione restituisce un oggetto, il compilatore genera automaticamente un oggetto temporaneo contenente il valore restituito alla funzione. Quando il valore viene restituito alla funzione chiamante, l’oggetto temporaneo va fuori ambito e provoca la chiamata al distruttore, che potrebbe eliminare qualcosa di necessario alla routine chiamante, come della memoria allocata dinamicamente.

  26. Classi ed Oggetti: Costruttori e Distruttori Area di memoria per str Oggettostringa restituito dalla funzione Oggetto temporaneo stringa contenente il valore dell’oggetto stringa restituito dalla funzione e sottoposto all’azione del distruttore

  27. Classi ed Oggetti: Costruttori e Distruttori • La risoluzione a questo tipo di problema è il • costruttore di copia. Con il costruttore di copia, è possibile specificare con precisione cosa accade quando : • un oggetto viene usato per inizializzarne un altro in un’istruzione di dichiarazione • un oggetto viene passato come parametro a una funzione • viene creato un oggetto temporaneo da usare come valore restituito ad una funzione

  28. Classi ed Oggetti: Costruttori e Distruttori La forma più comune per il prototipo del costruttore di copia è la seguente: nome_classe (const nome_classe &); Es: class stringa { char *str; public: stringa(char *, int =40); //costruttore normale stringa(const stringa &,int =40); //costruttore di copia char *getcar( ){ return str;} };

  29. Classi ed Oggetti: Costruttori e Distruttori stringa::stringa(char *inp, int SIZE=40) { int i; str = new char[SIZE]; cout << "sono qui \n"; for(i=0; *(inp+i) != '\0';i++) str[i]=inp[i]; str[i]= '\0'; }; stringa::stringa(const stringa &ob,int SIZE=40) { int i; str = new char[SIZE]; for(i=0;ob.str[i]!='\0';i++) str[i]=ob.str[i]; str[i]='\0'; };

  30. Classi ed Oggetti: Costruttori e Distruttori void display(stringa ob) { for(int i=0;*(ob.getcar()+i) != '\0';i++) cout << *(ob.getcar()+i); cout << "\n"; }; main ( ) { stringa a("PIPPO25"); display(a); //viene invocato il costruttore di copia return 0; }

  31. Classi ed Oggetti: Overload di operatori E’ possibile effettuare l’overload degli operatori del C++ in relazione ai tipi di classe. E’ possibile, per esempio, effettuare un overload dell’operatore + e fargli eseguire delle operazioni definite dal programmatore. Il concetto di overload è pertanto strettamente legato all’overloading delle funzioni. La forma generale di una funzione operatore utilizza la parola chiave operator nel seguente modo tipo nome_classe::operator op(argomenti); dove op è l’operatore di cui si vuole effettuare l’overloading.

  32. Classi ed Oggetti: Overload di operatori Es: class parall { int x,y,z; public: parall operator=(parall); …..}; parall parall::operator=(parall ob) {parall tmp; tmp.x = ob.x; tmp.y= ob.y; tmp z = ob.z; return tmp; }

  33. Classi ed Oggetti: Overload di operatori Es: parall a, b; ….. b=a; //viene usato l’operatore = di parall L’operatore = effettua l’overloading dell’operatore = standard in C++. Anche altri operatori (p.e. &&, ||) standard in C++ possono essere ridefiniti.

  34. Classi ed Oggetti: Composizione La composizione in C++ avviene specificando gli oggetti componenti (oggetti membro) all’interno della classe di cui fanno parte. Occorre comunque indicare gli argomenti del costruttore della classe composta da passare ai costruttori degli oggetti membro Questo avviene tramite gli inizializzatori di membro, che vengono usati nella definizione del costruttore.

  35. Classi ed Oggetti: Composizione Es: class Data: {Data (int, int, int); …}; Impiegato::Impiegato( char *nome, int giorno, int mese, int anno) :datadinascita(int giorno, int mese, int anno) {…}; Se una classe Impiegato ha un oggetto membro datadinascita di classe Data, i parametri giorno, mese e anno saranno passati al costruttore Data

  36. Classi ed Oggetti: Ereditarietà Nella terminologia del C++, la superclasse si chiama classe base, mentre la sottoclasse si chiama classe derivata. Le modalità di derivazione di una classe da una classe base sono specificate tramite lo specificatore di accesso alla classe base e la forma generale per dichiarare che una classe eredita da un’altra è: class classe_derivata: accesso classe base { corpo della classe_derivata} dove accesso può essere private, public e protected

  37. Classi ed Oggetti: Ereditarietà Es: class impiegato { public: Impiegato (char *) ; ~Impiegato( ); void print( ) const; private: char *nome;}; class interinale: public impiegato { public: ….. void print( ) const; private: double orario; double salario; };

  38. Classi ed Oggetti: Ereditarietà • Quando una classe base viene ereditata come pubblica, tutti suoi membri pubblici diventano pubblici per la classe derivata mentre i suoi membri privati sono nascosti alla classe derivata. • Quando una classe base viene ereditata come privata, tutti i suoi membri pubblici diventano membri privati della classe derivata mentre i suoi membri privati sono nascosti alla classe derivata

  39. Classi ed Oggetti: Ereditarietà Ricordiamo che i membri di una classe possono essere private, public e protected. La modalità protected è simile alla private , con una differenza che si riscontra nel caso di classe derivata: quando una classe base viene ereditata come pubblica, tutti suoi membri protected diventano membri protetti per la classe derivata; quando una classe base viene ereditata come privata, tutti suoi membri protected diventano membri privati per la classe derivata In questo modo è possibile dar vita a membri che sono privati per la loro classe ma che sono ereditabili ed accessibili per una classe derivata.

  40. Classi ed Oggetti: Ereditarietà Es: class base { public: void set(int) ; ... protected: int i, j; // privato per base, ma accessibile per derivato }; class derivato: public base { public: … // può accedere a i e j di base private: int k; };

  41. Classi ed Oggetti: Ereditarietà Quando una classe base viene ereditata come protected, tutti suoi membri pubblici e protetti diventano protetti per la classe derivata mentre i suoi membri privati sono nascosti alla classe derivata.

  42. Classi ed Oggetti: Ereditarietà Una classe derivata eredita i membri dalla classe base e pertanto , quando si istanzia un oggetto di classe derivata, il C++ chiama dapprima il costruttore della classe base e successivamente il costruttore della classe derivata. L’esecuzione dei distruttori avviene in ordine inverso: dapprima vengono eseguiti i distruttori della classe derivata e successivamente quelli della classe base.

  43. Classi ed Oggetti: Ereditarietà Nel caso in cui i costruttori della classe base necessitino di parametri, nella dichiarazione dei costruttori delle classi derivate si utilizzano gli inizializzatori di membro : Es: Interinale::Interinale (char *nome): impiegato(nome) { …. }

  44. Classi ed Oggetti: Ereditarietà E’ possibile che una classe erediti le proprietà di più classe basi. In questo caso, si ha la eredità multipla (multiple inheritance). In questo caso la forma generale per dichiarare una classe con multiple inheritance è class classe_derivata: accesso1 classe_base1, accesso2 classe_base2,..accesson classe_basen { corpo della classe_derivata} dove accesso1,..,accesson possono essere private, public e protected

  45. Classi ed Oggetti: Ereditarietà Sono possibili alcune ambiguità nei casi di eredità multipla: class a {public: int i}; class b: public a {public: int j}; class c: public a {public: int k}; class d: public b, public c { int sum}; d ob; ob.i = 5; // istruzione ambigua: quale i ?? A quale i si riferisce? A quella di b o c ?? Si introduce un elemento di ambiguità.

  46. Classi ed Oggetti: Ereditarietà Per risolvere questi tipo di ambiguità , si usano le classi base virtuali. La loro semantica è simile alle classi base non virtuali, con in aggiunta la parola chiave virtual prima delle definizione di accesso. Es: class a {public: int i}; class b: virtual public a {public: int j}; In questo modo, quando due o più oggetti sono derivati da una classe base comune, è possibile evitare che in un oggetto derivato da quegli oggetti siano presenti più copie della classe base.

  47. Classi ed Oggetti: Polimorfismo Il polimorfismo viene implementato tramite le funzioni virtuali. Una funzione virtuale si intende una funzione che viene preceduta dalla parola chiave virtual in una classe base e poi ridefinita in una o più classi derivate.

  48. Classi ed Oggetti: Polimorfismo Es: class a { .. public: virtual void print ( ) {cout << “prima stampa”;} }; class b: public a { .. public: void print ( ) {cout << “seconda stampa”;} };

  49. Classi ed Oggetti: Polimorfismo Ciascuna classe derivata può quindi avere la propria versione di funzione virtuale, pur mantenendo la medesima interfaccia. Quando una classe derivata non ridefinisce una funzione virtuale, la funzione viene impiegata nel modo in cui è definita nella classe base

More Related