Costruttori Le classi Usare una funzione per inizializzare membri di una classe viene considerato poco elegante. Ci si potrebbe dimenticare di invocare la funzione di inizializzaione o, peggio, chiamarla più volte. Il C++ permette di dichiarare una funzione che abbia l esplicito compito di inizializzare oggetti: il costruttore. Il costruttore si riconosce perchè ha lo stesso nome della classe Se una classe è dotata di costruttore tutti gli oggetti di quel tipo verranno inizializzati. F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 194
studente.h #ifndef STUDENTE_H #define STUDENTE_H #include <string> using std::string; struct studente { studente(string n) {nome=n; anno_dott=0; corsi_seguiti=0; buoni_e_cattivi=true;} studente(string n,int ad) {nome=n; anno_dott=ad; corsi_seguiti=0; buoni_e_cattivi=true;} string nome; int anno_dott; bool buoni_e_cattivi; int corsi_seguiti; void Print_student_name( ); void Set_Name( const string & n) ; void Add_corsi( ) ; }; #endif //STUDENTE_H Costruttore ha lo stesso nome della classe, i.e. del tipo Inizializza i membri e compie azioni necessarie alla corretta creazione in memoria dell oggetto Costruttori non di default, i.e. posso passare parametri con valori F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 195
Costruttori Scrivo un metodo con lo stesso nome della classe, ovvero del tipo base, senza tipo di ritorno Elenco eventuali parametri di input Dopo l operatore funzionale (i.e. ( ) elenco le inizializzazioni dei membri usando la forma funzionale. L elenco è preceduto da : e la lista e separata da, Dopo l elenco di inizalizzazioni creo lo scope del costruttore scrivendo il codice da eseguire quando il costruttore viene invocato (i.e. {}) studente(){name= no name ; anno_dott=0; corsi_seguiti=0; buoni_e_cattivi=true;} studente(string n) {name=n; anno_dott=0; corsi_seguiti=0; buoni_e_cattivi=true;} studente(string n,int ad) {name=n; anno_dott=ad; corsi_seguiti=0; buoni_e_cattivi=true;} F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 196
Costruttori Le classi Se non specifico parametri all atto della creazione dell oggetto verrà invocato il costruttore di default studente nessuno; // Equivalente a:studente nessuno(); Se specifico parametri verrà invocato il costruttore che ha i tipi dei parametri corrispondenti studente cafagna( Francesco Saverio ); // Viene invocato:studente(string ) string nome( Francesco Saverio ); studente cafagna(nome,1); // Viene invocato:studente(string,int); F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 197
Costruttori Le classi Essendo il costruttore una member function, anche se particolare, posso inizializzare i parametri formali all atto della loro dichiarazione: studente(sting n= no lastname, int i=1) : name(n), lanno_dottorato(i){}; studente primo(1); F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 198
studente.h (Evitiamo la proliferazione di costruttori) #ifndef STUDENTE_H #define STUDENTE_H #include <string> using std::string; struct studente { studente(string,int, int, bool ); string nome; int anno_dott; bool buoni_e_cattivi; int corsi_seguiti; void Print_student_name( ); void Set_Name( const string & n) ; void Add_corsi( ) ; }; studente::studente(string n= none,int ad, int corsi=0, bool bc=true) {nome=n; anno_dott=ad; corsi_seguiti=corsi; buoni_e_cattivi=bc;} #endif //STUDENTE_H F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 199
studente.h (Possiamo usare la forma funzionale) #ifndef STUDENTE_H #define STUDENTE_H #include <string> using std::string; struct studente { studente(string n= none,int ad, int corsi=0, bool bc=true) : nome(n), anno_dott(ad), corsi_seguiti(corsi), buoni_e_cattivi(bc){}; string nome; int anno_dott; bool buoni_e_cattivi; int corsi_seguiti; void Print_student_name( ); void Set_Name( const string & n) ; void Add_corsi( ) ; }; #endif //STUDENTE_H F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 200
Distruttori Le classi Spesso così come una classe richiede delle operazioni al momento della inizializzazione, potrebbe richiedere delle azioni all atto della distruzione di un oggetto. Esiste questa posibilità complementare ai costruttori e viene attuata dai: distruttori Anche questi prendono il nome dalla classe ma preceduto dal simbolo di complemento: ~ ~ studente(){ std::cout << Distrutto tutto << std::endl; } F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 201
Copia Gli oggetti di un ogni tipo di classe possono essere copiati: studente a( caf ); studente b=a; La copia copia ogni membro di una classe a meno che un costrutture di copia non sia stato definito: studente::studente(const studente &a) { name=a.name;} Member functions costanti Se una funzione non modifica i membri di una classe può essere definita in modo da essere invocata anche per un oggetto costante: void Print_student_name() const; void Print_my_student(const student &a ) { a.print_student_name();} F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 202
this Le classi this ritorna il puntatore all oggetto la cui member function è stata chiamata Quindi in un member function di una class C, il tipo ritornato da this è: C * In un member function const di una class C, il tipo ritornato da this è: const C * studente * studente::where_in_memory(){ return this;} studente Cafagna( F S,1); std::cout << Locazione di memoria dell oggetto di nome Cafagna << Cafagna.where_in_memory() << endl; F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 203
this Posso usare le member functions come lvalue? Mi basta ritornare solo la reference al tipo di cui fa parte? studente & aggiungi_corsi(int n){ corsi_seguiti+=n; return studente(name,anno_dottorato,corsi_seguiti,buoni_cattivi); } Occorre ritornare l oggetto stesso di cui la funzione è membro: this studente & aggiungi_corsi(int n){ corsi_seguiti+=n; return *this; } studente a( caf,5); a.aggiungi_corsi(2).print(); F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 204
Operatori Se le classi hanno lo stesso supporto dei tipi base, come faccio ad usare le operazioni di base tra classi? Per esempio come posso scrivere? studente a( fra ),b( caf,2); if(a==b) { } Creo lo studente a e b come un tipo base Ma che vuol dire studente a è uguale a studente b? Occorre spiegare come sono fatte le operazioni che coinvolgono oggetti di una classe (o struttura), riscrivendo gli operatori dei tipi base: operator overloading. Per questo possiamo definire helper o member functions che ridefiniscano gli operatori. F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 205
Operatori Posso ridefinire gli operatori: +, -, *, /, =, +=, -=, *=, /=, ++, -- <, >, ==,!=, <=, >=, &&, <<, >>, <<=, >>= %, &, ^,!,, ~, &=, ^=, =, %= [], (),, ->*, -> new, delete, new[], delete[] F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 206
Operatori Per definire un operatore dobbiamo dichiarare una operator function. Questa altro non è che una funzione il cui nome è preceduto dal prefisso: operator. tipo operator sign (lista dei parametri) { /*...*/ } F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 207
Operatori Le classi Per esempio definiamo == per la classe studente: class studente { bool operator == ( const studente & a){ return GetName() == a.getname(); } }; studente a( fra ),b( caf ); if(a==b) { } if(a.operator==(b)){ } Invoco direttamente l operatore! F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 208
Operatori Definiamo == come helper function: class studente { }; bool operator == ( const studente & a, const studente & b){ return a.getname() == b.getname(); } studente a( fra ),b( caf ); if(a==b) { } if(operator==(a,b)){ } Invoco direttamente l operatore! F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 209
Operatori Converrebbe minimizzare il numero di operatore dichiarati in una classe e limitarli a quelli che necessitano di operare sulla rappresentazione: class simple { public: simple(int a=0, int b=0): _a(a), _b(b) {}; ~simple() { std::cout << Ciao ciao << std::endl; } int Get_a(){ return _a;} int Get_b(){ return _b;} void Print() {std::cout << Simple : a << _a <<, b << _b << std::endl; } simple& operator+=(simple not_a) { std::cout << Sono in simple += simple << std::endl; _a+=not_a.get_a(); return *this; } simple& operator+=(int a) { std::cout << Sono in simple += int << std::endl; _a+=a; return *this; } private: int _a,_b; }; F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 210
Operatori Le classi simple operator+(simple a, simple b) { simple temp=a; return temp.operator+=(b); } simple operator+(simple a, int b) { simple temp=a; return temp+=b; } F.S. Cafagna, Linguaggi di programmazione avanzati: C++, XXIII ciclo 211