C. Genta Analisi Dati a.a. 2009/10 - Gruppo1-2 INFN...

Post on 25-Jun-2020

5 views 0 download

Transcript of C. Genta Analisi Dati a.a. 2009/10 - Gruppo1-2 INFN...

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...