UNIVERSITA’ DEGLI STUDI ROMA TRE
DIPARTIMENTO DI FISICA “E. AMALDI”
laboratorio di calcolo II
AA 2003/04
quinta settimana
a cura di
Domizia Orestano
Dipartimento di Fisica
Stanza 159 - tel. (06 5517) 7281
www.fis.uniroma3.it/~orestano
[email protected]
1
sommario
Ripasso degli argomenti trattati la settimana scorsa:
ereditarietà, protezioni, polimorfismo e metodi virtuali, distruttori e
distruttori virtuali, cosa abbiamo osservato nell’esercitazione
Un altro esempio che illustra nuovamente
ereditarietà, polimorfismo e metodi virtuali, distruttori e
distruttori virtuali, classi astratte
Overloading
Dei metodi e degli operatori, esempi
2
L'ereditarieta' in C++:
• Estensione delle caratteristiche di una classe: la classe
derivata è un caso particolare della classe base con
alcuni dettagli in più
– la figura 2D e' un caso particolare di Figura
– il Cerchio e' una figura 2D
• Adesione ad un modello: la classe base definisce le
caratteristiche minimali che devono avere tutte le
classi derivate
– Se Figura ha un metodo che si chiama disegna tutte le
classi che ereditano da Figura avranno un metodo disegna
3
Protezioni
Affinché la classe derivata possa accedere agli attributi della
classe base, senza violare l’incapsulamento che nasconde gli attributi della
classe base al resto del codice, questi devono essere dichiarati
protected nella classe base.
I clienti della classe derivata vedono i membri (attributi e metodi) della
classe base con livelli di protezione che dipendono da come si è dichiarata
la relazione di ereditarietà:
Tipo di
Ereditarieta’
Attributi e
Metodi Pubblici
Attributi e
Metodi Protetti
Attributi e
Metodi Privati
public
Pubblici
Protetti
Privati
protected
Protetti
Protetti
Privati
private
Privati
Privati
Privati
4
Metodi virtuali
1.
In presenza di metodi polimorfi, presenti con lo stesso prototipo in
più classi legate da ereditarietà, per indicare al compilatore che deve
cercare il metodo nella classe piu’ “bassa” nella catena gerarchica si
usa la parola virtual
2. virtual va utilizzato nella classe piu’ “alta” nella catena
gerarchica delle classi che devono utilizzare il polimorfismo (ma e’
bene ripeterlo anche nelle classi “figlie”)
3. Se un metodo e’ dichiarato virtual
•
•
Il compilatore ricerca un metodo nella classe piu’ bassa nella catena di
ereditarieta’ (esempio: calcolaPosizione(fx,fy,dt) )
Se non lo trova esegue il metodo nella classe piu’ alta (esempio: X()
Vx() )
4. Sintassi
virtual void calcolaPosizione
(float fx, float fy, float dt);
ma anche
virtual ~CorpoCeleste ( );
5
Distruttori virtuali
Quando viene invocato il Costruttore di una Classe che eredita da
altre, il compilatore invoca automaticamente i Costruttori di tutte le
Classi nella catena di ereditarieta’, inziando dal costruttore “piu’ in
alto” nella catena gerarchica
Quando viene invocato il Distruttore di una Classe che eredita da
altre, il compilatore invoca automaticamente i Costruttori di tutte le
Classi nella catena di ereditarieta’, inziando dal costruttore “piu’ in
basso” nella catena gerarchica
Se ad un oggetto si accede tramite il suo puntatore, istanziato come
puntatore di una delle classi madre, e’ necessario che il distruttore
sia definito virtual, in modo che il compilatore inizi ad invocare
il distruttore piu’ in basso nella catena di ereditarieta’, risalendo poi
tutta la catena gerarchica.
6
Esercitazione della scorsa settimana
Avete definito (.h) ed implementato (.cc) la classe Sonda che eredita da
CorpoCeleste. Una Sonda è un CorpoCeleste con alcune caratteristiche
in più (viene fatta partire dalla superficie di un CorpoCeleste con una
certa velocità iniziale ad un istante fissato) e con una versione
modificata del metodo calcolaPosizione.
Per inserire oggetti della nuova classe nella simulazione del sistema
solare è stato
sufficiente instanziarli nel main e dichiararli con aggiungiPianeta alla
classe SistemaSolare, non sono state necessarie modifiche a
SistemaSolare.
7
#include "CorpoCeleste.h"
class Sonda: public CorpoCeleste {
Sonda.h
protected:
float tCount;
float tStart;
CorpoCeleste *owner;
float svx;
float svy;
char started;
public:
Sonda(const char *name, float mass,
float starttime,
CorpoCeleste *startFrom,
float vxi, float vyi);
~Sonda() { } ;
void calcolaPosizione
(float fx, float fy, float t);
};
8
#include "Sonda.h"
#include <iostream.h>
Sonda.cc
Sonda::Sonda(const char *name, float mass,
float starttime, CorpoCeleste * startFrom,
float vxi, float vyi) :
CorpoCeleste(name, mass, 0., 0., 0., 0.) {
prima parte
tStart = starttime ;
tCount = 0 ;
owner = startFrom ;
svx = vxi ;
svy = vyi ;
started = 0 ;
x = owner->X() ;
y = owner->Y() ;
vx = owner->Vx() ;
vy = owner->Vy() ;
}
9
void Sonda::calcolaPosizione
(float fx, float fy, float t) {
if (tCount<tStart) {
x = owner->X() ;
y = owner->Y() ;
vx = owner->Vx() ;
vy = owner->Vy() ;
Sonda.cc
seconda parte
} else {
if (!started) {
cerr << "Sonda in partenza...\n” ;
vx += svx ;
vy += svy ;
started = 1 ;
}
CorpoCeleste::calcolaPosizione(fx,fy,t);
}
tCount += t ;
}
10
simula.cc
#include “SistemaSolare.h”
#include “Sonda.h”
int main() {
SistemaSolare ss(3) ;
// definisci un SistemaSolare
// definisci due pianeti
CorpoCeleste sole(“Il Sole”, 1.98e30, 0., 0., 0., 0.) ;
CorpoCeleste terra(“La Terra”, 5.98e24, 1.52e11, 0., 0., 29476.35) ;
// definisci una sonda
Sonda voyager(“Voyager II”, 110000., 100., &terra, 38000., -10800.) ;
// aggiungi i pianeti e la sonda al sistema solare
ss.aggiungiPianeta(&sole) ;
ss.aggiungiPianeta(&terra) ;
ss.aggiungiPianeta(&voyager) ;
// fai evolvere il sistema per 365 giorni
ss.evolvi(86400*365, 86400) ;
return 0 ;
}
11
Alcune modifiche sono state invece apportate in CorpoCeleste.h:
• dichiarazione gli attributi protected anziché private
chi se ne fosse scordato ha riscontrato un errore di compilazione quando Sonda cerca di
accedere x, y , vx o vy (nel costruttore e in calcolaPosizione)
• dichiarazione come virtual del metodo CorpoCeleste::calcolaPosizione
altrimenti, in SistemaSolare::evolvi, l’istruzione
pianeti[i]->calcolaPosizione((float)fx, (float)fy, dt);
chiamerebbe sempre CorpoCeleste::calcolaPosizione, anche per i puntatori ad oggetti
Sonda
• dichiazione come virtual del metodo CorpoCeleste::~CorpoCeleste
per far chiamare Sonda ::~Sonda (che a sua volta chiama CorpoCeleste::~CorpoCeleste )
quando si effettui il delete di un puntatore ad un CorpoCeleste che sia anche un Sonda
Chi ne ha avuto il tempo ha anche provato a rendere pure virtual un metodo di
CorpoCeleste e dovrebbe avere osservato un problema nella compilazione del
main: sole e terra non possono più essere istanziati!
12
#ifndef CORPOCELESTE_H
#define CORPOCELESTE_H
class CorpoCeleste {
protected:
char *Nome;
double m;
double x;
double y;
double vx;
double vy;
CorpoCeleste.h
con modifiche
per ereditarietà
public:
CorpoCeleste() ;
CorpoCeleste
(const char *nomeCorpo, float mass,
float xpos, float ypos, float vxi,
float vyi);
virtual ~CorpoCeleste() ;
virtual void calcolaPosizione
(float fx, float fy, float t);
void stampaPosizione();
void stampaVelocita() ;
const char *nome()
;
double M() ;
double X() ;
double Y() ;
double Vx() ;
double Vy() ;
};
#endif
13
Metodi pure virtual e classi astratte
1.
Se un metodo e’ dichiarato virtual, la classe che eredita
(la classe piu’ bassa nella catena gerarchica) puo’ ridefinire il metodo, che e’
comunque implementato nella classe da cui si eredita
2.
Se un metodo e’ dichiarato pure virtual
(virtual …. = 0 ; ) tutte le classi che ereditano devono fornire il
metodo, che non e’ implementato nella classe da cui si eredita
3.
Sintassi
virtual double Area() = 0 ;
4.
Una classe con almeno un metodo pure virtual si chiama classe astratta
5.
Attenzione! Gli oggetti di una classe astratta non possono essere istanziati
14
Un altro esempio
Supponiamo di avere tre classi (shape, cerchio e quadrato) legate tra loro da
una relazione di Ereditarietà.
shape
cerchio
quadrato
15
#ifndef SHAPE_H
#define SHAPE_H
shape.h
#include <iostream.h>
class shape {
public:
shape() {};
~shape() {
cout << " Distruggo una shape "
<< endl << endl ;
};
void print() {
cout << " Sono una shape" << endl ;
};
};
#endif
16
#ifndef CERCHIO_H
#define CERCHIO_H
cerchio.h
#include <iostream.h>
#include ”shape.h"
class cerchio : public shape {
public:
cerchio() {};
~cerchio() {
cout << " Distruggo un cerchio "
<< endl << endl ;
};
void print() {
cout << " Sono un cerchio " << endl ;
};
};
#endif
17
#ifndef QUADRATO_H
#define QUADRATO_H
quadrato.h
#include <iostream.h>
#include "shape.h"
class quadrato : public shape {
public:
quadrato() {};
~quadrato() {
cout << " Distruggo un quadrato "
<< endl << endl ;
};
void print() {
cout << " Sono un quadrato " << endl ;
};
};
#endif
18
int main() {
shape s;
cerchio c;
quadrato q;
cout << endl;
s.print();
c.print();
q.print();
Senza virtual
Sono una shape
Sono un cerchio
Sono un quadrato
shape * v[3];
v[0] = new shape;
v[1] = new cerchio;
v[2] = new quadrato;
cout << endl;
v[0]->print();
v[1]->print();
v[2]->print();
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
"
"
“
"
"
================== " << endl ;
Applico delete "
<< endl ;
shape 0 : " << endl; delete v[0];
shape 1 : " << endl; delete v[1];
shape 2 : " << endl; delete v[2];
endl;
" =================== " << endl;
return 0;
};
Sono una shape
Sono una shape
Sono una shape
19
#ifndef SHAPE_H
#define SHAPE_H
shape.h
#include <iostream.h>
class shape {
public:
shape() {};
~shape() {
cout << " Distruggo una shape "
<< endl << endl ;
};
virtual void print() {
cout << " Sono una shape" << endl ;
};
};
#endif
20
int main() {
shape s;
cerchio c;
quadrato q;
cout << endl;
s.print();
c.print();
q.print();
Con virtual
Sono una shape
Sono un cerchio
Sono un quadrato
shape * v[3];
v[0] = new shape;
v[1] = new cerchio;
v[2] = new quadrato;
cout << endl;
v[0]->print();
v[1]->print();
v[2]->print();
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
"
"
“
"
"
================== " << endl ;
Applico delete "
<< endl ;
shape 0 : " << endl; delete v[0];
shape 1 : " << endl; delete v[1];
shape 2 : " << endl; delete v[2];
endl;
" =================== " << endl;
return 0;
};
Sono una shape
Sono un cerchio
Sono un quadrato
21
Senza distruttore virtual
int main() {
shape s;
circle c;
quadrato q;
cout << endl;
s.print();
c.print();
q.print();
shape * v[3];
v[0] = new shape;
v[1] = new circle;
v[2] = new quadrato;
cout << endl;
v[0]->print();
v[1]->print();
v[2]->print();
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
==========================
Applico delete
shape 0 :
Distruggo una shape
shape 1 :
Distruggo una shape
shape 2 :
Distruggo una shape
=========================
Distruggo un quadrato
Distruggo una shape
Distruggo un cerchio
Distruggo una shape
Distruggo una shape
"
"
“
"
"
================== " << endl ;
Applico delete "
<< endl ;
shape 0 : " << endl; delete v[0];
shape 1 : " << endl; delete v[1];
shape 2 : " << endl; delete v[2];
endl;
" =================== " << endl;
return 0;
};
22
#ifndef SHAPE_H
#define SHAPE_H
shape.h
#include <iostream.h>
class shape {
public:
shape() {};
{
virtual ~shape()
cout << " Distruggo una shape "
<< endl << endl ;
};
virtual void print() {
cout << " Sono una shape" << endl ;
};
};
#endif
23
Con distruttore virtual
int main() {
shape s;
circle c;
quadrato q;
cout << endl;
s.print();
c.print();
q.print();
shape * v[3];
v[0] = new shape;
v[1] = new circle;
v[2] = new quadrato;
cout << endl;
v[0]->print();
v[1]->print();
v[2]->print();
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
==========================
Applico delete
shape 0 :
Distruggo una shape
shape 1 :
Distruggo un cerchio
Distruggo una shape
shape 2 :
Distruggo un quadrato
Distruggo una shape
=========================
Distruggo un quadrato
Distruggo una shape
Distruggo un cerchio
Distruggo una shape
Distruggo una shape
"
"
“
"
"
================== " << endl ;
Applico delete "
<< endl ;
shape 0 : " << endl; delete v[0];
shape 1 : " << endl; delete v[1];
shape 2 : " << endl; delete v[2];
endl;
" =================== " << endl;
return 0;
};
24
Supponiamo ora di voler aggiungere alle classi geometriche un
metodo che determini l’area della figura.
L’area di una figura si calcola in modo diverso a seconda della
sua forma. Dovremo quindi fornire una diversa
implementazione di
double Area( ) ;
per ogni classe.
Che metodo Area( ) mettiamo in shape? Ci mettiamo un
metodo pure virtual che fornisce il modello per le classi
derivate
virtual double Area( ) = 0 ;
25
#ifndef SHAPE_H
#define SHAPE_H
shape.h
#include <iostream.h>
class shape {
public:
shape() {};
virtual ~shape() {
cout << " Distruggo una shape "
<< endl << endl ;
};
virtual void print() {
cout << " Sono una shape" << endl ;
};
virtual double Area()=0;
};
#endif
26
Se ora provassimo a compilare il main avremmo degli errori :
1. Gli oggetti di tipo cerchio e di tipo quadrato non sono validi
perché non hanno il metodo Area
2. Gli oggetti di tipo shape non possono essere istanziati per lo
stessso motivo
Rimosso dal main l’oggetto di tipo shape aggiungiamo il metodo
Area nelle classi derivate:
27
#ifndef CERCHIO_H
#define CERCHIO_H
#include <iostream.h>
#include ”shape.h“
#include <math.h>
cerchio.h
class cerchio : public shape {
private:
double radius;
public:
cerchio(double r):radius(r) {};
~cerchio() {
cout << " Distruggo un cerchio "
<< endl << endl ;
};
void print() {
cout << " Sono un cerchio " << endl ;
};
double Area() {
return M_PI*radius*radius;
};
};
#endif
28
#ifndef QUADRATO_H
#define QUADRATO_H
#include <iostream.h>
#include "shape.h"
quadrato.h
class quadrato : public shape {
private:
double side;
public:
quadrato(s):side(s) {};
~quadrato() {
cout << " Distruggo un quadrato "
<< endl << endl ;
};
void print() {
cout << " Sono un quadrato " << endl ;
};
double Area() {
return side*side;
};
};
#endif
29
int main() {
shape * v[2];
v[0] = new circle(1);
v[1] = new quadrato(1);
cout << endl;
v[0]->print();
cout << v[0]->Area() <<endl;
v[1]->print();
cout << v[1]->Area() <<endl;
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
"
"
"
"
================== " << endl ;
Applico delete "
<< endl ;
shape 0 : " << endl; delete v[0];
shape 1 : " << endl; delete v[1];
endl;
" =================== " << endl;
return 0;
};
30
Overloading dei metodi
Due metodi della stessa classe aventi lo stesso nome, possono
essere distinti in base:
1. Al numero degli argomenti
CorpoCeleste( )
CorpoCeleste(char * nome, float mass, float x, float y)
2. Al tipo degli argomenti
calcolaPosizione(float fx,float dt);
calcolaPosizione(TwoVector f, float dt);
3. [ ovviamente: al tipo e al numero degli argomenti]
calcolaPosizione(float fx, float fy, float dt);
calcolaPosizione(TwoVector f, float dt);
Non e’ possibile distinguere tra metodi in base al tipo del
metodo (void, int, double, …)
31
unari
binari
Operatori aritmetici in C++
Addizione
X+Y
Sottrazione
X-Y
Moltiplicazione
X*Y
Divisione
X/Y
Modulo
X%Y
Addizione unaria
+X
Sottrazione unaria
-X
Preincremento
++X
Postincremento
X++
Predecremento
--X
Postdecremento
X--
NB non c’e’ l’operatore elevazione a potenza, si utilizza un metodo con 2
parametri: double pow(double base,double potenza)
32
Operatori sui bit in C++
Right shift dei bit
Left shift dei bit
OR
AND
XOR
X >> n
X << n
X|Y
X&Y
X^Y
33
Operatori logici in C++
Test di uguaglianza
Test di differenza
Test di ordinamento
Test di ordinamento
Test di ordinamento
Test di ordinamento
AND logico
OR logico
NOT logico
X==Y
X != Y
X<Y
X>Y
X <= Y
X >= Y
X && Y
X || Y
!X
34
Operatori di assegnazione in C++
Assegnazione
X =Y
Assegnazione con somma
X +=Y
Assegnazione con sottrazione
X -=Y
Assegnazione con moltiplicazione
X *=Y
Assegnazione con divisione
X /=Y
Assegnazione con modulo
X %=Y
Assegnazione con right shift dei bit
X >>= n
Assegnazione con left shift dei bit
X <<=n
Assegnazione con AND
X &= Y
Assegnazione con OR
X |= Y
Assegnazione con XOR
X ^= Y
35
Overloading degli operatori
Consente di definire un’algebra all’interno della classe.
Tutto ciò che facciamo con un operatore unario potrebbe essere
realizzato mediante un metodo membro senza parametri, che si limiti
ad agire sull’oggetto in esame (this) o con una funzione esterna alla
classe che riceva un unico parametro (una reference all’oggetto).
Tutto ciò che facciamo con un operatore binario potrebbe essere
realizzato mediante un metodo membro con un parametro o una
funzione esterna a due parametri.
L’uso degli operatori rende il codice più leggibile e consente
un’interpretazione più immediata delle operazioni effettuate. E’
importante però non stravolgere il significato convenzionale dei
simbili utilizzati: non definite una sottrazione scegliendo + come
simbolo !
36
Operatori membro
Gli operatori definiti all’interno della classe si chiamano operatori membro.
Gli operatori definiti in questo modo sono un modo naturale (e compatto) di
identificare un metodo (della classe) e come tali possono accedere ai membri
privati.
Gli operatori membro si applicano ad oggetti di una classe e possono avere
come argomento
nessun oggetto
(operatori unari)
un oggetto
(operatori binari)
a+b
a.operator+(b)
a=b
a.operator=(b)
a=b+c
a.operator=(b.operator+(c))
37
class Compl {
private:
double re; double im ;
Un esempio classico:
public:
la classe
// costruttori
Compl() ;
Compl(double a) ;
Compl(double a, double b) ;
Compl(Compl & c) ;
~Compl() ;
//distruttore
dei numeri complessi
//metodi di tipo Set
void set_Re(double a);
void set_Im(double b);
//metodi di tipo Get
double const Real() ;
double const Imm() ;
//operatori unari
Compl & operator- ();
//operatori binari
Compl & operator= (Compl const & c);
Compl operator+ (Compl const & c);
} ;
38
conversioni tra tipi
L’operatore
Compl operator+ (Compl const & c);
somma all’oggetto this il numero complesso c e ritorna il numero complesso
risultante, consentendo operazioni del tipo
Compl c1(2,3),c2(1,2),c3;
c3 = c1 + c2;
// equivalente a c3.operator=(c1.operator+(c2))
Come posso fare per sommare oggetti complessi e oggetti reali tra loro? Prevedo
l’opportuno operatore membro
Compl operator+ (doubl const & a);
double a = 5;
c3 = c1 + a;
// Ma non posso scrivere c3 = a + c1
39
Funzioni a due argomenti
Posso ricorrere ad un operatore non membro a due argomenti
Compl operator+(Compl const & c1, Compl const &c2);
Che viene dichiarato dopo la chiusura della dichiarazione della classe e che
non ha accesso ai membri privati della classe (dovrà usare metodi di tipo get).
Posso quindi implementare operatori specifici
Compl operator+(Compl const & c1, double const &a);
Compl operator+(double const & a, Compl const &c2);
O far uso del costruttore Compl(double a) che consente di scrivere
double a = 5;
compl c=a;
40
overloading dell’operatore << (cout)
overloading dell’operatore >> (cin)
L’overloading degli operatori << (cout) e >> (cin) avviene con
funzioni non membro. Gli operatori
ostream &
operator << (ostream & fstream, const Compl & c);
istream &
operator >> (istream & fstream, const Compl & c);
Sono definiti fuori della definizione della classe
41
Per referenza o per valore?
1. Negli argomenti delle funzioni, dei metodi e degli operatori è
sempre preferibile usare il passaggio per referenza (usando & o il
puntatore) poichè si evita la duplicazione dell’oggetto e si rende
quindi il programma più veloce
2. Nella variabile restituita dalla funzione : se la funzione ritorna un
oggetto vuol dire che il compilatore vi fornisce una copia di un
oggetto costruito all’interno della funzione. Non è possibile
ritornare l’indirizzo ad un oggetto locale costruito staticamente,
si possono invece ritornare indirizzi di oggetti creati
dinamicamente (ma ricordarsi sempre che qualcuno dovra’
cancellarli…). Usate la restituzione di un indirizzo solo quando è
strettamente necessario. In particolare è necessario farlo
nell’overloading di operatori predefiniti che ritornano indirizzi
(ad esempio =, += , <<) per mantenere la stesse funzionalità. 42
// Questo file e' stato ottenuto modificando,
// per scopo didattico, il file originario
// ThreVector.h (e ThreeVector.icc)
// della libreria CLHEP
// ===========================================
// This file is a part of the CLHEP - a Class
// Library for High Energy Physics.
// .SS Authors Leif Lonnblad and Anders Nilsson.
// ============================================
#ifndef TWOVECTOR_H
#define TWOVECTOR_H
#include <iostream.h>
#include <math.h>
TwoVector.h
class TwoVector {
private:
double dx, dy;
// The components.
public:
// COSTRUTTORE
TwoVector( float x , float y );
// COSTRUTTORE PER COPIA
TwoVector(const TwoVector &);
// DISTRUTTORE
~TwoVector();
43
// METODI
float x() const;
float y() const;
// The components in cartesian
// coordinate system.
void setX(float);
void setY(float);
// Set the components in
// cartesian coordinate system.
float phi() const;
// The polar angle.
float mag2() const;
// The magnitude squared (rho^2
// in spherical coordinate system).
float mag() const;
// The magnitude (rho in spherical
// coordinate system).
void setPhi(float);
// Set phi keeping mag constant (BaBar).
void setMag(float);
// Set magnitude keeping phi constant
// (BaBar).
44
// OPERATORI
TwoVector & operator = (const
// Assignment X = Y
TwoVector &);
// BOOLEANI ( Comparisons )
bool operator == (const TwoVector &) const;
bool operator != (const TwoVector &) const;
TwoVector operator - () const;
// Unary minus.
TwoVector & operator += (const TwoVector &);
// Addition ( += ).
TwoVector & operator -= (const TwoVector &);
// Subtraction (-= ).
TwoVector & operator *= (float);
// Scaling with real numbers.
double dot(const TwoVector &) const;
// Scalar product.
45
TwoVector operator +
(const TwoVector &);
// Addition of 2-vectors.
TwoVector operator – (const TwoVector &);
// Subtraction of 2-vectors.
double operator * (const TwoVector &);
// Scalar product of 2-vectors.
//
//
//
//
//
//
Si potrebbe anche definire un operatore
di moltiplicazione per una
matrice, che definisce una rotazione
generica.
Nel nostro caso lo evitiamo, poiche'
non sono state introdotte le matrici
//
TwoVector & operator *= (const HepRotation &);
//
TwoVector & transform (const HepRotation &);
//
//
Transformation with a
Rotation matrix.
};
46
// dopo il segno
classe
};
che indica la fine // della dichiarazione della
TwoVector operator * (const TwoVector & , float );
TwoVector operator * (float , const TwoVector & );
// Overloading dell'operatore <<
//
(cout)
ostream & operator << (ostream &, const TwoVector &);
// Output to a stream.
#include “TwoVector.icc”
#endif
//TWOVECTOR_H
47
//
//
//
//
Questo file e' stato ottenuto modificando,
per scopo didattico, il file // originario
ThreVector.icc (e ThreeVector.h) della
libreria CLHEP
//
//
//
//
//
//
//
=====================
This file is a part of the CLHEP –
a Class Library for High Energy Physics.
This is the definitions of the
member functions of the
TwoVector class.
=====================
TwoVector.icc
TwoVector::TwoVector(float x, float y)
: dx(x), dy(y) {}
float TwoVector::x() const {
return dx;
}
Float TwoVector::y() const {
return dy;
}
void TwoVector::setX(Float x) {
dx = x;
}
void TwoVector::setY(Float y) {
dy = y;
}
48
TwoVector::TwoVector(const TwoVector & p)
: dx(p.x()), dy(p.y())) {}
TwoVector::~TwoVector() {}
TwoVector & TwoVector::operator = (const TwoVector & p) {
dx = p.x();
dy = p.y();
return *this;
}
bool TwoVector::operator == (const TwoVector& v) const {
return (v.x()==x() && v.y()==y()) ? true :
false;
}
bool TwoVector::operator != (const TwoVector& v) const {
return (v.x()!=x() || v.y()!=y()) ? true : false;
}
TwoVector TwoVector::operator - () const {
return TwoVector(-dx, -dy);
}
TwoVector & TwoVector::operator +=
dx += p.x();
dy += p.y();
return *this;
}
(const TwoVector & p) {
49
TwoVector & TwoVector::operator -= (const TwoVector & p) {
dx -= p.x(); dy -= p.y();
return *this;
}
TwoVector & TwoVector::operator *= (float a) {
dx *= a;
dy *= a;
return *this;
}
float TwoVector::dot(const TwoVector & p) const {
return dx*p.x() + dy*p.y();
}
float TwoVector::mag2() const {
return dx*dx + dy*dy;
}
float TwoVector::mag() const {
return sqrt(mag2());
}
float TwoVector::phi() const {
return dx == 0.0 && dy == 0.0 ? 0.0 :
}
atan2(dy,dx);
50
void TwoVector::setMag(float ma){
float ph = phi();
setX(ma* cos(ph));
setY(ma* sin(ph));
}
void TwoVector::setPhi(float ph){
float ma = mag();
setX(ma*cos(ph));
setY(ma*sin(ph));
}
TwoVector TwoVector::operator + (const TwoVector & a) {
return TwoVector(dx + a.x(), dy + a.y());
}
TwoVector TwoVector::operator - (const TwoVector & a) {
return TwoVector(dx - a.x(), dy - a.y());
}
double TwoVector::operator * (const TwoVector & a) {
return this->dot(a);
}
51
non-member operators
TwoVector operator * (const TwoVector & p, float a) {
return TwoVector(a*p.x(), a*p.y());
}
TwoVector operator * (float a, const TwoVector & p) {
return TwoVector(a*p.x(), a*p.y());
}
ostream & operator << (ostream & fstream, const TwoVector & v) {
fstream << " (" << v.x() << "," << v.y() << ") ";
}
52
Scarica

ppt - Università degli Studi Roma Tre