Oggetti e Classi (CAP 10) Alberto Garfagnini Università degli studi di Padova 1 Dicembre 2009 Il paradigma OO e le Classi La programmazione ad Oggetti () è una filosofia di programmazione che si basa sui seguenti concetti: 1. astrazione 2. encapsulation e data hiding 3. polimorfismo 4. inheritance 5. riutilizzo del codice la classe incarna in pieno la filosofia OO: permette di tradurre una astrazione in un tipo definito dall utente; incorpora la rappresentazione dei dati e dei metodi per la loro manipolazione (interfaccia con l utilizzatore).
Progettazione di una classe in C++ Supponiamo di disegnare una classe che permette di gestire gli studenti iscritti al corso di Laurea in Fisica. Le operazioni (semplificate) che uno studente può fare sono: iscriversi al primo anno di un corso di laurea; rinnovare la propria iscrizione ad un anno successivo (se il numero di CFU sostenuti lo permettono); PUBLIC INTERFACE sostenere e registrare degli esami; mostrare la propria matricola (ove richiesta); visualizzare il numero di CFU acquisiti. Le informazioni che devono essere memorizzate sono: il numero di matricola; i dati anagrafici (nome e cognome); il numero di CFU sostenuti; l anno di corso al quale è iscritto. INTERNAL DATA Creazione di una Classe Per scrivere una classe è necessario fornire: 1. una dichiarazione della classe che descrive le componenti dei dati in termini dei data members, e realizza l interfaccia pubblica in termini di function members (chiamati anche semplicemente metodi). 2. le definizioni dei metodi della classe che forniscono l implementazione delle funzioni, metodi della classe. Data Hiding Public Interface class classname private: data member declarations public: member function prototypes ;
Class Declaration: Studente // Dichiarazione Classe Studente #include <cstring> class Studente private: int matricola; char nome[30]; char cognome[50]; int anno_corso; int cfu_acquisiti; public: void iscrivi_i_anno(int matricola, const char * cognome, const char * nome); void registra_esame( int cfu ); int get_matricola( ); int get_cfu( ); void stampa_sommario( ); ; Class Members Implementation: Studente (parte 1) // Member Functions per la Classe Studente void Studente::iscrivi_I_anno( int c, const char * cg, const char * nm) std::strncpy( nome, nm, 30 ); nome[29] = \0 ; std::strncpy( cognome, cg, 50 ); cognome[49] = \0 ; matricola = codice; cfu_acquisiti = 0; void Studente::stampa_sommario( ) using namespace std; cout << "cognome: " << cognome; cout << " nome: " << nome << endl; cout << " matricola: " << matricola << endl; cout << " anno di corso: " << anno_corso << endl; cout << " CFU superati: " << cfu_acquisiti << endl;
Class Members Implementation: Studente (parte 2) // Registra un nuovo esame int Studente::registra_esame( int cfu ) if ( cfu < 0 ) return; cfu_acquisiti += cfu; // Ritorna il numero di matricola dello Studente int Studente::get_matricola( ) return matricola; // Ritorna il CFU acquisiti int Studente::get_cfu( ) return cfu_acquisiti; // Esempio di utilizzo della classe Studente Studente iscritto cognome: Rossi nome: Aldo int main( ) matricola: 5432 anno di corso: I using namespace std; CFU superati: 0 Dopo il primo esame - CFU: 12 Studente aldo; aldo.iscrivi_i_anno(5432, "Rossi", "Aldo" ); cout << "Studente iscritto" << endl; aldo.stampa_sommario( ); // Registra Sperimentazioni I aldo.registra_esame( 12 ); cout << "Dopo il primo esame -"; << "CFU: " << aldo.get_cfu( ) << endl; return 0;
I metodi Costruttori Una volta definita la classe è possibile dichiarare degli oggetti Studente aldo; Ma non è possibile inizializzare direttamente i suoi dati, come si farebbe per altri tipi: int year = 2009; // codice valido struct point double x, y; ; point origin = 0, 0; // valido Studente s = 598765, "Rossi", "Mario"; // Errato! Per inizializzare i dati di una classe è necessario invocare un metodo speciale chiamato costruttore. Perchè soltanto all interno di un metodo è possibile accedere alla parte privata della classe. Definiamo un costruttore per la classe Studente // Costruttore per la Classe Studente Studente::Studente( int c, const char * cg, const char * nm) std::strncpy( nome, nm, 30 ); nome[29] = \0 ; std::strncpy( cognome, cg, 50 ); cognome[49] = \0 ; matricola = codice; cfu_acquisiti = 0; // Default Constructor Studente::Studente( ) nome[0] = \0 ; cognome[0] = \0 ; matricola = 0; cfu_acquisiti = 0; Il compilatore crea un Default Constructor vuoto se non è fornito dal programmatore Studente::Studente( )
La Classe Studente rivista // Dichiarazione Classe Studente #include <cstring> class Studente private: int matricola; char nome[30]; char cognome[50]; int anno_corso; int cfu_acquisiti; public: Studente( ); Studente(int matr, const char * cognome, const char * nome); void registra_esame( int cfu ); int get_matricola( ); int get_cfu( ); void stampa_sommario( ); ; Utilizzo dei costruttori della classe Studente In che modo è possibile creare e inizializzare un oggetto: Studente a(23,"rossi","aldo"); Studente a = Studente(544,"Verdi","Carla"); È possibile anche creare un oggetto dinamicamente: Studente *p = new Studente(23,"Rossi","Aldo"); A volte viene invocato il default constructor : Studente f; Il costruttore di default viene sempre invocato per array di oggetti Studente lista[120]; anche se si inizializzano chiamando esplicitamente il costruttore Studente lista[2] = Studente(543,"Rossi","Aldo"), Studente(544,"Verdi","Carla") ;
Il metodo Destructor Una volta che un oggetto viene creato invocando il suo Costruttore, il programma si prende la responsibilità di tenere traccia dell oggetto fino a quando deve essere eliminato. A questo punto viene invocato un metodo chiamato Distruttore che si occupa di liberare tutte le risorse occupate dall oggetto. nella maggior parte dei casi il Distruttore è vuoto ma nel caso in cui si creasse dinamicamente della memoria all interno del Costruttore, questa deve essere liberata nel Distruttore Studente::Studente( int c, const char * cg, const char * nm) int n = strlen( cg ); cognome = new char[ n+1 ]; std::strncpy( cognome, cg, n ); cognome[n] = \0 ;... Studente::~Studente( ) delete [] cognome;... La Classe Studente rivista (2) // Dichiarazione Classe Studente #include <cstring> class Studente private: int matricola; char * nome; char * cognome; int anno_corso; int cfu_acquisiti; public: Studente( ); Studente(int matr, const char * cognome, const char * nome); ~Studente( ); void registra_esame( int cfu ); int get_matricola( ); int get_cfu( ); void stampa_sommario( ); ;
// Esempio di utilizzo della classe Studente Studente iscritto cognome: Rossi nome: Aldo int main( ) matricola: 5432 anno di corso: I using namespace std; CFU superati: 0 Dopo il primo esame - CFU: 12 Studente aldo( 5432, "Rossi", "Aldo" ); cout << "Studente iscritto" << endl; aldo.stampa_sommario( ); // Registra Sperimentazioni I aldo.registra_esame( 12 ); cout << "Dopo il primo esame -"; << "CFU: " << aldo.get_cfu( ) << endl; return 0;