Corso di Programmazione ad Oggetti



Documenti analoghi
Corso di Programmazione ad Oggetti

Eredità in C++ Corso di Linguaggi di Programmazione ad Oggetti 1. a cura di Giancarlo Cherchi

Programmazione a Oggetti Lezione 10. Ereditarieta

Parola chiave extends

Modulo 4: Ereditarietà, interfacce e clonazione

Inizializzazione, Assegnamento e Distruzione di Classi

Fondamenti di Informatica 1. Prof. B.Buttarazzi A.A. 2010/2011

Introduzione. Java. Composizione. Esempio -- composizione. G. Prencipe È qualcosa che abbiamo già visto varie volte

Esercitazione n 4. Obiettivi

La struttura dati ad albero binario

Progettazione : Design Pattern Creazionali

Oggetti Lezione 3. aspetti generali e definizione di classi I

Relazioni tra oggetti e classi : Composizione. Relazioni tra oggetti e classi : esempio di Aggregazione. classe contenitore

!"#$%&&'()#*%+%+!"#$"',,'()#*%+ -")%*&'&'+'$.)+-$$%&&) !"#$%&&'(%)'*+%",#-%"#.'%&'#/0)-+#12"+3,)4+56#7+#.')8'9

Programmazione a Oggetti Modulo B

12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP)

Generalizzazione di funzioni e di classi. Macro come funzioni generiche

Visibilità dei Membri di una Classe

P a s q u a l e t t i V e r o n i c a

costruttori e distruttori

Corso di Informatica

I puntatori e l allocazione dinamica di memoria

Linguaggi Corso M-Z - Laurea in Ingegneria Informatica A.A Esercitazione. Programmazione Object Oriented in Java

Programmazione a Oggetti e JAVA. Prof. B.Buttarazzi A.A. 2012/2013

Java Virtual Machine

Tipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto:

Programmazione II. Lezione 4. Daniele Sgandurra 30/09/2011.

Java: Compilatore e Interprete

SOMMARIO Coda (queue): QUEUE. QUEUE : specifica QUEUE

Informatica 3. LEZIONE 7: Fondamenti di programmazione orientata agli oggetti (1)

Funzioni in C. Violetta Lonati

Programmazione ad Oggetti Modulo A (Esame del 11/9/2015)

3 - Variabili. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Soluzione dell esercizio del 2 Febbraio 2004

Laboratorio di programmazione

dall argomento argomento della malloc()

Strutture. Strutture e Unioni. Definizione di strutture (2) Definizione di strutture (1)

Monitor. Introduzione. Struttura di un TDA Monitor

Allocazione dinamica della memoria - riepilogo

Definizione di classi con array di oggetti

Object Oriented Software Design

I casi d uso corrispondono ai compiti che l attore (che può essere una persona fisica e non) può svolgere.

Light CRM. Documento Tecnico. Descrizione delle funzionalità del servizio

Database. Si ringrazia Marco Bertini per le slides

Fondamenti di Informatica C Esercitazioni di Laboratorio / 3 Outline

Uso di JUnit. Fondamenti di informatica Oggetti e Java. JUnit. Luca Cabibbo. ottobre 2012

Simulazione traffico urbano


Algoritmi per suddividere il testo in righe in un editor di testo

Realizzazione di una classe con un associazione

Sistemi Operativi MECCANISMI E POLITICHE DI PROTEZIONE. D. Talia - UNICAL. Sistemi Operativi 13.1

MECCANISMI E POLITICHE DI PROTEZIONE 13.1

Indice generale. OOA Analisi Orientata agli Oggetti. Introduzione. Analisi

Esercizi della lezione 5 di Java

13 - Gestione della Memoria nella Programmazione Orientata agli Oggetti

4. Un ambiente di sviluppo per Java

Mac Application Manager 1.3 (SOLO PER TIGER)

Creare una nuova spedizione personalizzata.

Workland CRM. Workland CRM Rel /11/2013. Attività --> FIX. Magazzino --> NEW. Nessuna --> FIX. Ordini --> FIX

Il paradigma OO e le relative metodologie di progettazione. Programmazione orientata agli oggetti

Introduzione alla Programmazione ad Oggetti in C++

FONDAMENTI di INFORMATICA L. Mezzalira

Dynamic Linking. Introduzione Creazione di una libreria dinamica Uso di una libreria dinamica

RIFERIMENTI ATTORI GLOSSARIO. ERRORI COMUNI REV. REQUISITI INGEGNERIA DEL SOFTWARE Università degli Studi di Padova

Programmazione Java: Variabili membro, Metodi La parola chiave final

3 Gestione e stampa casse edili

DINAMIC LIGHT PLUS Principali modifiche introdotte con la versione 4.75 Giugno 2011

Uno dei pregi di Java è quello di integrare la documentazione con il codice stesso Formato dei commenti:

Creare diagrammi di Gantt con Visio 2003

15 - Packages. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Reflection in Java. Linguaggi Corso M-Z - Laurea in Ingegneria Informatica A.A

UML Diagrammi delle classi. UML Diagramma classi 1

Siti web centrati sui dati Architettura MVC-2: i JavaBeans

Gestione Rapporti (Calcolo Aree)

MANUALE PARCELLA FACILE PLUS INDICE

DESIGN PATTERN CREAZIONALI INGEGNERIA DEL SOFTWARE INTRODUZIONE SINGLETON. Scopo dei design pattern creazionali

Object Oriented Programming

Programmazione in Java Parte I: Fondamenti

Cambio Codice IVA (dal 21% al 22%)

Manuale d uso Software di parcellazione per commercialisti Ver [05/01/2015]

Fondamenti di Informatica e Laboratorio T-AB T-16 Progetti su più file. Funzioni come parametro. Parametri del main

Ottava Esercitazione. introduzione ai thread java mutua esclusione

Architettura MVC-2: i JavaBeans

Esercitazione di Basi di Dati

Registratori di Cassa

Concetto di Funzione e Procedura METODI in Java

14 - Packages. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Protezione. Protezione. Protezione. Obiettivi della protezione

Proff. Fabio Ciao e Raffaele Bortone

Realizzazione di Politiche di Gestione delle Risorse: i Semafori Privati

Corso di Sistemi di Elaborazione delle informazioni

ASPETTI GENERALI DI LINUX. Parte 2 Struttura interna del sistema LINUX

GHPPEditor è un software realizzato per produrre in modo rapido e guidato un part program per controlli numerici Heidenhain.

Introduzione alla programmazione in C

Guida Rapida all uso del License Manager di ROCKEY4Smart (V )

Prossime lezioni. Dai TDA agli oggetti. Riassunto. Riassunto TDA. Oggi. Stefano Mizzaro 1

Transcript:

Corso di Programmazione ad Oggetti Il meccanismo dell ereditarietà a.a. 2008/2009 Claudio De Stefano 1

L ereditarietà consente di definire nuove classi per specializzazione o estensione di classi preesistenti, in modo incrementale Il meccanismo dell'ereditarietà è di fondamentale importanza nella programmazione ad oggetti, in quanto induce una strutturazione gerarchica nel sistema software da costruire L ereditarietà consente di realizzare relazioni tra classi di tipo generalizzazionespecializzazione, in cui una classe, detta base, realizza un comportamento generale comune ad un insieme di entità, mentre le classi derivate (sottoclassi) realizzano comportamenti specializzati rispetto a quelli della classe base Esempio: Tipo o classe base: Animale Tipi derivati (sottoclassi): Cane, Gatto, Cavallo, In una gerarchia gen-spec, le classi derivate sono specializzazioni (cioè casi particolari) della classe base 2

e tassonomie Generalizzazione: dal particolare al generale Specializzazione o particolarizzazione: dal particolare al generale Generalizzazione Specializzazione Nel paradigma a oggetti, col meccanismo dell ereditarietà ci si concentra sulla creazione di tassonomie del sistema in esame 3

: esempio Per descrivere un sistema sono possibili tassonomie diverse, a seconda degli obiettivi Oggetto Oggetto Automobile Automobile Benzina Berlina Veicolo Veicolo Diesel Station Wagon Veicolo Veicolo Senza Senza Motore Motore Veicolo Veicolo A Motore Motore Motocicletta Motocicletta Automobile Automobile Aereo Aereo Taxi Taxi 4

e riuso Esiste però anche un altro motivo, di ordine pratico, per cui conviene usare l'ereditarietà, oltre quello di descrivere un sistema secondo un modello gerarchico; questo secondo motivo è legato esclusivamente al concetto di riuso del software In alcuni casi si ha a disposizione una classe che non corrisponde esattamente alle proprie esigenze. Anziché scartare del tutto il codice esistente e riscriverlo, si può seguire con l'ereditarietà un approccio diverso, costruendo una nuova classe che eredita il comportamento di quella esistente, salvo che per i cambiamenti che si ritiene necessario apportare Tali cambiamenti possono riguardare sia l'aggiunta di nuove funzionalità che la modifica di quelle esistenti 5

: vantaggi In definitiva, l ereditarietà offre il vantaggio di ridurre i tempi di sviluppo, in quanto minimizza la quantità di codice da scrivere quando occorre: definire un nuovo tipo che è un sottotipo di un tipo già disponibile, oppure adattare una classe esistente alle proprie esigenze Non è necessario conoscere in dettaglio il funzionamento del codice da riutilizzare, ma è sufficiente modificare (mediante aggiunta o specializzazione) la parte di interesse 6

L esempio mostra come sia possibile derivare dalla classe Shape la classe Circle: L'ereditarietà in C++ I membri pubblici della classe base sono membri pubblici della classe derivata class Shape { public: Shape(Point& location, Color& color); ~Shape(); private: Point location; Color color; }; class Circle : public Shape { public: Circle(Point& location, Color& color, double radius); ~Circle(); private: double radius; }; 7

L accessibilità ai membri della classe base Classe base Public Private public non accessibili Classe derivata La classe derivata ha accesso ai soli membri public della classe base 8

: I membri protected Public Classe base Protected Private class T { public: protected: private: }; non accessibili public accessibili alla sola classe derivata Classe derivata I membri protected sono membri privati che risultano però accessibili alla classe derivata 9

L ereditarietà si presenta in tre distinte forme: class B : public A { }; class B : private A { }; class B : protected A { }; Nell ereditarietà pubblica, i membri ereditati hanno la stessa protezione che avevano nella classe base gli utenti della classe derivata possono usare i membri pubblici ereditati Nell ereditarietà privata, i membri ereditati divengono membri privati della classe ereditata gli utenti della classe derivata non possono usare i membri ereditati Nell ereditarietà protetta, i membri pubblici e protetti ereditati divengono membri protetti della classe derivata 10

Tipo di ereditarietà public protected private Classe base public protected private public protected private public protected private Classe derivata public protected inaccessibile protected protected inaccessibile private private inaccessibile 11

Public Protected Private public Ereditarietà I membri pubblici e protetti della classe base diventano membri pubblici e protetti, rispettivamente, della classe derivata Public Protected Private public Function Class 12

Public Protected Private private Public Protected Private Ereditarietà I membri pubblici e protetti della classe base diventano membri privati della classe derivata public Function Class 13

Public Ereditarietà Protected Private protected Public I membri pubblici e protetti della classe base diventano membri protetti della classe derivata Protected Private public Function Class 14

I costruttori delle classi derivate I costruttori non si ereditano, ma si ridefiniscono nelle classi derivate Poiché l oggetto della classe base deve esistere prima che possa essere trasformato in un oggetto della classe derivata il costruttore della classe base deve essere chiamato per creare l oggetto della classe base prima che il costruttore della classe derivata possa essere chiamato in mancanza di una esplicita chiamata, da effettuarsi nella lista d inizializzazione, il compilatore inserisce la chiamata del costruttore di default della classe base Circle::Circle(Point& loc, Color& color, double rad) : Shape(loc, color), radius(rad) { }; Il costruttore della classe base è invocato al primo posto nella lista d'inizializzazione 15

La regola vale per tutti i costruttori... class DerivedIntArray: public intarray { int zzz; public: DerivedIntArray const& operator=(derivedintarray const &a) { intarray::operator=(a); zzz = a.zzz; return *this; } }; Il costruttore di assegnazione della classe base è chiamato prima ancora di assegnare valore al nuovo dato membro zzz 16

I distruttori delle classi derivate L invocazione del distruttore di una classe derivata produce automaticamente la chiamata di tutti i distruttori delle sue superclassi i distruttori sono chiamati secondo l ordine che si ottiene risalendo via via la gerarchia delle classi Pertanto, il distruttore di una classe derivata non deve invocare esplicitamente il distruttore della classe base, ma deve solo preoccuparsi delle azioni di pulizia relative ai nuovi dati membro introdotti nella classe derivata e ai file aperti dalle nuove funzioni membro della classe derivata 17

L overriding delle funzioni membro Una classe derivata può ridefinire funzioni membro già disponibili a livello della classe base In questo caso, se è utile, la funzione originale è utilizzabile nella ridefinizione, grazie all impiego dell operatore di risoluzione dello scope :: class ComplexPolygon : public Shape { }; bool ComplexPolygon::containsPoint(Point& pt) { if(!shape::containspoint(pt)) return false; // Do the precise check to see if pt is within the polygon } Chiama la funzione membro della classe base Non è una chiamata ricorsiva! Non è la chiamata di una funzione membro statica! 18

Un oggetto di una classe derivata può essere implicitamente convertito in un oggetto della classe base questa operazione di chiama upcasting, perché ci si muove verso l alto nella gerachia delle classi Circle circle(pt, "Red", 5); Shape shape = circle; Un upcasting: l oggetto della classe derivata circle è assegnato all oggetto della classe base shape L upcasting produce però l object slicing, con perdita dei dati membro definiti a livello della classe derivata nell esempio, solo i campi location e color di circle sono assegnati ai corrispondenti campi di shape, e non il campo radius Per evitare l object slicing, l upcasting va usato solo con puntatori e riferimenti 19

Il binding statico è la norma Anche impiegando puntatori e riferimenti, il C++ utilizza il binding statico per le funzioni membro normali la funzione membro invocata è quella associata al tipo statico dell oggetto: class Shape { void draw() const; }; class Circle : public Shape { void draw() const; }; class Square : public Shape { void draw() const; }; class Rectangle : public Shape { void draw() const; }; Shape* sl[3]; sl[0] = new Circle( ); sl[1] = new Square( ); sl[2] = new Rectangle( ); sl[0]->draw(); sl[1]->draw(); sl[2]->draw(); Upcast a Shape* La funzione chiamata è sempre Shape::draw() Il binding dinamico è ottenibile solo rendendo virtual le funzioni membro 20

Il binding dinamico e il polimorfismo Il polimorfismo e il binding dinamico si ottengono solo: dichiarando virtual le funzioni membro operando tramite puntatori e riferimenti Il modificatore virtual è essenziale solo nella classe base Le funzioni membro delle classi derivate sono automaticamente virtual class Shape { virtual void draw() const; }; class Circle : public Shape { virtual void draw() const; }; class Square : public Shape { virtual void draw() const; }; class Rectanglele : public Shape { virtual void draw() const; }; Shape* sl[3]; sl[0] = new Circle( ); sl[1] = new Square( ); sl[2] = new Rectangle( ); sl[0]->draw(); sl[1]->draw(); sl[2]->draw(); Upcast a Shape* Le funzioni chiamate sono di volta in volta diverse: Circle::draw() Square::draw() Rectangle::draw() 21

Solo i puntatori e i riferimenti sono polimorfi Anche usando le funzioni virtuali, il polimorfismo funziona solo se si opera tramite puntatori e riferimenti: Circle c; Shape& s1 = c; Shape* s2 = &c; Shape s3 = c; s1.draw(); s2->draw(); s3.draw(); Chiamano Circle::draw() Chiama Shape::draw() Per le classi che si fondano sulle funzioni virtuali può essere opportuno disabilitare i costruttori di copia e di assegnazione (si opera solo attraverso puntatori) 22

Polimorfismo e flessibilità Il rinvio a tempo di esecuzione della decisione su quale funzione chiamare, rende possibile compilare una funzione che esegue invocazioni di funzioni virtuali anche se la classe derivata che dovrà fornire la funzione non è stata ancora implementata o ancore neanche definita Questa capacità è importante per i produttori di software che progettano librerie il cui sorgente deve rimanere proprietario Un cliente della libreria può sviluppare classi derivate e ottenere che queste usino le funzioni della libreria senza avere alcun bisogno di accedere ai file d implementazione 23

L'implementazione delle funzioni virtuali L uso delle funzioni virtuali produce un piccolo overhead: Per ogni classe polimorfa, esiste a run-time una tabella (v-table), contenente puntatori al codice delle funzioni virtuale Nelle varie classi derivate, ogni funzione (ad esempio draw)) occupa in tutte le v-table la stessa posizione (ad esempio 3) Ogni oggetto di una classe polimorfa ha un puntatore alla v-table Il compilatore traduce la chiamata di una funzione virtuale (ad esempio draw) nella forma chiama la f. virtuale di offset 3 A run-time, si segue il link e si determina il codice da chiamare object vtable ptr data ptr to code ptr to code 01001 01011 11010 01001 01001 01011 11010 01001 data...... vtable 24

Classi polimorfe, costruttori e distruttori Un costruttore non può essere virtuale, in quanto ogni costruttore deve esattamente conoscere la struttura dell oggetto da creare Un distruttore può essere virtuale ed è opportuno che lo sia class Shape { virtual ~Shape(); }; Shape::~Shape() {cout << " there";} Circle::~Circle() {cout << "hello";} Shape *s = new Circle(); delete s; hello there Se i distruttori non sono virtuali si visualizza solo Se i distruttori sono virtuali si visualizza there 25

Le funzioni virtuali pure class Shape { Un distruttore non può essere puro public: Shape(Location const &loc, Color const &color); virtual ~Shape() { }; virtual Location getlocation() const; virtual Color getcolor() const; virtual void draw() const = 0; virtual bool intersect(shape const *shape) const = 0; }; class Circle: public Shape { virtual void draw() const; virtual bool intersect(shape const *shape) const; }; 26