UNIVERSITA’ DEGLI STUDI ROMA TRE DIPARTIMENTO DI FISICA “E. AMALDI” laboratorio di calcolo II AA 2003/04 terza settimana a cura di Domizia Orestano Dipartimento di Fisica Stanza 159 - tel. (06 5517) 7281 www.fis.uniroma3.it/~orestano [email protected] 1 L’operatore & reference float x = 2.5; float& a = x; float &b = x ; a e b sono chiamati reference e sono due “etichette” equivalenti all’etichetta x, che fanno riferimento allo stesso oggetto. Non confondere reference con puntatore: int i = 3; // oggetto i int &j = i; // reference a i int *p = &i; // puntatore a i i ha un indirizzo in memoria che contiene il valore 3 j ha lo stesso indirizzo p contiene l’indirizzo di i 2 Uso di & reference (I) # include <iostream.h> int main() { int i=5; int *p; int *q; p = &i; q = new int(i); cout << i << " " << *p << " " << *q << " " << &i << " " << p << " " << q << endl; i=8; cout << i << " " << *p << " " << *q << " " << &i << " " << p << " " << q << endl; } return 0; 5 5 5 0xbffffa34 0xbffffa34 0x8049a80 8 8 5 0xbffffa34 0xbffffa34 0x8049a80 3 Uso di & reference (II) # include <iostream.h> int main() { int i=5; int &j=i; int *q; q = new int(i); cout << i << " " << j << " " << *q << " " << &i << " " << &j << " " << q << endl; i=8; cout << i << " " << j << " " << *q << " " << &i << " " << &j << " " << q << endl; } return 0; 5 5 5 0xbffffa34 0xbffffa34 0x8049a80 8 8 5 0xbffffa34 0xbffffa34 0x8049a80 4 Passaggio dei parametri ad una funzione (I) I parametri di una funzione possono essere trasmessi per valore: void swap_value(int i1, int i2); // prototipo di una funzione che riceve due parametri per valore o per reference: void swap_ref(int &i1, int &i2); // prototipo di una funzione che riceve due parametri per reference 5 Passaggio dei parametri ad una funzione (II) Per valore: void swap_value(int i1,int i2) { // quando viene chiamata questa funzione con una // istruzione del tipo // swap(a,b); // tutto va come se il compilatore eseguisse le istruzioni // int i1=a; // int i2=b; int temp = i1; i1 = i2; i2 = temp; } 6 Passaggio dei parametri ad una funzione (III) Per reference: void swap_ref(int &i1,int &i2) { // quando viene chiamata questa funzione con una // istruzione del tipo // swap(a,b); // tutto va come se il compilatore eseguisse le istruzioni // int &i1=a; // int &i2=b; int temp = i1; i1 = i2; i2 = temp; } 7 Passaggio dei parametri ad una funzione (IV) con i puntatori (“alla maniera del C”): void swap_point(int *i1,int *i2) { // quando viene chiamata questa funzione con una // istruzione del tipo // swap(&a,&b); // tutto va come se il compilatore eseguisse le istruzioni // int *i1=&a; // int *i2=&b; int temp = *i1; *i1 = *i2; *i2 = temp; } 8 Passaggio dei parametri ad una funzione (V) int main() { int a = 2; int b = 3; cout << endl; cout << endl << " a = " << a << "; b = " << b << endl ; swap_value(a,b); cout << endl << " a = " << a << "; b = " << b << endl ; swap_ref(a,b); cout << endl << " a = " << a << "; b = " << b << endl ; swap_point(&a,&b); cout << endl << " a = " << a << "; b = " << b << endl ; return 0; } a = 2; b = 3 a = 2; b = 3 a = 3; b = 2 a = 2; b = 3 9 Passaggio dei parametri ad una funzione (VI) Funzioni che hanno come parametro un vettore: void modulo2(double * vect, int dim) { double mod = 0; for(int I=0; I<dim; I++){ mod += vect[I]*vect[I]; // uso vect[I] vect[I] = 0; // modifico vect[I] } return mod; } Un vettore viene identificato mediante il puntatore al suo primo elemento, quindi la funzione riceve sempre un puntatore e potrebbe andare ad alterare il contenuto del vettore... Come si realizza in questo caso il passaggio per valore? Cambiando il prototipo della funzione in: void modulo2(const double * vect, int dim); 10 Stato della simulazione del sistema solare • Abbiamo creato la classe Corpo Celeste • Abbiamo scritto diverse versioni del programma main che instanzia direttamente degli oggetti di questa classe • Prima di proseguire sarà bene soffermarsi a verificare la correttezza del codice prodotto: nel corso dell’esercitazione effetturete un esercizio di “debug” del metodo CorpoCeleste::CalcolaPosizione • Ora torniamo al diagramma UML delle classi previste e effettuiamo la dichiarazione della classe SistemaSolare e la sua implementazione • Infine scriviamo il programma principale, simula.cc 11 relazione di aggregazione 12 La classe SistemaSolare SistemaSolare ????????? pianeti int N SistemaSolare(int n) ~SistemaSolare() int aggiungiPianeta(CorpoCeleste * unPianeta) void evolvi(float T, float dt) int nPianeti() 13 #include "CorpoCeleste.h" #define G 6.673e-11 SistemaSolare.h class SistemaSolare { protected: ?????????? pianeti; int N; // lista dei pianeti // numero dei pianeti public: SistemaSolare(int n); ~SistemaSolare(); int aggiungiPianeta(CorpoCeleste *unPianeta); int nPianeti() {return N;}; void evolvi(float T, float dt); }; 14 15 16 #include "CorpoCeleste.h" #define G 6.673e-11 SistemaSolare.h class SistemaSolare { protected: CorpoCeleste ** pianeti; int N; // lista dei pianeti // numero dei pianeti public: SistemaSolare(int n); ~SistemaSolare(); int aggiungiPianeta(CorpoCeleste *unPianeta); int nPianeti() {return N;}; void evolvi(float T, float dt); }; 17 #include #include #include #include "SistemaSolare.h" <stdlib.h> <math.h> <iostream.h> SistemaSolare.cc Prima parte SistemaSolare::SistemaSolare(int n) { pianeti = new CorpoCeleste*[n]; // si alloca un vettore di puntatori a oggetti di tipo // CorpoCeleste: n puntatori a CorpoCeleste N = 0; // si pone il numero iniziale di pianeti pari a 0 } SistemaSolare::~SistemaSolare() { delete [] pianeti; } int SistemaSolare::aggiungiPianeta(CorpoCeleste *unPianeta) { pianeti[N++] = unPianeta; // si aggiunge unPianeta //alla lista dei pianeti e si incrementa N di uno. return N; } 18 void SistemaSolare::evolvi(float T, float dt) { float t = 0 ; //tempo dall’inizio della simulazione // ripeti fino a che t<=T while (t <= T) { // loop sui pianeti for (int i=0; i<N; i++) { SistemaSolare.cc Seconda parte double fx = 0.; double fy = 0.; // calcola la forza esercitata sul pianeta // i-esimo da parte di tutti gli altri // pianeti j-esimi for (int j=0; j<N; j++) { // calcola la distanza tra i e j double d = sqrt( (pianeti[i]->X()-pianeti[j]->X())* (pianeti[i]->X()-pianeti[j]->X())+ (pianeti[i]->Y()-pianeti[j]->Y())* (pianeti[i]->Y()-pianeti[j]->Y()) ); 19 if (d!=0) { //Somma a fx e fy agenti sull i-esimo corpo //la forza dovuta al corpo j-esimo fx += -G*pianeti[i]->M()*pianeti[j]->M()* ( pianeti[i]->X() – pianeti[j]->X() ) / (d*d*d) ; fy += -G*pianeti[i]->M()*pianeti[j]->M()* ( pianeti[i]->Y() – pianeti[j]->Y()) / (d*d*d) ; } // termina l’if su d!=0 } // termina il loop sul j-esimo pianeta SistemaSolare.cc // ora conosco la forza che agisce sulTerza parte // l’i-esimo pianeta e posso invocare // calcolaPosizione sull’i-esimo pianeta pianeti[i]->calcolaPosizione((float)fx, (float)fy, dt); pianeti[i]->stampaPosizione(); } // termina il loop sull’iesimo pianeta cout << endl; t += dt; // viene incrementato il tempo } // while ripeti fino a che t<=T } // l’implementazione del metodo evolvi e’ conclusa 20 Interaction Diagram (semplificato) 21 #include “SistemaSolare.h” simula.cc int main() { //NB si usano unita’ MKS // instanzio un oggetto SistemaSolare ss con 2 corpi SistemaSolare ss(2); // instanzio due oggetti CoproCeleste, sole e terra CorpoCeleste sole(“Il Sole”, 1.98e30, 0., 0., 0., 0.); CorpoCeleste terra(“La Terra”, 5.98e24, 1.52e11, 0., 0., 29476.35); // li aggiungo al Sistemasolare ss ss.aggiungiPianeta(&sole); ss.aggiungiPianeta(&terra); // faccio evolvere il sistema per 1 anno in passi di un giorno ss.evolvi(86400*365, 86400); return 0; } 22