Introduzione ai linguaggi compilati orientati ad oggetti Alessandra Doria, Napoli Vincenzo Innocente, CERN Luca Lista, Napoli December1998 Vincenzo Innocente Introduzione al C++ 2 Soldato December1998 Vincenzo Innocente Introduzione al C++ 3 Concetti base dell’OO Classi ed oggetti Incapsulazione Relazione di ereditarietà Polimorfismo Programmazione Generica December1998 Vincenzo Innocente Introduzione al C++ 4 Kalman.inc PARAMETER (NPLAN = 8, NSTOP = NPLAN-1, + NSTOP5 = 5*NPLAN ) COMMON /GCFIT/ + CSIX(6,0:NSTOP),CSIY(6,0:NSTOP) + ,CSIZ(6,0:NSTOP) + ,WW(5,5,0:NSTOP),DDT(5,5,0:NSTOP) + ,VV(5,5,0:NSTOP),SS(5,5,0:NSTOP) + ,CC(5,5,0:NSTOP) + ,CHI2,CHI2N,CHI2T,CHI2M + ,PLANI(3,4,0:NSTOP) DOUBLE PRECISION + CSIX ,CSIY ,CSIZ + ,WW ,DDT + ,VV ,SS + ,CC + ,CHI2,CHI2N,CHI2T,CHI2M Dati globali Modello dei dati esplicito Sintassi oscura Tipo non controllato December1998 Filter.f SUBROUTINE FILTER(JSTOP,IFAIL) INTEGER JSTOP, IFAIL #include “Kalman.inc” DOUBLE PRECISION YDUM(5) * ** filter * CALL DVADD(25,WW(1,1,JSTOP),WW(2,1,JSTOP), + VV(1,1,JSTOP),VV(2,1,JSTOP), + CC(1,1,JSTOP),CC(2,1,JSTOP)) CALL DSINV(5,CC(1,1,JSTOP),5,IFAIL) IF ( IFAIL.NE.0 ) THEN 1 PRINT *,'DSINV IFAIL',IFAIL,' AT PLANE ',JSTOP CALL VZERO(CC(1,1,JSTOP),50) RETURN ENDIF CALL DMMPY(5,5,VV(1,1,JSTOP),VV(1,2,JSTOP),VV(2,1,JSTOP), + CSIZ(1,JSTOP),CSIZ(2,JSTOP), + YDUM(1), YDUM(2)) CALL DMMPA(5,5,WW(1,1,JSTOP),WW(1,2,JSTOP),WW(2,1,JSTOP), + CSIY(1,JSTOP),CSIY(2,JSTOP), + YDUM(1), YDUM(2)) CALL DMMPY(5,5,CC(1,1,JSTOP),CC(1,2,JSTOP),CC(2,1,JSTOP), + YDUM(1), YDUM(2), + CSIX(1,JSTOP),CSIX(2,JSTOP)) CSIX(6,JSTOP) = CSIY(6,JSTOP) * CHI2 DO J = 1,5 DO K=1,5 CHI2 = CHI2 + + (CSIX(K,JSTOP)-CSIZ(K,JSTOP))*VV(K,J,JSTOP)* + (CSIX(J,JSTOP)-CSIZ(J,JSTOP)) + + (CSIX(K,JSTOP)-CSIY(K,JSTOP))*WW(K,J,JSTOP)* + (CSIX(J,JSTOP)-CSIY(J,JSTOP)) ENDDO ENDDO * END Vincenzo Innocente Introduzione al C++ 5 KalmanStep.h KalmanStep.cc class KalmanStep { public: bool propagate(const KalmanStep& previous); bool filter() ; bool smooth(const KalmanStep& next); private: Vector5 csix; SimMatrix5 cc; SimMatrix5 ss; bool KalmanStep::filter() { bool fail = false; cc = ww+vv; cc.invert(fail); if (fail) { cc.zero(); return !fail;} csix = cc*(vv*csiz + ww*csiy); chi2 += (csix-csiz)*vv*(csix-csiz)+ (csix-csiy)*ww*(csix-csiy); return !fail; } Vector5 csiy; SimMatrix5 ww; Tipo controllato o convertito Vector5 csiz; SimMatrix5 vv; Sintassi naturale Matrix5 ddt; Plane plane; double chi2; }; Modello dei dati nascosto Dati incapsulati December1998 Vincenzo Innocente Introduzione al C++ 6 Classi e oggetti Scriviamo delle classi che modellino oggetti disegnabili quali cerchi, rettangoli, esagoni. December1998 Vincenzo Innocente Introduzione al C++ 7 Circle.cc Cerchio #include “Circle.h” Nome della classe Circle.h Costruttore class Circle { public: Circle(Point2d ic, double ir); ~Circle(); void void void void void moveAt(const Point2d & where); scale(double s); rotate(double); draw() const; cancel() const; private: Point2d center_; double radius_; }; Main.cc void Circle::draw() const { float x[100], y[100]; float phi=0,float dphi=6.28e-2; for {int i=0;i!=100;++i) { x[i] = center_.x() + radius_*cos(phi); y[i] = center_.y() + radius_*sin(phi); phi+=dphi; } polyline_draw(x,y,100,color_,FILL); } Distruttore Point2d: classe che rappresenta un puntovoid in 2 Circle::moveAt(const dimensioni. Point2d& where) { cancel(); center_ = where; draw(); } void Circle::scale(double s) { cancel(); radius_*=s; draw(); } Interfaccia Pubblica Circle::Circle(Point2d ic, center_(ic), radius_(ir) Metodi: operazioni sugli oggetti { draw(); } double ir) : #include “Circle.h” Circle::~Circle() { cancel(); } “Dati” privati int main() { (Attributi, membri) Circle c1(Point2d(2, 3), 4.23); Punto e virgola! c1.draw(); c1.moveAt(Point2d(3, 3)); return 0; } December1998 c1 è un oggetto di classe Circle Vincenzo Innocente Introduzione al C++ 8 Circle.cc Cerchio Circle.h Nome della classe Costruttore class Circle { public: Circle(Point2d ic, double ir, Color ico=TRASPARENT) : center_(ic), radius_(ir), color_(ico) {draw();} ~Circle(){cancel();} Distruttore #include “Circle.h” void Circle::draw() const { float x[100], y[100]; float phi=0,float dphi=6.28e-2; for {int i=0;i!=100;++i) { x[i] = center_.x() + radius_*cos(phi); y[i] = center_.y() + radius_*sin(phi); phi+=dphi; } polyline_draw(x,y,100,color_,FILL); } void moveAt(const Point2d& where) {cancel();center_=where; draw();} void moveBy(const Vector2d& delta) {cancel();center_+=delta; draw();} void changeColor(Color newColor) {cancel(); color_=newColor; draw();} void scale(double s) {cancel(); radius_*=s; draw();} void rotate(double){} void draw() const; Point2d: void cancel() const; Interfaccia Pubblica Metodi: operazioni sugli oggetti classe che rappresenta un punto in 2 dimensioni Un oggetto può essere un attributo di un’altro. private: Point2d center_; double radius_; Color color_; }; Punto e virgola! December1998 “Dati” (attributi, membri) privati Vincenzo Innocente Introduzione al C++ 9 Square.cc Quadrato Square.h class Square { public: Square(Point2d ilc, Point2d iuc, Color ico=TRASPARENT) : center_(median(ilc,iuc)), touc_(iuc-center_), color_(ico) {draw();} ~Square(){cancel();} #include “Square.h” void Square::draw() const { float x[4], y[4]; Vector2d delta = touc_; for (int i=0;i!=4;++i) { point2d corner = center_+delta; x[i] = corner.x(); y[i] = corner.y(); delta.rotate(M_PI_2); } polyline_draw(x,y,4,color_,FILL); } void moveAt(const Point2d& where) {cancel();center_=where; draw();} void moveBy(const Vector2d& delta) {cancel();center_+=delta; draw();} void changeColor(Color newColor) {cancel(); color_=newColor; draw();} void scale(double s) {cancel(); touc_*=s; draw();} void rotate(double phi) {cancel(); touc_.rotate(phi); draw();} void draw() const; void cancel() const; private: Point2d center_; Vector2d touc_; Color color_; }; December1998 touc_ upper corner lower corner Vincenzo Innocente Introduzione al C++ 10 Codice Applicativo Main.cc #include “Circle.h” #include “Rectangle.h” #include <vector> “Include” delle dichiarazioni delle classi usate Oggetto temporaneo int main() { Circle c1(Point2d(2.,3.),4.23,RED); Square r1(Point2d(2.,1.),Point2d(4.,3.)); c1.draw(); r1.moveBy(Vector2d(3.,3.)); r1.draw(); vector<Circle *> vc; for (int I=0; I!=10; ++I) { vc.push_back(new Circle(Point2d(I,I),2.) ); } vector<Circle *>::const_iterator p; for (p=vc.begin(); p!=vc.end(); ++p) (*p)->draw(); Invoca i costruttori per creare nuovi oggetti locali Invoca i metodi draw() e moveBy() Costruisce un vettore di puntatori a cerchi, crea oggetti sull’heap e salva i loro puntatori nel vettore. Itera sul vettore e invoca draw() per ogni elemento return 0; } December1998 Vincenzo Innocente Introduzione al C++ Come gestire cerchi e quadrati insieme? 11 Polimorfismo Tutte le Shapes hanno la stessa interfaccia: draw, pick, move, fillColor..., ma ogni sottotipo diverso può avere la usa personale implementazione December1998 Vincenzo Innocente Introduzione al C++ 12 Interfaccia astratta Main.cc Shape.h class Shape { public: Shape(){} virtual ~Shape(){} Interfaccia di metodi puramente virtuali virtual void moveAt(const Point2d& where)=0; virtual void moveBy(const Vector2d& delta)=0; virtual void changeColor(Color newColor)=0; virtual void scale(double s) =0; virtual void rotate(double phi)=0; virtual void draw() const=0; virtual void cancel() const=0; }; Square.h #include “Shape.h” class Square : public Shape { // …. Il resto tutto uguale a prima }; #include “Circle.h” #include “Square.h” #include <vector> int main() { Circle c1(Point2d(2.,3.),4.23,RED); // Shape s; // errore! Una classe astratta non si instanzia! Shape * s = &c1; // Shape si usa solo come puntatore! c1.draw(); // invoca direttamente Circle::draw s->moveby(Vector2d(3.,3.)); // invoca moveby “virtualmente” vector<Shape *> vs; for (int I=0; I!=10; ++I) { vs.push_back(new Circle(Point2d(I,I),2.)); vs.push_back(new Square(Point2d(I,I), Point2d(I+1,I+2))); } vector<Shape *>::const_iterator p; for (p=vs.begin(); p!=vs.end(); ++p) (*p)->draw(); return 0; December1998 } Vincenzo Innocente Introduzione al C++ 13 Ereditarietà e riuso del codice CCShape.h Circle.h Square.h {draw();} ~Circle(){cancel();} class Square { Non si possono chiamare public: Square(Point2d ilc, Point2d iuc, Color metodi virtuali in costruttori e ico=TRASPARENT) : distruttori (troppo presto, center_(median(ilc,iuc)), touc_(iuc-center_), color_(ico) {draw();} troppo tardi) ~Square(){cancel();} Class CCShape: public Shape { class Circle { public: public: CCShape(Point2d Color ico=TRASPARENT) : Circle(Point2dic,ic, double ir, center_(ic), color_(ico) {/*draw();*/}: Color ico=TRASPARENT) center_(ic), radius_(ir), color_(ico) ~Circle() {/*cancel();*/} void moveAt(const Point2d& where) Square.h void moveAt(const Point2d& where) {cancel();center_=where; draw();} void moveAt(const Point2d& where) {cancel();center_=where; draw();} void moveBy(const Vector2d& delta) CCShape { {cancel();center_=where; draw();}class Square : public void moveBy(const Vector2d& delta) {cancel();center_+=delta; draw();} void moveBy(const Vector2d& delta) public: {cancel();center_+=delta; draw();} {cancel();center_+=delta; draw();}SquarePoint2d void changeColor(Color newColor) ilc, Point2d iuc, Color ico=TRASPARENT) : void changeColor(Color newColor) void changeColor(Color newColor) {cancel(); color_=newColor; draw();} CCShape(median(ilc,iuc),ico), touc_(iuc-center_)draw();} {draw();} {cancel(); color_=newColor; {cancel(); color_=newColor; draw();} virtual void scale(double s) =0; ~Square(){cancel();} void scale(double s) {cancel(); radius_*=s; void scale(double s) {cancel(); touc_*=s; draw();} void rotate(double phi) {cancel(); virtual void rotate(double)=0; draw();} touc_.rotate(phi); virtual draw() const =0; void scale(double s) {cancel(); touc_*=s;draw();} draw();} void void rotate(double){} void draw() const; virtual cancel() const =0; void void draw() const; void rotate(double phi) {cancel(); touc_.rotate(phi); draw();} void cancel() const; void cancel() const; void draw() const; protected: void cancel() const; private: private: Point2d center_; Point2d center_; Point2d center_; Vector2d touc_; Color color_; private: double radius_; Color color_; }; Color color_; Vector2d touc_; }; }; }; December1998 Vincenzo Innocente Introduzione al C++ 14 Modello UML December1998 Vincenzo Innocente Introduzione al C++ 15 Programmazione generica Funzioni Generiche “<” deve essere definito per “T” template<class T> inline T min(const T& a, const T& b) {return a<b ? a:b;} P.h Main.cc class P { public: P(int ix,int iy):x(ix),y(iy){} bool operator<(const P& b) const { return y<b.y ||(y==b.y&&x<b.x); } private: float x; float y; }; December1998 Usa min<float> int main() { float a =min(3.,2.); int i = min(2,3); P p1(1.,2.), p2(3.,1.); P p3 = min(p1,p2); return 0; } Vincenzo Innocente Introduzione al C++ Usa min<P> 16 Programmazione generica Classi Generiche “copy” è una funzione generica di STL Vector3d.h template <class T> class Vector3d { public: Vector3d(const T*a) {copy(a,a+3,&x[0]);} Vector3d<T>& operator+=(const Vector3d<T>& b) {x[0]+=b.x[0]; x[1]+=b.x[1]; x[2]+=b.x[2]; return *this;} Main.cc private: #include “vector3d.h” T x[3]; int main() { }; Vector3d<float> a, b,c; Ritorna se stesso per permettere la concatenazione di operatori December1998 Vincenzo Innocente Introduzione al C++ c+=b+=a; Vector3d<complex> c1, c2; c2+=c1; return 0; } 17 La libreria standard: std (STL) Contenitori generici: Iteratori vector, list, set, map, “string” puntatori “intelligenti” nei contenitori generici Funzioni generiche copy, merge, find, sort, swap,… agiscono su iteratori December1998 Vincenzo Innocente Introduzione al C++ 18 Un semplice vettore Main.cc #include <vector> int main() { vector<int> v; // creamo un vettore di interi vuoto cout << v.size() << endl; // stampa dimensione di v: zero for (int I=0; I!=10; ++I) { un loop da 0 a 9 v.push_back(I); // aggiungiamo un intero a v dal fondo } cout << v.size() << endl; // stampa dimensione di v: 10 // creiamo un iteratore costante per un vettore di interi: // p si comporta come un “const int *” a tutti gli effetti vector<int>::const_iterator p; // begin() punta al primo elemento end() all’ultimo+1 // (confrontare col “for” precedente) for (p=v.begin(); p!=v.end(); ++p) cout << (*p) << “ “; cout << endl; return 0; } December1998 Vincenzo Innocente Introduzione al C++ 19 Un semplice vettore begin() end() 0 1 2 ... 9 ++ p p p p p December1998 Vincenzo Innocente Introduzione al C++ push_back() p 20 Vettore di classe astratta Shape* Main.cc #include “Circle.h” #include “Square.h” #include <vector> int main() { vector<Shape *> vs; // un vettore di puntatori a Shapes for (int I=0; I!=10; ++I) { // aggiungiamo un puntatore ad un nuovo cerchio vs.push_back(new Circle(Point2d(I,I),2.)); // aggiungiamo un puntatore ad un nuovo quadrato vs.push_back(new Square(Point2d(I,I), Point2d(I+1,I+2))); } // iteratore: essenzialmente un puntatore a Shape* ossia un Shape** vector<Shape *>::const_iterator p; for (p=vs.begin(); p!=vs.end(); ++p) // loop sull’intero vettore (*p)->draw(); // disegniamo ogni Shape return 0; } December1998 Vincenzo Innocente Introduzione al C++ 21 Puntatori int int int int int i=4; // un intero locale (locale = viene distrutto quando va fuori scopo) j=i; // un altro intero locale * pi = &i; // un puntatore alla locazione di memoria di “i” * qi = pi; // un altro puntatore alla locazione di memoria di “i” * pj = &j; // un puntatore alla locazione di memoria di “j” cout << i << endl; // stampo il valore di “i” cout << *pi << endl; // stampo il contenuto della locazione di memoria // puntata da “pi” (il valore di “i”) cout << pi << endl; // stampo il valore di “pi”: l’indirizzo di memoria di “i” *pi==*qi; pi == qi; pi == qj; // falso! December1998 *pi==*pj; // vero! Vincenzo Innocente Introduzione al C++ 22 Puntatori Circle c1(Point2d(2.,3.),4.23,RED); // un cerchio locale Circle * pc1 = &c1; // un puntatore alla locazione di memoria di “c1” // new alloca un quadrato sull’heap; pq2 punta alla sua locazione in memoria Square * pq2 = new Square(Point2d(2.,1.),Point2d(4.,3.)); // le tre istruzioni seguenti producono lo stesso risultato c1.draw(); (*pc1).draw(); pc1->draw(); delete pq2; // distrugge l’oggetto puntato da pq2 e rilascia la memoria allocata December1998 Vincenzo Innocente Introduzione al C++ 23 Vettori, Puntatori e Iteratori int v1[4]; // array locale (dimensione fissa al tempo della compilazione) const int n=4; int * v2 = new int[n]; // array sull’heap (dimensione fissata all’allocazione) vector<int> v3(4); // vettore STL (dimensione variabile) // accesso all’elemento i-esimo v3[i] = v2[i] = v1[i]; // ma anche int * p; p=v1; p+=i; v2[i]=*p; vector<int>::iterator q=v3.begin(); *(q+i)=v1[i] ; // copia usando std::copy copy(&v1[0],&v1[4],v2); // copia v1 in v2 copy(v2,v2+4,v3.begin()); // copia v2 in v3 December1998 Vincenzo Innocente Introduzione al C++ 24 Per referenza e per valore Sub.f subroutine Sub(I) I=4 end void Sub(int I) { I=4; } PROGRAM MAIN int J; int main() { J=3 call Sub(J) C Sub.c stampa 4 print *, J end J=3; Sub(J); Sub.cc void Sub(int & I) { I=4; } /* stampa 3 */ printf(%d,J); } int main() { int J=3; Sub(J); // } December1998 stampa 4 cout << J << endl; Vincenzo Innocente Introduzione al C++ 25 Concetti Classici Riveduti Relazioni tra oggetti Decomposizione funzionale in una classe responsabilità dei metodi Decomposizione funzionale tra classi responsabilità delle classi December1998 Vincenzo Innocente Introduzione al C++ 26 Modello di Hardware DAQ Costruiamo un modello del Hardware per un sistema di acquisizione “Use Cases”: gestione delle parti (dove sono, a chi appartengono) simulazione (potenza dissipata, spazio occupato) controllo on-line (on/off, temperatura, voltaggio) DAQ (questi dati da dove vengono?) calibrazione (piedistalli, guadagni, fattori di conversione) December1998 Vincenzo Innocente Introduzione al C++ 27 Chi sono i giocatori? I componenti Hardware: Racks, crates, moduli di vario tipo e foggia “Utenti” (persone, displays, interfacce) conviene avere un “corrispondente” nel modello Primi candidati a classi e oggetti December1998 Vincenzo Innocente Introduzione al C++ 28 Un primo modello December1998 Vincenzo Innocente Introduzione al C++ 29 Calcolo della potenza in un rack December1998 Vincenzo Innocente Introduzione al C++ 30 La base di un modello composto December1998 Vincenzo Innocente Introduzione al C++ 31 Codice del modello composto DaqComponent.h DaqLeaf.h class DaqComposite; // forward declaration class DaqComponent { public: DaqComponent() : parent_(0) {} virtual float power() const=0 protected: DaqComposite * parent_; }; #include “DaqComponent.h” class DaqLeaf: public DaqComponent { public: explicit DaqLeaf(float ip=0): power_(ip) {} float power() const { return power_;} } protected: float power_; }; December1998 Vincenzo Innocente Introduzione al C++ 32 Codice del modello composto DaqComposite.h #include “DaqComponent.h” class DaqComposite : public DaqComponent { public: typedef vector<DaqComponent *> VC; typedef VC::const_iterator CIter; DaqComposite(){} float power() const { tp =0; CIter p=components.begin(); CIter pe=components.end(); while (p!=pe) {tp+=(*p)->power(); ++p;} return tp; } protected: VC components; }; December1998 Vincenzo Innocente Introduzione al C++ 33 Le classi “concrete” December1998 Vincenzo Innocente Introduzione al C++ 34 Aggiungiamo un inventario December1998 Vincenzo Innocente Introduzione al C++ 35 Dove si trova un componente? Dato un componente vogliamo sapere la sua locazione globale La risposta è una stringa che concatena le locazioni locali (room,rack,crate,module) Chi è responsabile della conoscenza della locazione: il componente o il composito? Entrambe le soluzioni hanno pro e contro Una soluzione “flessibile” è assegnare la locazione all’associazione di composizione December1998 Vincenzo Innocente Introduzione al C++ 36 Locazione di un componente In C++: DaqComponent punterà a Location DaqComposite avrà un vettore di (puntatori a) Locations Location (oltre ad un identificatore) punterà a DaqComponent e DaqComposite Location può essere una classe astratta e la rappresentazione del suo identificatore può così dipendere dal tipo di composito (un intero per la slot di un modulo in un crate, una stringa per la posizione di un rack in una stanza) December1998 Vincenzo Innocente Introduzione al C++ 37 Stampa della locazione globale Per ottenere una stringa che identifichi la posizione globale, ogni componente prima invoca la locazione del suo genitore e poi stampa la propria locazione (delegando quest’ultima operazione a Location per essere indipendente dalla rappresentazione concreta dell’identificatore della locazione stessa) December1998 Vincenzo Innocente Introduzione al C++ 38 Circle.cc Cerchio Nome della classe #include “Circle.h” void Circle::draw() const { float x[100], y[100]; Circle.h float phi=0,float dphi=6.28e-2; Circle.h for {int i=0;i!=100;++i) { Costruttore class { classCircle Circle { class Circle { x[i] = center_.x() + radius_*cos(phi); public: public: public: Circle(Point2d ic, double ir, y[i] = center_.y() + radius_*sin(phi); Circle(Point2d ic, double ir, Color Color ico=TRASPARENT) : phi+=dphi; center_(ic), radius_(ir), color_(ico) {draw();} Color ico=TRASPARENT) : ico=TRASPARENT) : } center_(ic), radius_(ir), color_(ico) polyline_draw(x,y,100,color_,FILL); ~Circle(){cancel();} } {draw();} Distruttore void moveat(const Point2d& where) ~Circle(){cancel();} {cancel();center_=where; draw();} void moveby(const Vector2d& delta) void {cancel();center_+=delta; moveby(const Vector2d& delta) draw();} void changeColor(Color newColor) {cancel();center_+=delta; draw();} {cancel(); color_=newColor; draw();} voidscale(double draw() const; void s) {cancel(); radius_*=s; #include “Circle.h” void cancel() const; draw();} int main() { void rotate(double){} void draw() const; Point2d: classe che rappresenta un private: void cancel() const; Main.cc private: private: private: Point2d center_; Point2d center_; double radius_; double radius_; Color color_; Color color_; Interfaccia Pubblica Metodi: operazioni sugli oggetti punto in 2 dimensioni Circle c1(Point2d(2.,3.),4.23,RED); Un oggetto può essere un attributo di un’altro. c1.draw(); “Dati” (attributi, membri) c1.moveby(Vector2d(3.,3.)); return 0; Vincenzo}Innocente }; }; }; privati Punto e virgola! December1998 Introduzione al C++ 39