Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Astrazioni in C++
Fondamenti di informatica
Michele Tomaiuolo
tomamic@ce.unipr.it
http://www.ce.unipr.it/people/tomamic
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Generale e particolare
Possibile definire relazioni tra classi (sotto-insieme,
specializzazione) Ball: classe base
Diversi tipi di palle: classi derivate
Ereditano caratteristiche di Ball
Aggiungono caratteristiche specifiche: casualità del rimbalzo, elasticità dell'urto...
Ball
CrazyBall SoftBall ...
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Principio di sostituibilità
La specializzazione è una relazione di tipo is-a
È sempre possibile usare un oggetto di una classe derivata al posto di un oggetto di una classe base
field->add(new Ball());
// …
field->add(new CrazyBall());
field->add(new SoftBall());
// …
field->moveAll();
field->print();
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Metodi e campi ereditati
Classe derivata, definita a partire da classe base:
Eredita tutte le caratteristiche public della classe base Non ha accesso alla sezione private della classe base Può definire nuove caratteristiche (Eckel: is-like-a)
class CrazyBall : public Ball { // additional features
}
Classe base:
Può definire delle caratteristiche protected , a cui solo
lei e le classi derivate possono accedere
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Polimorfismo
Un metodo polimorfo di una classe base è ridefinibile nelle classi derivate
Un tale metodo deve essere dichiarato virtual nella classe base
Occorre una tabella (vtable) che associ il giusto metodo ad un oggetto a runtime
Inoltre, bisogna usare puntatori
Altrimenti slicing: l'oggetto di classe derivata viene convertito nella classe base!
Es. Rendere move ridefinibile
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
#ifndef BALL_H
#define BALL_H class Ball { public:
static const int WIDTH = 16;
static const int HEIGHT = 12;
Ball();
Ball(int x0, int y0, int dx0, int dy0);
int getX();
int getY();
virtual void move();
protected:
int x; int y;
int dx; int dy;
};
#endif
Metodi virtual
virtual, così può essere ridefinito dalle sotto-classi
virtual, così può essere ridefinito dalle sotto-classi
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
#ifndef CRAZYBALL_H
#define CRAZYBALL_H
#include "ball.h"
class CrazyBall : public Ball { public:
CrazyBall();
CrazyBall(int x, int y, int dx, int dy, int randomness);
void move();
private:
int randomness; // in percent };
#endif
Classe CrazyBall
Ball
CrazyBall
- randomness : int + move() : void
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
#include "crazyball.h"
CrazyBall::CrazyBall() : Ball() { randomness = 0;
}
CrazyBall::CrazyBall(int x, int y, int dx, int dy, int randomness)
: Ball(x, y, dx, dy) {
this->randomness = randomness;
}
void CrazyBall::move() {
if (x+dx < 0 || x+dx >= WIDTH) { dx = -dx;
if ((rand() % 100) < randomness) { dy = rand() % 2 – 1;
// ...
Implementazione
Sezione di inizializzazione dopo i “:” e prima del corpo Sezione di inizializzazione dopo i “:” e prima del corpo
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
#include "ball.h"
#include "crazyball.h"
int main() {
Ball* b1 = new Ball(8, 4, +1, +1);
Ball* b2 = new CrazyBall(4, 8, -1, +1);
b1->move(); // the method of Ball
b2->move(); // the method of CrazyBall!
}
Se move non fosse virtual, sarebbe eseguito
il metodo di Ball Se move non fosse virtual, sarebbe eseguito
il metodo di Ball
Applicazione
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Distruttori virtual e costruttori
In caso di polimorfismo, la classe base deve sempre dichiarare virtual il suo distruttore, altrimenti...
Eseguito sempre e solo il distruttore della classe base Non quello giusto, della classe derivata
Liberate risorse della classe base, non della derivata
I costruttori non vengono ereditati
Non inizializzano gli attributi aggiunti in classe derivata
Ma necessario eseguire costruttore della classe base
Costruire prima le caratteristiche della classe base...
poi quelle della classe derivata
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Sezione di inizializzazione
Precede il corpo di un costruttore
Indicare un costruttore della classe base
(altrimenti, scelto quello senza parametri, se c'è...) Inizializzare gli attributi (più efficiente)
Necessario inizializzare costanti di istanza e oggetti membri (altrimenti costruiti senza parametri...)
Oggetti nello heap: new nel corpo del costruttore
CrazyBall::CrazyBall(int x, int y, int dx, int dy, int r) : Ball(x, y, dx, dy), randomness(r) {
/* intentionally empty*/
}
Sezione di inizializzazionedopo i “:” e prima del corpo Sezione di inizializzazione dopo i “:” e prima del corpo
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Clausola protected
Per metodi e attributi accessibili solo dalla classe e dalle derivate
Non visibili all’esterno della classe, come se fossero privati
Ma visibili alle sue classi derivate
Da usare con cautela; solo per caratteristiche…
Che non conviene rendere pubbliche:
campi incapsulati, o servizi non significativi
Ma potenzialmente utili a chi estende la classe
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Classe astratta
Contiene alcuni metodi astratti (senza implementazione)
Saranno implementati dalle sue sotto-classi Informazioni non sufficienti nella classe base
Meccanismi specifici per implementare un metodo
…
Una classe astratta non può essere istanziata
Classe astratta pura, o interfaccia: contiene solo
metodi astratti
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
class MovingObject { public:
virtual void move() = 0;
virtual int getX() = 0;
virtual int getY() = 0;
}
MovingObject
MovingObject
+ getX() : int + getY() : int + move() : void
Stone Ghost Ball
Tutti i metodi sono virtuali puri → La classe
è detta “astratta pura”, o “interfaccia”
Tutti i metodi sono virtuali puri → La classe
è detta “astratta pura”, o “interfaccia”
Se uno dei metodi è virtuale puro → La classe
è “astratta”, non può avere istanze dirette
Se uno dei metodi è virtuale puro → La classe
è “astratta”, non può avere istanze dirette
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
class Ghost : public MovingObject { public:
Ghost(int x, int y,
int width, int height);
int getX();
int getY();
void move();
private:
int x; int y; int width; int height;
}
Ghost::Ghost(int x, int y, int width, int height) {/*…*/}
int Ghost::getX() { return x; } int Ghost::getY() { return y; } void Ghost::move() {
int dx = rand() % 3 – 1; x = (x + dx + width) % width;
int dy = rand() % 3 – 1; y = (y + dy + height) % height;
}
Classe Ghost
Definizione della classe: file ghost.h
Definizione della classe: file ghost.h
Implementazione dei metodi: file ghost.cpp Implementazione dei metodi: file ghost.cpp
Le classi derivate devono implementare tutti
i metodi virtuali puri Le classi derivate devono implementare tutti
i metodi virtuali puri
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Astrazione e riusabilità
Strutture dati ed algoritmi, in Field, possono essere implementati sulla classe MovingObject
Per il movimento e la posizione, si sfrutta il fatto che tutti gli oggetti MovingObject hanno i metodi necessari
move, getX, getY
Dati e algoritmi definiti in funzione della classe:
più alta nella gerarchia (più astratta), che offra le caratteristiche richieste
→ Massimizzazione di riusabilità e flessibilità
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
class Field { public:
Field(int width, int height);
~Field();
void add(MovingObject* obj);
void moveAll();
void print();
private:
int width;
int height;
vector<MovingObject*> objects;
char getSymbol(int x, int y);
}
Campo da gioco generico
MovingObject Field
1
*
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
const int W = 16, H =12;
Field* field = new Field(W, H);
field->add(new Ball(4, 8, +1, +1, W, H));
field->add(new Ghost(12, 4, W, H));
field->print();
string line;
while (getline(cin, line)) { field->moveAll();
field->print();
}
delete field;
Oggetti in movimento
Fill a field with
objects Fill a field with
objects
Move objects
Move objects
Delete field and
Delete field and
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Quando usare l'ereditarietà? Due fasi diverse:
Nella fase di analisi per modellare il problema
Nella fase di progettazione, per modellare la soluzione e massimizzare il riuso, tramite astrazione
… Progetto delineato a partire dal modello di analisi
Classe derivata usata allo stesso modo e al posto della sua classe base?
Eckel: ereditarietà o composizione?
“Do I need to upcast?”
Progettare tramite astrazioni
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Massimizzare il riuso
Ereditare codice e dati di una classe esistente
Ma si eredita anche l'interfaccia!
Es. Circle estende Point e aggiunge radius?
No, per questo scopo è meglio usare la composizione Relazione: is-a oppure has-a?
Riusare e specializzare un intero sistema esistente, mediante la realizzazione di certe classi astratte
Si progetta il sistema ad alto livello di astrazione
Poi si aggiungono nuove classi specializzate
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Ereditarietà C++ vs. Java
Ereditarietà multipla tra le classi C++
Una classe può avere più classi base dirette
Java: ereditarietà singola + interfacce
Non esiste una classe radice, da cui tutte le classi implicitamente derivano
Java: Object , base di tutte le classi
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Classe astratta pura: solo metodi pure virtual
Insieme delle signature dei metodi pubblici
Senza corpo dei metodi, senza implementazione Classe MovingObject: in effetti una interfaccia
Modello più “pulito”, attenzione ai servizi
Cosa un oggetto sa fare, non come lo fa Possibilità di migliorare la riusabilità
La classe di implementazione sceglie come memorizzare lo stato ed implementare i metodi
No “diamond problem”...
Interfacce
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/
Ereditarietà multipla
Un veicolo anfibio è contemporaneamente…
Un veicolo terrestre Un veicolo acquatico
Una classe AmphibiousCar dovrebbe estendere sia Car che Motorboat
Se ereditarietà multipla...
Quale stato usare?
Quali metodi eseguire?
“Diamond problem”
olo – Fondamenti di informaticaolo – Fondamenti di informatica neria dell'informazione – UniPRneria dell'informazione – UniPR .ce.unipr.it/people/tomamic/.ce.unipr.it/people/tomamic/
Interfacce per veicoli
Vehicle
Car Motorboat Bicycle
ConcreteBicycle ConcreteMotorboat
AmphibiousCar
ConcreteCar
Tomaiuolo – Fondamenti di informaticaTomaiuolo – Fondamenti di informatica . Ingegneria dell'informazione – UniPR. Ingegneria dell'informazione – UniPR p://www.ce.unipr.it/people/tomamic/p://www.ce.unipr.it/people/tomamic/