La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

1 Ereditarietà Una classe può essere derivata da una classe esistente usando la sintassi: public, protected e private specificano il tipo di accesso ai.

Presentazioni simili


Presentazione sul tema: "1 Ereditarietà Una classe può essere derivata da una classe esistente usando la sintassi: public, protected e private specificano il tipo di accesso ai."— Transcript della presentazione:

1 1 Ereditarietà Una classe può essere derivata da una classe esistente usando la sintassi: public, protected e private specificano il tipo di accesso ai membri della classe protected vuol dire che i campi sono accessibili da una sottoclasse, ma non da altre classi esterne (sta fra public e private, è come se la sottoclasse fosse friend della classe di base per quei campi) class newclass: (public|protected|private) oldclass { dichiarazioni... };

2 2 Ereditarietà (2) Una classe derivata pubblicamente è a tutti gli effetti un sottotipo della classe base. –Un oggetto della classe derivata può essere trattato come se fosse un oggetto della classe base –Un puntatore alla classe base può puntare ad oggetti della classe derivata –Un riferimento alla classe derivata può, se la cosa ha un senso, essere implicitamente convertito ad un riferimento alla classe base –E` possibile dichiarare un riferimento alla classe base ed inizializzarlo ad un oggetto della classe derivata

3 3 Ereditarietà (3) La definizione dellinterfaccia (metodi pubblici) della classe base è estremamente importante perchè determina il comportamento delle classi derivate Un metodo della classe base può essere: –dichiarato e definito normalmente la classe derivata eredita questo metodo e NON può ridefinirlo –dichiarato virtual e definito normalmente la classe derivata eredita questo metodo e può ridefinirlo –dichiarato virtual e non definito (=0) la classe derivata eredita il metodo e DEVE ridefinirlo

4 4 Classi base astratte Una funzione puramente virtuale è un metodo virtuale non definito. E` dichiarato come: Una classe che ha almeno un metodo puramente virtuale è chiamata classe astratta Oggetti di una classe astratta non possono esistere Puntatori ad una classe base astratta possono essere definiti ed usati polimorficamente (per puntare ad oggetti delle classi derivate) Una classe base astratta viene introdotta per specificare linterfaccia di una categoria di classi virtual func_prototype = 0;

5 5 Esempio: i soldati Tutti i soldati devono capire il messaggio attacca. Il messaggio ha conseguenze diverse a seconda del tipo di soldato: –un arcere lancia una freccia –un fante usa la spada –un cavaliere lancia una lancia Il gestore della schermata vuole tenere una lista di soldati e vuole poter dire ad ogni soldato di attaccare indipendentemente dal tipo ma basandosi solo sulla posizione.

6 6 list lista; riempiLista(lista); Posizione unaPosizione=...; list ::iterator iter; for(iter=lista.begin();iter!=lista.end();iter++){ Soldato unSoldato=(*iter); if(unSoldato.posizione()==unaPosizione) unSoldato.attacca(); } class Soldato { void attacca() { // cosa scrivo qui?!? Per quale tipo di // soldato implemento il metodo attacca()? // soluzione la dichiaro virual = 0!!!! } }; list lista; riempiLista(lista); Posizione unaPosizione=...; list ::iterator iter; for(iter=lista.begin();iter!=lista.end();iter++){ Soldato unSoldato=(*iter); if(unSoldato.posizione()==unaPosizione) unSoldato.attacca(); } class Soldato { void attacca() { // cosa scrivo qui?!? Per quale tipo di // soldato implemento il metodo attacca()? // soluzione la dichiaro virual = 0!!!! } };

7 7 class Soldato { virtual void attacca()=0; }; class Arcere : public Soldato { virtual void attacca() { // lancia una freccia } }; class Fante : public Soldato { virtual void attacca() { // usa la spada } };... class Soldato { virtual void attacca()=0; }; class Arcere : public Soldato { virtual void attacca() { // lancia una freccia } }; class Fante : public Soldato { virtual void attacca() { // usa la spada } };...

8 8 Erediarietà multipla Lereditarietà multipla permette di derivare una classe da due o più classi base. La sintassi viene estesa per permettere una lista di classi base L ereditarietà multipla viene spesso utilizzata per combinare uninterfaccia ed una implementazione, ma è molte volte sintomo di un cattivo disegno class A {.. }; class B {.. }; class AplusB: public A, private B {.. };

9 9 Ereditarietà (4) Una classe derivata estende la classe base e ne eredita tutti i metodi e gli attributi class Track { public: LorentzVector momentum() { return p_; } protected: LorentzVector p_; }; class Track { public: LorentzVector momentum() { return p_; } protected: LorentzVector p_; }; Track.h #include Track.h class DchTrack : public Track { public: int hits() { return hits_->size(); } DchHit* hit(int n) { return hits_[n]; } protected: list hits_; }; #include Track.h class DchTrack : public Track { public: int hits() { return hits_->size(); } DchHit* hit(int n) { return hits_[n]; } protected: list hits_; }; DchTrack.h DchTrack è una Track che ha degli attributi in più ( hits_ ) e nuovi metodi ( DchHit* hit(int n), int hits() )

10 10 Esempio: shape Tutti gli oggetti nella finestra hanno comportamenti comuni che possono essere considerati in astratto: –disegna –sposta –ingrandisc –etc...

11 11 Cerchi e quadrati Quadrato Cerchio

12 12 Circle.h Cerchio Costruttore Distruttore Nome della classe Punto e virgola! Point2d : classe che rappresenta un punto in 2 dimensioni. public: Circle(Point2d center, double radius); ~Circle(); void moveAt(const Point2d & p); void moveBy(const Point2d & p); void scale(double s); void rotate(double phi); void draw() const; void cancel() const; Dati privati (Attributi, membri) class Circle { }; private: Point2d center_; double radius_; Interfaccia Pubblica Metodi: operazioni sugli oggetti

13 13 Cerchio (2) # include Circle.h void Circle::draw() const { const int numberOfPoints = 100; float x[numberOfPoints], y[numberOfPoints]; float phi = 0, deltaPhi = 2*M_PI/100; for ( int i = 0; i < numberOfPoints; ++i ) { x[i] = center_.x() + radius_ * cos( phi ); y[i] = center_.y() + radius_ * sin( phi ); phi += dphi; } polyline_draw(x, y, numberOfPoints, color_, FILL); } void Circle::moveAt( const Point2d& p ) { cancel(); center_ = p; draw(); } void Circle::scale( double s ) { cancel(); radius_ *= s; draw(); } Circle::Circle( Point2d c, double r ) : center_( c ), radius_( r ) { draw(); } Circle::~Circle() { cancel(); } Circle.cc #include Circle.h int main() { Circle c( Point2d(10, 10), 5 ); c.draw(); c.moveAt(Point2d(20, 30)); return 0; } Main.cc

14 14 Quadrato class Square { public: Square(const Point2d&, const Point2d&, Color color = TRASPARENT); ~Square(); void moveAt( const Point2d& p ); void moveBy( const Point2d& p ); void changeColor( Color color ); void scale( double s ); void rotate( double phi ); void draw() const; void cancel() const; private: Point2d center_; Vector2d centerToUpperCorner_; Color color_; }; Square.h #include Square.h void Square::draw() const { float x[4], y[4]; Vector2d delta( centerToUpperCorner_ ); 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 Square::rotate( double phi ) { cancel(); centerToUpperCorner_.rotate( phi ); draw(); } Square::Square(const Point2d& lowerCorner, const Point2d& upperCorner, Color color) : center_( median(lowerCorner, upperCorner) ), centerToUpperCorner_( upperCorner - center_ ), color_( color ) { draw(); } void Square::scale( double s ) { cancel(); centerToUpperCorner_ *= s; draw(); } Square.cc upperCorner loweCorner centerToUpperCorner _

15 15 Codice Applicativo (Client) #include Circle.h #include Square.h int main() { Circle c1( Point2d(2.,3.), 4.23 ); Square r1( Point2d(2.,1.), Point2d(4.,3.) ); Circle * circles[ 10 ]; for ( int i = 0; i < 10; ++i ) { circles[ i ] = new Circle( Point2d(i,i), 2. ); } for ( int i = 0; i < 10; ++i ) circles[ i ]->draw(); return 0; } Main.cc Come gestire cerchi e quadrati insieme? Costruisce un vettore di puntatori a cerchi, crea oggetti in memoria e salva i loro puntatori nel vettore. Itera sul vettore e invoca draw() per ogni elemento

16 16 Polimorfismo Tutte le Shapes hanno la stessa interfaccia: draw, pick, move, fillColor..., ma ogni sottotipo diverso può avere la usa personale implementazione

17 17 class Shape { public: Shape() { } virtual ~Shape() { } virtual void moveAt(const Point2d& where) = 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; }; Shape.h Interfaccia astratta Interfaccia di metodi puramente virtuali #include Shape.h class Square : public Shape { // …. Il resto tutto uguale a prima }; Square.h #include Circle.h #include Square.h int main() { Shape * shapes[ 20 ]; int index = 0; for ( int i = 0; i < 10; i++ ) { Shape * s; s = new Circle( Point2d(i, i), 2.) ); shapes[ index ++ ] = s; s = new Square( Point2d(i, i), Point2d(i+1, i+2)) ); shapes[ index ++ ] = s; } for ( int i = 0; i < 20; i++ ) shapes[ i ]->draw(); return 0; } Main.cc

18 18 Ereditarietà e riuso del codice Class CenteredShape: public Shape { public: CenteredShape(Point2d c, Color color = TRASPARENT) : center_(c), color_(color) { /*draw();*/ } ~Circle() { /*cancel();*/ } void moveAt( const Point2d& ); void moveBy( const Vector2d& ); void changeColor( Color ); virtual void scale( double ) = 0; virtual void rotate( double ) = 0; virtual void draw() const = 0; virtual void cancel() const = 0; protected: Point2d center_; Color color_; }; CenteredShape.h Non si possono chiamare metodi virtuali in costruttori e distruttori (troppo presto, troppo tardi) #include CenteredShape.hh class Square : public CenteredShape { public: Square( Point2d lowerCorner, Point2d upperCorner, Color col = TRASPARENT) : CenteredShape( median(lowerCorner, upperCorner), col), touc_(upperCorner - center_) { draw(); } ~Square() { cancel(); } virtual void scale( double s ) { cancel(); centerToUpperCorner_ *= s; draw(); } virtual void rotate( double phi ); virtual void draw() const; virtual void cancel() const; private: Vector2d touc_; }; Square.h

19 19 Attenzione alle generalizzazioni... class Rectangle { public: Rectangle(double x0, double y0, double lx, double ly) : lx_(lx), ly_(ly), x0_(x0), y0_(y0) { } void scaleX(double s); void scaleY(double s); protected: double x0_, y0_; double lx_, ly_; }; Rectangle.h Attenzione: scegliere le relazioni di ereditarietà può essere non banale. Un quadrato è un rettangolo? class Square : public Rectangle { public: Square(double x0, double y0, double l) : Rectangle(x0, y0, l, l) { } }; Square.h Avere lx_ e ly_ è ridondante per Square Cosa succede se si invoca scaleX o scaleY ? Avere lx_ e ly_ è ridondante per Square Cosa succede se si invoca scaleX o scaleY ?

20 20 Ereditarietà multipla Una classe può ereditare da più classi class DrawableObj { public: virtual void draw() = 0; }; DrawableObj.h class Shape { public: virtual void scale(double s) = 0; virtual void moveAt( Vector2d& ) = 0; }; Shape.h class DrawableShape : public DrawableObj, public Shape { public: virtual void draw(); virtual void scale(double s); virtual void moveAt( Vector2d& ); }; DrawableShape.h

21 21 Polimorfismo Polimorfismo con tipi controllati dal compilatore Come? In C++ viene implementato tramite il concetto di ereditarietà (inheritance) Classe astratta: definisce i metodi Classe concreta: implementa i metodi La classe concreta eredita da quella astratta


Scaricare ppt "1 Ereditarietà Una classe può essere derivata da una classe esistente usando la sintassi: public, protected e private specificano il tipo di accesso ai."

Presentazioni simili


Annunci Google