1 ereditarietà una classe può essere derivata da una classe esistente usando la sintassi: public,...

Post on 01-May-2015

217 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

Ereditarietà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

Ereditarietà (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

Ereditarietà (3)Ereditarietà (3)• La definizione dell’interfaccia (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

Classi base astratteClassi 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 l’interfaccia di una categoria di classi

virtual func_prototype = 0;

5

Esempio: i soldatiEsempio: 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

list<Soldato> lista;riempiLista(lista);Posizione unaPosizione=...;list<Soldato>::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<Soldato> lista;riempiLista(lista);Posizione unaPosizione=...;list<Soldato>::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

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

Erediarietà multiplaErediarietà multipla• L’ereditarietà 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 un’interfaccia ed una implementazione, ma è molte volte sintomo di un cattivo disegno

class A {. . . .};class B {. . . .};

class AplusB: public A, private B {. . . .};

9

Ereditarietà (4)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.hTrack.h

#include “Track.h”

class DchTrack : public Track{public: int hits() { return hits_->size(); }

DchHit* hit(int n) { return hits_[n]; }

protected: list<DchHit> hits_;};

#include “Track.h”

class DchTrack : public Track{public: int hits() { return hits_->size(); }

DchHit* hit(int n) { return hits_[n]; }

protected: list<DchHit> hits_;};

DchTrack.hDchTrack.h

DchTrack è una Track che ha degli attributi in più (hits_) e nuovi metodi (DchHit* hit(int n), int hits())

10

Esempio: shapeEsempio: shape

• Tutti gli oggetti nella finestra hanno comportamenti comuni che possono essere considerati in astratto:– disegna

– sposta

– ingrandisc

– etc...

11

Cerchi e quadratiCerchi e quadrati

Quadrato Cerchio

12

Circle.h

CerchioCerchio

CostruttoreCostruttore

DistruttoreDistruttore

Nome della classeNome della classe

Punto e virgolaPunto e virgola!!

Point2dPoint2d: classe che rappresenta : classe che rappresenta un punto in 2 dimensioni.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” privatiDati” privati((AttributiAttributi, membri), membri)

class Circle {

};

private: Point2d center_; double radius_;

Interfaccia PubblicaInterfaccia PubblicaMetodiMetodi: operazioni sugli : operazioni sugli

oggettioggetti

13

Cerchio (2)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

Quadrato 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

upperCornerupperCorner

loweCornerloweCorner

centerToUpperCornercenterToUpperCorner__

15

Codice Applicativo (Client)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 Come gestire cerchi e quadrati insieme?e quadrati insieme?

Costruisce un vettore di puntatori a Costruisce un vettore di puntatori a cerchi, crea oggetti in memoria e salva cerchi, crea oggetti in memoria e salva i loro puntatori nel vettore. i loro puntatori nel vettore.

Itera sul vettore e invoca Itera sul vettore e invoca drawdraw()() per ogni elementoper ogni elemento

16

PolimorfismoPolimorfismo

Tutte le Tutte le ShapeShapesshanno la stessa interfaccia:hanno la stessa interfaccia:draw, pick, move, fillColor...draw, pick, move, fillColor...,,ma ogni ma ogni sottotiposottotipo diverso diversopuò avere la usa personalepuò avere la usa personaleimplementazioneimplementazione

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 astrattaInterfaccia astratta

Interfaccia di metodi Interfaccia di metodi puramente virtualipuramente 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

Ereditarietà e riuso del codiceEreditarietà 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.hNon si possono chiamare Non si possono chiamare metodi virtuali in costruttori e metodi virtuali in costruttori e distruttori distruttori (troppo presto, (troppo presto, troppo tardi)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

Attenzione alle generalizzazioni...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 SquareCosa succede se si invoca scaleX o scaleY ?

Avere lx_ e ly_ è ridondante per SquareCosa succede se si invoca scaleX o scaleY ?

20

Ereditarietà multiplaEreditarietà 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

PolimorfismoPolimorfismo

• 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

top related