Rappresentazione in C++ di tipi di dato: le classi tipo di dato = insieme di valori + insieme di operatori esempio: il tipo di dato data : ins. di valori da rappresentare: 13 Maggio 1975, 23/12/01, 7-5-2002, fi scelta di una rappresentazione fl triple di numeri interi gg mm aaaa fl insieme di valori del tipo di dato data : D = { [gg mm aaaa] 1 gg 31, 1 mm 12 1 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
quali operatori ( primitivi ) da applicare a un elemento x Œ D? scelta plausibile (e minimale ): un operatore per conoscere il valore di x un operatore per modificare il valore di x rappresentazione C++ (usando gli strumenti che conosciamo): struct data {int giorno, mese, anno;; void mostradata(data); void modificadata(data&, int, int, int); definizione delle operazioni: void mostradata(data x) {cout<<x.giorno<<'/'<<x.mese<<'/'<<x.anno<<endl; void modificadata(data& x, int g, int m, int a) {if (g<1 g>31 m<1 m>12) cout<<"valori scorretti per il tipo data\n"; else { x.giorno=g; x.mese=m; x.anno=a; 2 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
esempio: #include <iostream> #include "data.h" Æ file che contiene le definizioni C++ del tipo di dato 'data' {data data1, data2; modificadata(data1, 3, 5, 2002); mostradata(data1); modificadata(data2, 27, 31, 2002); modificadata(data2, 27, 1, 2002); mostradata(data2); uscita prodotta: 3/5/2002 valori scorretti per il tipo data 27/1/2002 3 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
Problema: come si fa a garantire che le modifiche ad elementi del tipo di dato data siano vincolate ad essere fatte solo tramite la funzione da noi definita modificadata()? #include <iostream> #include "data.h" {data data1, data2; modificadata(data1, 3, 5, 2002); mostradata(data1); modificadata(data2, 27, 1, 2002); data2.mese = 31; mostradata(data2); uscita prodotta: 3/5/2002 27/31/2002 fi data non valida!! usando gli strumenti che conosciamo non c è modo di introdurre questo vincolo fl possibili problemi di inconsistenza, difficoltà nel riuso, 4 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
classi C++: meccanismo per: legare insieme valori e operatori obbligare a usare gli operatori per accedere/modificare i valori sintassi ( usuale ): generalizzazione della sintassi di struct denominazione di tipo (si può usare per dichiarare variabili, funzioni, di quel tipo) class nomeclasse { public: dichiarazione funzioni membro dichiarazione costruttori private: dichiarazione dati [dichiarazione funzioni ausiliarie] ; funzioni (Æ operatori!) e dati sono legati insieme solo i nomi definiti nella parte public sono visibili (Æ utilizzabili!) fuori dalla definizione della classe 5 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
esempio: class data {public: void mostradata() {cout<<giorno<<'/'<<mese<<'/'<<anno<<endl; operatori void modificadata(int g,int m, int a) {if (g<1 g>31 m<1 m>12) cout<<"valori scorretti per data\n"; else { giorno=g; mese=m; anno=a; data() { giorno=1; mese=1; anno=0; private: int giorno, mese, anno; ; costruttore (deve avere nome identico a quello della classe) rappresentazione del tipo (qui, una tripla di interi) nota: si possono definire più costruttori, differenziati tra loro dal numero e/o tipo dei parametri 6 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
dichiarazione di variabili di tipo classe: nomeclasse nomevar; provoca la creazione di una variabile nomevar di tipo nomeclasse ( istanza della classe) con i suoi campi inizializzati in accordo al costruttore specificato nella definizione della classe 1 giorno data d1; fi d1 : 1 mese 0 anno uso di variabili di tipo classe: tramite le funzioni definite nella parte public, usando la notazione: nomevar.nomefun(parametri) applica la funzione nomefun() definita nella parte public della classe alla variabile della stessa classe di nome nomevar data d1; d1.modificadata(3,7,2001); 7 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
funzioni definite nella classe vedono tutti i nomi definiti nella stessa classe void modificadata(int g,int m, int a) {if (g<1 g>31 m<1 m>12) cout<<"valori scorretti per data\n"; else { giorno=g; mese=m; anno=a; fl d1.modificadata(3,7,2001); assegna i valori: 3 7 2001 ai campi: d1.giorno d1.mese d1.anno fuori dalla classe i nomi privati sono inaccessibili!! 8 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
esempio: #include <iostream> #include "data.h" Æ file che contiene la definizione C++ di class data {data data1, data2; data1.modificadata(3, 5, 2002); data1.mostradata(); data2.modificadata(27, 31, 2002); data2.modificadata(27, 1, 2002); data2.mostradata(); uscita prodotta: 3/5/2002 valori scorretti per data 27/1/2002 ================================== #include <iostream> #include "data.h" {data data1, data2; data1.modificadata(3, 5, 2002); data1.mostradata(); data2.modificadata(27, 1, 2002); data2.mese = 31; Æ il compilatore segnala errore data2.mostradata(); messaggio del compilatore g++ (sotto Linux): In function 'int ': 8: member 'mese' is a private member of class 'data' 9 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
accorgimenti per migliorare la leggibilità di una definizione di classe: - inserire nella classe solo la dichiarazione delle funzioni - spostare fuori dalla classe la definizione delle funzioni fl separare la definizione dai dettagli realizzativi class data {public: void mostradata(); void modificadata(int g,int m, int a); data(); private: int giorno, mese, anno; ; void data::mostradata() {cout<<giorno<<'/'<<mese<<'/'<<anno<<endl; void data::modificadata(int g,int m, int a) {if (g<1 g>31 m<1 m>12) cout<<"valori scorretti per data\n"; else { giorno=g; mese=m; anno=a; data::data() { giorno=1; mese=1; anno=0; associa la definizione della funzione alla classe data 10 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
Altro esempio: rappresentazione del tipo di dato tempo (ore e minuti) (nota: versione semplificata del tipo di dato Time (libreria ccc_time.h)) valori da rappresentare: 12:53, 1:07am, 23:12, 15:10, 9.24pm, fl scelta della rappresentazione: l insieme dei valori da rappresentare è T = { o m o Œ N, m Œ N, 0 o 23, 0 m 59 operatori ( primitivi ) da applicare a un elemento t Œ T scelta plausibile : un operatore per conoscere il valore di t.o un operatore per conoscere il valore di t.m un operatore per sommare a t una certa quantità di minuti un operatore per calcolare la distanza (in minuti) tra t e un altro valore t' Œ T 11 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
rappresentazione C++ : #include <cmath> class tempo {public: tempo(int o,int m); costruttore con param. int dammiore(); int dammimin(); void sommamin(int m); int minutida(tempo t); private: int ore, minuti; ; tempo::tempo(int o,int m) { ore=o; minuti=m; int tempo::dammiore() {return ore ; int tempo::dammimin() {return minuti ; void tempo::sommamin(int m) { esercizio int tempo:: minutida(tempo t) {int m; m = 60*static_cast<int>(fabs(ore-t.ore)) + static_cast<int>(fabs(minuti-t.minuti)); return m; 12 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
#include <iostream> #include "tempo.h" {tempo t1; int min; min=t1.dammimin(); cout<<min<<endl; file che contiene la definizione C++ di class tempo messaggio di errore del compilatore g++ sotto Linux: p.cc: In function 'int ': p.cc:4: no matching function for call to 'tempo::tempo ()' per correggere questo errore potremmo definire un costruttore aggiuntivo senza parametri:... class tempo {public: tempo(); costruttore senza parametri tempo(int o,int m); costruttore con param.... private: int ore, minuti; ; tempo::tempo() { ore=0; minuti=0; inizializzazione di default tempo::tempo(int o,int m) { ore=o; minuti=m; inizializzazione parametrica... 13 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
#include <iostream> #include "tempo.h" {tempo t1(10,47); int min; t1.minuti=t1.minuti+3; min=t1.dammimin(); cout<<min<<endl; messaggio di errore del compilatore g++ sotto Linux: p.cc: In function 'int ': p.cc:6: member 'minuti' is a private member of class 'tempo' p.cc:6: member 'minuti' is a private member of class 'tempo' versione corretta: #include <iostream.h> #include "tempo.h" {tempo t1(10,47); int min; t1.sommamin(3); min=t1.dammimin(); cout<<min<<endl; risultato prodotto: 50 14 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
#include <iostream> #include "tempo.h" {tempo t1(10,23),t2(8,10); int min; min=minutida(t2); cout<<min<<endl; messaggio di errore del compilatore g++ sotto Linux: p.cc: In function 'int ': p.cc:7: warning: implicit declaration of function 'int minutida(...)' /tmp/cc7jbdwh.o: In function 'main': /tmp/cc7jbdwh.o(.text+0xeb): undefined reference to 'minutida' collect2: ld returned 1 exit status versione corretta: #include <iostream> #include "tempo.h" {tempo t1(10,23),t2(8,10); int min; min=t1.minutida(t2); cout<<min<<endl; risultato prodotto: 133 15 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
calcolare la distanza in secondi tra due variabili t1 e t2 di tipo tempo nota: non esiste una operazione primitiva per fare questo fl realizzare l operazione a partire dalle operazioni primitive int secondifra(tempo t1, tempo t2) {return 60*t1.minutiDa(t2) ; tempo t1(9,54),t2(18,23); int min, sec; min = t1.minutida(t2); cout<<min<<endl; sec = secondifra(t1, t2); cout<<sec<<endl; risultato prodotto: 571 34260 16 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi
esercizio: un appuntamento è costituito da una data, un orario, un luogo usando la classe tempo per rappresentare la componente orario di un appuntamento, realizzare in C++ la soluzione del seguente problema: dati: un insieme di N appuntamenti, una data d, un orario o, e un valore m, spostare in avanti di m minuti tutti gli appuntamenti con data = d, e orario o 17 L.classi Fondamenti di Informatica 1 - Vincenzo Grassi