c. genta analisi dati a.a. 2009/10 - gruppo1-2 infn...
TRANSCRIPT
C++
C. GentaAnalisi Dati
a.a. 2009/10
C. Genta – Analisi dati 2
Perché il C++?
E’ necessario utilizzare dei calcolatori per analizzare i dati raccolti agli esperimenti di fisica delle particelleEsistono dei programmi sviluppati da altri che ci aiutano in questoIl più importante in fisica delle particelle è ROOT– http://root.cern.ch
ROOT è la versione in C++ di un precedente programma che si chiamava PAW ed era scritto in Fortran
C. Genta – Analisi dati 3
Cosa faremo?
Cercherò di darvi il minimo di basi necessarie perché possiate usare ROOTOltre alle slide del corso in rete potete trovare molti tutorial e libri:
Manuale:“Thinking C++” di B. Eckel: http://hep.fi.infn.it/TIC2Vone.pdf http://hep.fi.infn.it/TIC2Vtwo.pdf
Tutorial:http://www.cplusplus.com/
C. Genta – Analisi dati 4
Primi elementi di C++
La funzione main è una funzione speciale, la prima da cui parte l’esecuzione del codiceOgni linea di comando deve finire con ;– Gli spazi non contano e si puo’ andare a capo in una
linea di comando
// indica una linea di commentoTutta la regione inclusa tra /* e */ è commentata
int main() {
// questo e’ un commento
return 0;
}
C. Genta – Analisi dati 5
Variabili e funzioni predefinite
Esistono dei “tipi” di variabile predefiniti– Un numero intero (int)– Un numero reale (float)– Un carattere (char)– Una variabile logica vera o falsa (bool)– Una variabile “senza tipo” (void)
Il C/C++ è dichiarativo: ogni variabile che deve essere utilizzata deve essere dichiarata prima (cioè dobbiamo specificare se è intera o cosa altro)– Attenzione! minuscolo è diverso da maiuscolo
Non esistono funzioni predefinite o intrinseche– Si possono tuttavia “caricare” delle funzioni definite tramite gli
“header” file
C. Genta – Analisi dati 6
Scrivere qualcosa in output
int a=7;std::cout << “Hello world! a=” << a <<std::endl;
Esiste anche std::cerr per mandare l'ouput nello stderr.
std::cout = output,di solito lo schermo
operatore << immaginatelo come una freccia:
Hello world! va a finire sull’output
Stampa il valore di a
Sullo schermo: Hello world! a = 7
std::endl dice di andare a capo
C. Genta – Analisi dati 7
Input
Per leggere un input da tastiera– int a;– std::cin >> a;
Anche l'operatore >> può essere concatenato per leggere più variabili di input separate da caratteri di spazio, Tab, o a capo :
std::cin>>x>>y;
std::cin = input,la tastiera
Metti (freccia) quello che hai letto da tastiera nella variabile a
C. Genta – Analisi dati 8
Esempio: InputOutput.cpp
#include <iostream>
int main() {
bool b=true;
char c='a';
int i=1;
float f;
std::cin >> f;
std::cout << b << " " << c << " " <<
i << " " << f << std::endl;
return 0;
}
Carica le funzioni di I/O
C. Genta – Analisi dati 9
Compilare ed eseguire un programma
Il comando per compilare è– g++
esempio:> g++ InputOutput.cpp> ./a.out
oppure> g++ -o InputOutput InputOutput.cpp> ./InputOutput
C. Genta – Analisi dati 10
Namespace
Perche’ devo scrivere sempre std:: davanti a cin e cout ?In C++ i vari oggetti sono suddivisi in compartimenti (namespace)– Posso avere una variabile a definita in un
compartimento, e questa sarà diversa dalla variabile a definita in un’altro
– int pippo::a;– int pluto::a;
C. Genta – Analisi dati 11
In C++
cin e cout sono definite nel namespace std, per cui devono essere chiamati come std::cin e std::cout;Oppure: posso dire una volta per tutte al compilatore che anche se non specifico nulla, assuma che io voglio lavorare in un namespace definitousing namespace std;
Sembra una complicazione inutile ma se per caso decidete di fare un vostro cout e cin privato potete definirli in un altro namespace e passare da uno all'altro semplicemente cambiando:using namespace mionamespace;
C. Genta – Analisi dati 12
Funzioni
Abbiamo già visto la funzione main()Quando si definisce una funzione devo dichiarare il tipo di oggetto che restituiscePuò essere float, int, ecc... ma anche nulla, cioè void Tra parentesi tonda si indicano gli argomenti– con il loro tipo
Tra parentesi graffe si implementa la funzioneIl risultato di una funzione non void viene restituito con – return qualcosa;
C. Genta – Analisi dati 13
Esempio: swap.cpp
Immaginiamo una funzione che deve scambiare due interi
Facile, no?
void swap(int i1, int i2) { // Swap arguments int temp = i1; i1 = i2; i2 = temp;}
C. Genta – Analisi dati 14
Argomenti per valore
Peccato che non funzioni...La funzione scambia effettivamente il valore di i1 e i2, ma non quello delle variabili che sono state passate come argomento, cioe’ c e d nell’esempio qui sotto
In altre parole in questo modo si passa il valore della variabile come argomento e non la variabile
int c=3;int d=4;swap(c, d);
C. Genta – Analisi dati 15
PuntatoriCome in C anche in C++ esistono i puntatori:
int* a;significa che a contiene l’indirizzo di memoria di inizio una variabile intera– una variabile intera e’ costituita da 4 bytes
Un puntatore si può assegnare usando l’operatore &
int b=8;int *i;i = &b;
nota : un puntatore può essere 0 nel qual caso si dice che e’ un puntatore “nullo”. Se si cerca di accedere al valore di un puntatore nullo si ha un crash. Esempio:
int *p=0;int b=*p; // questa riga fa crashare il programma
C. Genta – Analisi dati 16
Puntatori
Anteponendo una * al puntatore si ottiene la variabile alla quale “punta”– puo’ essere utilizzato anche per assegnare un valore– se il puntatore e’ nullo l’operazione di dereferenziazione puo’
generare un errore
Quanto valgono a,b,*i? E &a, &b, i quanto valgono?Provate a scriverli con cout...E adesso provate a modificare la funzione swap()
int b=8;int *i = &b;int a = *i; *i = 9;
C. Genta – Analisi dati 17
Nulla di nuovo rispetto a C?
In realtà in C++ esiste una alternativa al passare il puntatore ad una variabile: usare una reference. La reference è un alias della variabile. Cambiare il valore della reference equivale a cambiare la varibile di cui è l'alias
Quanto valgono a,b,c? E &a, &b, &c quanto valgono?Vi viene in mente un altro modo di modificare swap()?
int b=8;
int& c=b;
int a = c;
c = 9;
C. Genta – Analisi dati 18
Reference vs puntatore
Una reference deve essere sempre inizializzata.A differenza dei puntatori, una volta che una reference a una variabile è creata non può essere cambiata per diventare reference di un'altra variabile.In linea di principio è più sicura di un puntatore perché non può mai essere nulla dovendo essere sempre associata a un oggetto.
C. Genta – Analisi dati 19
Reference
Posso utilizzare delle reference negli argomenti di swap()
Perchè funziona? Qual’è il vantaggio?
void swap(int& i1, int& i2) { // Swap arguments int temp = i1; i1 = i2; i2 = temp;}
C. Genta – Analisi dati 20
Vettori
Un vettore di 5 reali si definisce nel seguente modo:float x[5];
Che significa esattamente? Se facciamo un dump della memoria troviamo:
*x e x[0] sono la stessa cosax e &x[0] sono la stessa cosaNota: ma x indica un vettore e non un puntatore!
C. Genta – Analisi dati 21
ArrayAndPointer.cpp
Consideriamo:
y e z sono puntatori a x[0]y+1 e’ un puntatore a x[1] y[1] e’ una abbreviazione per *(y+1)Le operazioni di addizione e sottrazione di interi sono permesse sui puntatori
float x[5]={0., 1.1, 2.2, 3.3, 4.4};float *y = &x[0];float *z = x;
cout << "*y = " << *y << “, *z = " << *z << endl;cout << "*(y+1) = " << *(y+1) << “, y[1] = " << y[1] << endl;
C. Genta – Analisi dati 22
Allocazione dinamica della memoria
E’ possibile definire la dimensione di un vettore durante l’esecuzione
E’ anche possibile creare un oggetto in memoria in modo tale che non sia cancellato quando la funzione termina (usa la memoria heap anziché lo stack della funzione)
int n;cin >> n; float x[n];
int n;cin >> n; float* x = new float[n] ;
C. Genta – Analisi dati 23
deleteL’unico problema è che bisogna ricordarsi di cancellarlo quando non ne abbiamo più bisogno
Funziona anche per variabili semplici, non soltanto vettori
NOTA: Un volta cancellato, bisogna ricordarsi di non usare più il puntatore altrimenti il programma può avere un comportamento imprevedibile.
float* x = new float[5];
...
delete [ ] x;
float* x = new float;
...
delete x;
float* x = new float;
delete x;
std::cout<<”Puntatore a x= ”<<x<<std::endl;
std::cout<<”Valore di x= “<<*x<<std::endl;
Stampa il puntatore di x (diverso da 0!)
Tenta di accedere a x che e' stato cancellato →
C. Genta – Analisi dati 24
Scope
Lo scope di una variabile è la regione del programma in cui la variabile può essere usataSe una parte di codice è delimitata da {} allora queste delimitano lo scope delle variabili dichiarate al loro interno comprese le parentesi usate per loop, if ..:
Le variabili dichiarate fuori dalle funzioni incluso main possono essere usate in qualsiasi punto del programma (global scope)
int x = 5;for (int i=0; i<n; i++){int y = i + 3;x = x + y;}cout << "x = " << x << endl; // OKcout << "y = " << y << endl; //non compila: y out of scopecout << "i = " << i << endl; //non compila: i out of scope
C. Genta – Analisi dati 25
if e if ... else
if ( a == b ) c = 2;
if ( a == b ) { c=2;}
if ( a == b ) { c=2;}else{ c=1;}
C. Genta – Analisi dati 26
operatori
Per vostra referenza
C. Genta – Analisi dati 27
Cicli condizionali
int i;for (i=0; i<10; i++) { cout<<i<<endl;}
int i=0;while (i<10) { cout<<i<<endl;
i++;}
Esercizio: creare una funzione che restituisce la somma degli elementi di un vettore
C. Genta – Analisi dati 28
Programmazione a oggetti
Fin qui la parte noiosa...Sostanzialmente abbiamo descritto la sintassi del C++, ma senza introdurre nessun elemento di programmazione a oggettiChe significa programmare a oggetti?
C. Genta – Analisi dati 29
Come si affronta un problema complesso ?
Generalmente la soluzione di un problema complesso con metodi IT avviene in 3 fasi:
• ASTRAZIONEASTRAZIONE
• DECOMPOSIZIONEDECOMPOSIZIONE
• ORGANIZZAZIONEORGANIZZAZIONE
I diversi paradigmiparadigmi disponibili nella programmazione (procedurale, object-oriented) affrontano le 3 fasi in maniera molto diversa
C. Genta – Analisi dati 30
Procedurale
Il paradigma proceduraleprocedurale affronta un problema in termini di funzioni che agiscono su dei dati:
1.1. ASTRAZIONEASTRAZIONE– formalizzazione del problema in termini di un processoprocesso che
lo risolve
1.1. DECOMPOSIZIONEDECOMPOSIZIONE– dividere la procedura di soluzione in unità più piccole,
facilmente maneggiabili (funzionifunzioni)
1.1. ORGANIZZAZIONEORGANIZZAZIONE– preparare le funzioni in maniera che si chiamino tra loro
C. Genta – Analisi dati 31
Procedurale
PRIMAPRIMA– definire l’insieme di strutture dati
QUINDIQUINDI– definire le funzionifunzioni che agiscono sulle
strutture dati
C. Genta – Analisi dati 32
Object-Oriented
Il paradigma object-orientedobject-oriented affronta un problema in termini di oggetti che interagiscono:
1.1. ASTRAZIONEASTRAZIONE– formalizzazione del problema in termini di agenti
indipendenti (oggettioggetti) che lavorano tra loro
1.1. DECOMPOSIZIONEDECOMPOSIZIONE– definire i tipi degli oggetti su cui suddividere il compito
complessivo
1.1. ORGANIZZAZIONEORGANIZZAZIONE– creare il numero appropriato di oggetti di ogni tipo
C. Genta – Analisi dati 33
Object-Oriented
PRIMAPRIMA– definire il comportamento e le proprietà
dei vari tipi di oggettioggetti definiti
QUINDIQUINDI– creare gli oggetti e metterli al lavoro tra
loro
C. Genta – Analisi dati 34
Procedurale vs Object-OrientedL’utilizzo di linguaggi procedurali comporta vari problemi:
•Evoluzione incontrollata del codice
•Dipendenza del codice dalle strutture datiI linguaggi Object-Oriented Object-Oriented nascono con l’intento di
superare queste limitazioni e rendere più semplice la manutenzione del software. In particolare:
•Riduzione della dipendenza del codice di alto livello da quello di basso livello
•Riutilizzo del codice di alto livello
•Dettagli delle implementazioni nascosti
•Supporto di tipi di dati astratti
C. Genta – Analisi dati 35
Le classi
Una classe è un insieme di oggetti che condividono le stesse proprietà e gli stessi comportamenti La classe è intuitivamente il tipotipo degli oggetti
Nella classe vengono definiti variabili e metodi
Un oggetto che segue la definizione di una classe si chiama istanzaistanza della classe
C. Genta – Analisi dati 36
Un esempio di classe
Vediamo come si dichiara e definisce una classe in C++C++
Come linea generale:Dichiarazione in un headerheader file (estensione .h.h)Implementazione dei metodi in un file di librerialibreria (estensione .cc.cc)
Proviamo a costruire la classe “punto del piano cartesiano”
C. Genta – Analisi dati 37
Punto.hclass Punto{ public: Punto(double x0, double y0); double GetX(); double GetY();
private: double x; double y;};
Variabili per immagazzinare le coordinate del punto.private significa che non sono accessibili all'utente.
Per accedere alle varie informazioni della classe si utilizzano i metodi
In questo esempio i due metodi GetX() e GetY() permettono di accedere all'informazione contenuta nella classe.(i due metodi qui sono dichiarati ma non implementati. L'implementazione e' nel .cc)
Costruttore dell'oggetto punto nel piano
C. Genta – Analisi dati 38
Punto.hclass Punto{ public: Punto(double x0, double y0); double GetX(); double GetY();
double GetRho(); double GetPhi();
void SetX(double x0); void SetY(double y0);
private: double x; double y;};
L'utente potrebbe volere il punto in coordinate polari oppure settare nuovi valori per le coordinate...
Per accedere ai vari metodi di una classe si usa la stessa sintassi valida per accedere alle variabili di una struttura in C, ovvero “.” e “>” I metodi vengono usati come se fossero funzioni.Es:
#include “punto.h”int main(){ Punto p(2.1,2.2); p.SetX(1.1); cout<<”Rho= ”<<p.GetRho() <<”Phi= ”<<p.GetPhi()<<endl;}
C. Genta – Analisi dati 39
Punto.cc#include ”punto.h”
Punto::Punto(double x0, double y0){ x=x0; y=y0;}
double Punto::GetX(){ return x;}
void Punto::SetX(double x0){ x=x0;}double Punto::GetRho(){ return sqrt(x*x+y*y);}
scrivendo Punto:: informiamo il compilatore di quale classe stiamo parlando
class Punto{ public: .... private: double rho; double phi;};
Se nella classe decido diimmagazzinare le coordinate polari invece che le cartesiane:
Devo cambiare di conseguenza Punto .ccMa cosa deve cambiare l'utente nel programma main()?
C. Genta – Analisi dati 40
Punto
class Punto{ public: Punto(double x, double y); double GetX(); double GetY();
double GetRho(); double GetPhi();
void SetX(double x0); void SetY(double y0);
private: double rho; double phi;};
#include “punto.h”int main(){ Punto p(2,2); p.SetX(1); cout<<”Rho= ”<<p.GetRho() <<”Phi= ”<<p.GetPhi()<<endl;}
Assolutamente niente!L'interfaccia della classe è rimasta la stessa, sono cambiate solo le variabili interne.L'utente non si accorge di niente.
interfaccia
C. Genta – Analisi dati 41
Interazione tra oggetti
Inte
rfac
cia
PublicPrivate
MetodiDati
Metodi privati
Oggetto (es. Classe Punto)
Può cambiare senzache gli altri oggetti ne risentano
Altri oggetti
Classerettangolo
Classecerchio
Classevettore
C. Genta – Analisi dati 42
Esempio#include “punto.h”int main(){ //creazione oggetto Punto punto(1,2); // puntatore a un oggetto Punto *p = & punto; // chiamata di metodi p>SetX(0); // vettore di oggetti: Punto punti[100]; punti[0].SetX(0); punti[0].SetY(0);} i metodi dell’oggeto si chiamano con il punto
con il puntatore si usa >
•g++ -c Punto.cc
crea il file di libreria Punto.o
•g++ Esempio.cpp Punto.o –o Esempio
crea l’eseguibile Esempio
Che cosa succede se scriviamo Punto p;?
C. Genta – Analisi dati 43
CostruttoriDichiarazione:class Punto{ public: Punto(double x,double y); Punto(); Punto(const Punto &); ~Punto(){} //distruttore};Il costruttore ha lo stesso nome della classe e viene chiamato automaticamente quando un oggetto della classe è creato.Può essere utilizzato per inizializzare l'oggetto.Si possono dichiarare piu' costruttori.
Implementazione:Punto::Punto(double x0, double y0){ x=x0; y=y0;}
Punto::Punto(){ x=0.; y=0.;}Punto::Punto(const Punto&p){ x=p.GetX(); y=p.GetY();}
Costruttoredefault
Se non se ne dichiara nessuno, il compilatore crea un costruttore di default che chiama i costruttori di default delle variabili della classe.Il costruttore di copia e il distruttore se non dichiarati vengono creati automaticamente dal compilatore.
Costruttoredi copia
C. Genta – Analisi dati 44
Esempi#include “punto.h”int main(){ //creazione oggetto Punto punto(1,2);
//costruttore di copia Punto copia=punto;
//costruttore di default Punto p0;
// costruttore Punto *p = new Punto(2,3);
// distruttore delete p; }
C. Genta – Analisi dati 45
Esempio: un vettore
Avremo bisogno di vettori 3Dvettori 3D per molti scopi:identificare una posizione in un sistema di riferimento (cartesiano, cilindrico, sferico)memorizzare l’impulso di una particella…
Una struttura di questo tipo può essere utilizzata molte volte in un grande progetto software.
C. Genta – Analisi dati 46
Vettore.h
Questo è l’headerheader file per un vettore 3D in coordinate cartesiane
C. Genta – Analisi dati 47
Vettore.cc
Questa è l’implementazione dei metodi
C. Genta – Analisi dati 48
Somma di vettori
Possiamo definire una funzione somma()
C. Genta – Analisi dati 49
Overloading di operatori
Il C++C++ ci mette a disposizione degli strumenti più eleganti e funzionali per ottenere lo stesso scopo: la possibilità di fare l’overloadingoverloading degli operatori
C. Genta – Analisi dati 50
Overloading degli operatori I/O
ostream& operator <<(ostream& os, const Vettore v) { os << "(" << v.x() << "," << v.y() << "," << v.z() << ")"; return os;}
Allo stesso modo si può fare l’overloading dell’operatore <<
Utile per non dover ogni volta scrivere ogni componente...
C. Genta – Analisi dati 51
Un passo in più: gli array
La classe Vettore ci permette di fare molte cose, ma naturalmente non ci accontentiamo: vorremmo una classe che ci permetta di decidere la lunghezza del vettore a run-time, in modo da essere più flessible
In particolare vorremmo le seguenti caratteristiche:
• dimensionamento a run-time
• accesso all’iesimo elemento
• utilizzo automatico della memoria, senza bisogno di scrivere esplicitamente nel codice new o delete
C. Genta – Analisi dati 52
FloatArray.h
~FloatArray();
C. Genta – Analisi dati 53
FloatArray.cc
C. Genta – Analisi dati 54
Non siamo ancora soddisfatti…
… perché essere obbligati ad usare i float ?Possiamo superare il problema usando una classe templatetemplate(bisogna mettere tutto nel .h questa volta...)
#endif
C. Genta – Analisi dati 55
I template all’opera
La classe ArrayArray è molto flessibile: nessuno ci impedisce di definire array non solo di tipi come float, ma anche di qualunque altra classe (Point per esempio)
C. Genta – Analisi dati 56
Ereditarietà
La nostra classe ArrayArray inizia a essere soddisfacente. Non ci dispiacerebbe, però, avere una classe che, quando
usiamo un array di tipi numerici (es: float), ci fornisca gli opportuni operatori matematici: ArrayWithMathArrayWithMath.
D’altra parte vorremmo anche utilizzare il codice scritto finora, e non dover implementare di nuovo i metodi già presenti in ArrayArray nella classe ArrayWithMathArrayWithMath.
Possiamo sfruttare il meccanismo delle classi derivateclassi derivate.
C. Genta – Analisi dati 57
ArrayWithMath.h
Ricordarsi di mettere protectedprotected al posto di privateprivate in Array.h
C. Genta – Analisi dati 58
ArrayWithMath.h
#endif
C. Genta – Analisi dati 59
Ereditarietà
Quando creiamo un’istanza di una classe derivata, questa comunque eredita i metodi delle classi che la precedono nella gerarchia di derivazione
C. Genta – Analisi dati 60
Classi astratte
Stiamo realizzando un programma per disegnare figure geometriche. Per il momento ci limiteremo ai quadrati.
C. Genta – Analisi dati 61
Classi astratteQuesta e’ la classe che disegna il quadrato
C. Genta – Analisi dati 62
Il programma principale
C. Genta – Analisi dati 63
Classi astratte
Cosa succede se oltre ai quadrati vogliamo disegnare i cerchi?Ci serve una classe Cerchio e dobbiamo aggiungere un metodo a Designer per disegnare i cerchi.
Ma è proprio necessario ?
C. Genta – Analisi dati 64
Classi astratte
Square, Circle ed in genere tutte le figure geometriche che ci possono venire hanno alcuni aspetti in comune:un metodo che ci restituisce la posizione sullo schermo la possibilità di spostare la figuraun metodo per disegnarlaQuello che possiamo fare e’ definire una interfaccia astratta da cui derivano tutte le figuregeometriche che vogliamo poter disegnare.
C. Genta – Analisi dati 65
Shape.h
L’interfaccia astratta…
C. Genta – Analisi dati 66
Le forme geometriche
C. Genta – Analisi dati 67
Classi astratte
Designer continuerà ad essere una classe molto semplice e non dovremo avere un metodo per ogni forma:
Questo significa programmare interfacce!E nel programma principale cosa succede ?
shape
C. Genta – Analisi dati 68
Classi astratte
Vediamo come è possibile avere un codice semplice e di facile lettura, ma anche totalmente funzionale, se le interfacce sono state pensate (e programmate…) con cura
C. Genta – Analisi dati 69
Esercizi
Realizzare una classe per estendere ai numeri complessi il C++
Se ci volete provare avrete bisogno di fare – #include <math.h>
per avere tutte le funzioni matematiche tipo sin(), cos(), ecc...