Introduzione alla
programmazione ad oggetti
E.Mumolo, DEEI
[email protected]
1
Paradigmi di programmazione


È un punto di vista della programmazione
Alcuni paradigmi

Programmazione imperativa (lista di istruzioni da eseguire,
es. Fortran, C, C++, Java ….)






Programmazione non strutturata
Programmazione strutturata
Programmazione dichiarativa (condizioni logiche, es.
Prolog, Lisp …)
Programmazione procedurale
Programmazione ad oggetti
…
2
Architetture software

Programmazione procedurale
Funzione principale
Sotto-funzione 1
Sotto-funzione 1.1
Sotto-funzione 1.2
Sotto-funzione 2
Sotto-funzione 2.1
Sotto-funzione 2.2
3
Programmazione non strutturata

Problema:
if(90<A<100)and(25<B<100)or(80<A<89)and(50<B<100)or(70<A<79)and(75<B<100) then “ACCETTA”

Usando GOTO:
SI
A>90
SI
SI
A>80
B>25
SI
SI
A>70
B>50
SI
B>75
Non accetta
accetta
4
Programmazione strutturata

Codice realizzato mediante combinazione di
tre strutture

Tutti gli algoritmi possono essere realizzati
mediante le tre strutture
5
Programmazione strutturata
SI
A>90
SI
SI
A>80
B>25
SI
SI
A>70
B>50
SI
B>75
N
N
A N
A
N
A
6
Programmazione strutturata - pseudocodice
if(A>90)
then
if(B>25)
then
Accetta
else
Nonaccetta
fi
else
if(AZ80)
then
if(B>50)
then
Accetta
else
Nonaccetta
fi
else
if(A>70)
then
if(B>75)
then
Accetta
else
Nonaccetta
fi
fi
fi
fi
7
Programmazione procedurale


Modello procedurale
 Il mondo della programmazione viene visto come un sistema di
processi
Alcuni temi tipici del modello procedurale:
 Processi, sequenze di esecuzione
 Diagrammi di flusso
 Programmazione top-down
 Programmazione strutturata
 Algoritmi=strutture dati + programmazione strutturata
 Tradizionali linguaggi strutturati: Fortran, Pascal, C …
 Operazioni effettuate sui dati inviate alle procedure e alle
funzioni sistemi software validi ed efficienti per basse
complessità
MA : ad alte complessità si evidenzia un cedimento del sistema
 Una modifica di una struttura dati ha grandi effetti sul sistema
 campo di visibilità delle strutture dati
 Riusabilita’ nei linguaggi procedurali
8
Esempio: conto corrente

Programmazione procedurale:

Decomposizione funzionale del problema


Divisione del problema in moduli
Progetto struttura dati, esempio:
…

Numero correntista
Nome correntista
Saldo
Numero operazioni
ID correntista
…
Implementazione delle funzioni per operare con i dati,
esempio:




Deposito(ID,#)
Preleva(ID,#)
CalcolaInteressi(ID)
…
9
Approccio orientato agli oggetti: OOA




metodologia generale
pensare e rappresentare problemi usando
concetti del mondo reale
oggetti: rappresentano proprietà e
comportamenti in una unica entità
I modelli possono essere implementati
usando un linguaggio di programmazione, un
sistema di gestione di archivi, in hardware
etc…
10
Alcune differenze tra OO e procedurale




OOP  dati e comportamento contenuti in un
oggetto singolo
Procedurale  dati e comportamento separati
OOP  divide il problema in oggetti separati che
realizzano azioni relazionandosi con altri oggetti
Vantaggi proncipali di OOP:




Dati e operazioni incapsulati in un oggetto
Quando viene creato un nuovo tipo di oggetto, non è
necessario modificare le implementazioni precedenti
Piuttosto, il nuovo oggetto eredita alcune caratteristiche
precedenti
Programmi OO sono di più semplice manutenzione
11
Esempio: conto corrente

Programmazione procedurale:

L’attenzione del programmatore è concentrata sulle
funzioni che manipolano i dati!
Punto di vista tradizionale:
valore=CalcolaInteressi(ID);
valore di ritorno


funzione
argomento
Ma: l’attenzione di un correntista è più concentrata sui dati
che sulle funzioni!
Inoltre:


Chiunque può modificare i dati (se i dati
sono visibili)
Funzioni e dati entità separate
12
Esempio: conto corrente

Programmazione ad oggetti:




L’attenzione del programmatore è concentrata sui dati non sulle funzioni
Dati e funzioni NON sono entità separate
programma ad oggetti: insieme di oggetti cooperanti, che sono istanze di un
tipo di dati astratto
Esempio di tipo di dati astratto per gestire un conto corrente:
ContoCorrente
Numero correntista
Nome correntista
Saldo
Numero operazioni
deposita(valore)
preleva(valore)
calcolaInteressi()
incrementaNumeroOperazioni
leggiNumeroOperazioni()
dati
funzioni
13
Esempio: conto corrente

Programmazione ad oggetti:


Un particolare Conto Corrente è una ‘istanza’ del tipo do dati
astratto
Le funzioni sono attivate mediante messaggi.
Punto di vista ad oggetti:
valore=ID  CalcolaInteressi();
valore di ritorno

oggetto
funzione
messaggio
Un particolare ContoCorrente: cosa è visibile dall’esterno?
Dati e funzioni pubbliche:
Deposita
Preleva
leggiNumeroOperazioni
Oggetto:

ContoCorrente
CalcolaInteressi
 interfaccia
Dati privati:
Numero correntista
Nome correntista
Saldo
Dati protetti: numero operazioni
14
Esempio: conto corrente

Utilizzo dell’oggetto:
Messaggio:
‘deposita(x)’
oggetto
ContoCorrente
Messaggio:
‘leggiNumeroOperazioni()’
15
Cenni di UML


UML è un linguaggio (Unified Modeling
Language)
Fornisce i costrutti per lo sviluppo di sistemi
software:





Analisi dei requisiti
Analisi e progetto OO
Modellazione dei componenti
Modellazione della struttura e della configurazione
Modello espresso mediante diagrammi grafici
16
Cenni di UML

Diagrammi di UML







Diagramma dei casi d’uso: elenca i casi d’uso del sistema
e le loro relazioni
Diagramma delle classi: struttura dati degli oggetti e loro
relazioni
Diagramma degli oggetti: mostra un insieme di oggetti e
loro relazioni
Diarammi di interazione: interazioni tra gli oggetti durante
scenari di funzionamento
Diagrammi di stato e attività: descrive gli stati di un oggetto
e le sequenze eventi-azioni-transizioni
Diagramma dei componenti: descrive l’architettura fisica
del sistema
Diagramma di distribuzione: struttura del sistema hardware
e allocazione dei vari moduli software
17
Cenni di UML

Diagrammi dei casi d’uso:



Rappresentano le modalità di utilizzo del sistema da parte
degli attori del sistema
Descrivono l’interazione tra attori e sistema, la logica
interna
Un attore



Spedisce o riceve messaggi dal sistema, o scambia
informazioni con esso
Esegue i casi d’uso (funzionalitè percepita da un attore, e
sempre attivato da un attore)
Corrisponde ad una classe, non ad un oggetto
18
Cenni di UML

Diagramma dei casi d’uso in una biblioteca
restituzione
Attore: il bibliotecario
prestito
Cancella la prenotazione
Attore: il cliente
prenota
19
Simboli usati per la visibilità
UML
Tool di Reverse eng.
ContoCorrente
-Numero correntista
-Nome correntista
-Saldo
#Numero operazioni
+deposita(valore)
+preleva(valore)
+calcolaInteressi()
-incrementaNumeroOperazioni
+leggiNumeroOperazioni()
• Tipo di dati astratto=classe
• istanza di un tipo di dati astratto = oggetto
• incapsulamento = data hiding = fornisce un livello di astrazione attraverso le funzoni
 Non c’è struttura dati separata: operazioni e struttura dati integrate in una singola
entità
20
Modelli orientati agli oggetti

Modello ad oggetti
 Il mondo viene visto come un sistema di cose
Comportamento visibile
Un oggetto
Stato interno nascosto
Oggetto = stato + comportamento + identità
21
Esempio di organizzazione per oggetti
Oggetto automobile
Oggetto Carrozzeria
Oggetto Motore
peso = carrozzeriapeso() + motorepeso()
peso = automobile  peso()
22
Le classi

Classificazione:




Oggetti con gli stessi attributi e con gli stessi
comportamenti sono raggruppati in classi
Classe astrazione che descrive delle proprietà
Una classe descrive un insieme di oggetti
individuali.
Un oggetto è una istanza della classe


Ogni istanza ha valori diversi degli attributi
Le istanze di una classe condividono i nomi degli
attributi e le operazioni
23
Approccio orientato agli oggetti

Esempio di classi:

PezzoScacchi (una Torre è un oggetto della classe)



Poligono (un Triangolo è un oggetto della classe)



Attributi:

Colore, Altezza, Posizione
Operazioni:

Muove
Attributi:

Vertici, ColoreBordi, ColoreInterno
Operazioni:

Disegna, Cancella, Muove
Bicicletta (la mia bicicletta è un oggetto della classe)


Attributi:

DiametroRuote, Altezza, Materiale
Operazioni:

Muove, Ripara, Pulisci
24
Passi per la modellazione OO




Identificare gli oggetti
Identificare il comportamento degli oggetti
Identificare le relazioni tra gli oggetti
Realizzare gli oggetti: raggruppare in classi le strutture
dati ed i comportamenti
25
Approccio orientato agli oggetti

Caratteristiche di un oggetto:



Attributi (struttura dati)
Comportamento
Caratteristiche richieste da un approccio
orientato agli oggetti:



Identità
Polimorfismo
Ereditarietà
(identity)
(polymorphism)
(inheritance)
26
Approccio orientato agli oggetti

Identità:




oggetti distinti: ogni oggetto ha la sua identità anche se i
loro attributi sono identici
Oggetti: entità concrete (es. un file in un file system) o
concettuali (es.: una politica di schedulazione)
Oggetti del mondo reale (esempio): due mele – anche se
dello stesso colore e forma sono due oggetti distinti -, due
gemelli, una persona, un oscilloscopio …
Oggetti definiti mediante un linguaggio di programmazione
(esempio): un albero binario, una tabella …
27
Approccio orientato agli oggetti

Polimorfismo:





La stessa operazione si comporta diversamente in
diverse classi (es. operazione Muovi nella classe
PezzoScacchi e Bicicletta).
La specifica implementazione di una operazione è
chiamata metodo.
Polimorfismo=diversi metodi per operatore
In un linguaggio orientato agli oggetti il linguaggio
seleziona automaticamente il metodo corretto
L’utente può non conoscere quanti metodi
implementano un operatore
28
Approccio orientato agli oggetti

Ereditarietà:





Creazione di una gerarchia tra le classi
Metodo di progetto bottom-up: una super-classe
viene definita in modo generico e poi viene
perfezionata via via in sotto-classe
La super classe fattorizza le proprietà comuni di
diverse classi
Una sotto-classe eredita tutte le proprietà della
sua superclasse e aggiunge altre proprietà
Normalmente le proprietà della superclasse non
sono ripetute in ogni sottoclasse
29
Caratteristiche fondamentali

Astrazione



Caratteristiche essenziali di una entità
Prima di implementare un oggetto, chiedersi cos’è
e cosa fa’
Incapsulamento



Chiamato anche ‘Information Hiding’
Separazione degli aspetti esterni (accessibili da
oggetti esterni) dalla implementazione interna
(nascosti ad oggetti esterni)
Rende i programmi robusti dalle piccole variazioni
30
Caratteristiche fondamentali

Combinazione dei dati e dei comportamenti




Approccio convenzionale: procedurale
 Gerarchia delle strutture dati
 Gerarchia delle procedure
OOA ha una gerarchia unificata
 Gerarchia delle classi
 manutenzione più semplice: il codice non deve essere
modificato quando viene aggiunta una classe
Importanza del polimorfismo: sposta il problema di
decidere l’implementazione da usare alla gerarchia
delle classi

Esempio: per disegnare in una finestra, basta chiamare un
ipotetico metodo draw. Il metodo corretto viene scelto
implicitamente
31
Vantaggi della programmazione ad oggetti





Protezione delle strutture dati
 Incapsulamento – information hiding
Maggiore semplicità di progettazione astratta
 progettazione top-down e bottom-up, gerarchia di classi
 composizione delle classi come mattoni fondamentali
Migliore riutilizzazione del codice
 composizione, aggregazione, derivazione
Migliore manutenzione del codice
 le modifiche sono realizzate mediante aggiunta di classi e
funzioni virtuali – non è necessario riprendere e modificare
l’intero codice
Migiore documentazione del codice
 Strumenti grafici del tipo UML
32
Modelli orientati agli oggetti

Diagrammi delle classi e delle istanze
Giulio:Persona
Carla : Persona
Persona
Giulio:Persona
Carla : Persona
Nome: string
Età: integer
Peso: float
nome=Giulio
eta=24
peso=70.1
nome=Carla
eta=25
peso=??
Persona

:Persona
Attributi
33
Modelli orientati agli oggetti

Nei diagrammi delle classi:
File
Persona
Nome
Indirizzo
Lavoro
Nome
Dimensione
Data_creazione
Cambia_lavoro
Cambia_indirizzo

Oggetto geometrico
Colore
Posizione
print
Notazione:
move(vettore delta)
Select(point p):boolean
Ruota(angolo)
Nome della classe
Nome attributo:tipo di dato-1=valore default
Nome attributo:tipo di dato-2=valore default
…
Nome operazione-1 (argomenti):tipo risultato
Nome operazione-2 (argomenti):tipo risultato
…
34
Modelli orientati agli oggetti

Operazioni e metodi
 Funzioni o trasformazioni applicate agli oggetti della classe
 Tutti gli oggetti della classe condividono le stesse operazioni
 Ogni operazione opera su un oggetto che può essere implicito o
esplicito
 Un metodo è l’implementazione di una operazione
 Esempio: classe File, operazione print, metodi per stampare
file ASCII, binari etc.
 Polimorfismo: un modo per scegliere il metodo è legato al
numero e tipo degli argomenti (sovrapposizione=overloading)
 Esempio: print(file_name) vs. print(file_pointer)
 Polimorfismo: il metodo è scelto sulla base dell’oggetto
(aggiramento=overriding)
35
Un primo metodo: il costruttore della classe






Inizializza le variabili
Ciclo di vita di una variabile locale: nello ‘scope’ in cui e’ definita
Ciclo di vita di una variabile dinamica: programma
Quando viene generata una variabili di tipo classe, si attiva
automaticamente una funzione che inizializza le variabili della classe:
costruttore
Quando la variabile termina il suo ciclo di vita viene attivata
automaticamente -se disponibile- una funzione di eliminazione:
distruttore (ad esempio delete di variabili nella memoria libera)
Costruttore: funzione con lo stesso nome della classe





non richiede tipo di ritorno
puo’ avere una lista di argomenti di inizializzazione
attivata automaticamente quando si crea un'oggetto con new
sono possibili costruttore diversi, che devono avere liste di argomenti
diversi
costruttore di default: senza argomenti.
36
Relazioni tra oggetti e classi

Collegamenti e associazioni


Associazione: gruppo di collegamenti con struttura comune
Vengono lette in una particolare direzione:
Stato
nome




HaCapitale
CapitaleDi
Città
Diagramma delle classi
nome
I nomi indicano il ruolo di una classe all’interno di una
associazione
Si interpreta: Stato - HaCapitale - Città
Un collegamento è una istanza di una associazione
Tipicamente realizzati mediante puntatori
37
Relazioni tra oggetti e classi: associazione

Molteplicità del ruolo della classe

Descrive quante istanze di una classe possono relazionarsi ad
una singola istanza della classe associata

Simboli terminatori:







1
0..1
M..N
*
0..*
1..*
 uno e solo uno
 zero o uno (opzionale)
 da M a N
 0 o più (molti)
 0 o più (molti)
 1 o più (molti)
Esempio: punti di intersezione su una linea. Associazione molti-amolti.
Punto
Linea
2..*
nome

*
nome
Si interpreta:

Linea si relaziona con molti Punti; Punto si relaziona con 2 o più Linee
38
Relazioni tra oggetti e classi: associazione
marito
Società
Nome
indirizzo
*
1
Persona
Persona
Nome
impiegato Indirizzo
Codice fiscale
Data di nascita
Datore
lavoro
dirigente
Nome
Indirizzo
0..1 Codice fiscale
Data di nascita
*
persona
poligono
1..*
*
possiede
*
ha lati
3..*
casa
1..*
0..1
Situata in
*
linea
0..1
2
0..1
moglie
dipendente
città
punto
39
Relazioni tra oggetti e classi: associazione n-aria

Esempio di diagramma delle classi
Libro
-id
+inserisci
+rimuovi
+cerca
Titolo
-nome
-autore
-isbn
-numeroPrenotazioni
+inserisci
+rimuovi
+cerca
0..*
0..1
Rivista
-durataPrestito
Prestito
Data=dataCorrente
+inserisci
+rimuovi
+cerca
0..*
0..*
Cliente
Nome
Indirizzo
Cerca
Inserisci
rimuovi
Prenotazione
-Data=dataCorrente
+inserisci
+rimuovi
+cerca
0..*
40
Relazioni tra oggetti e classi: associazione n-aria


Le associazioni binarie legano due classi.
Una classe può legarsi a n classi  associazione
+
n-aria. Simbolo:
1
1..*
Insegnante
studenti
Corso
Data_inizio
Data_fine
1
*
1
Giorno e ora
Aula
Lezione
argomento
41
Relazioni tra oggetti e classi

Aggregazione: Esprime la forza della associazione o
tra classi. Simbolo:


Puramente logico
Sia il tutto che le parti esistono indipendentemente
genitore
Persona
0..2


figlio
*
Persona
Asimmetrico, bidirezionale, transitivo
Composizione: più forte della aggregazione.
Simbolo:

Le parti esistono solo in relazione al tutto
Automezzo
1
1
Motore
42
Aggregazione
• Rappresenta un tipo di contenimento tra classi
• Contenimento lasco: B = contenitore, A = contenuto
•Contenimento lasco:
• ciclo di vita oggetto contenuto e contenitore indipendenti
• il contenitore non è responsabile della creazione e
della distruzione dell’oggetto
• si realizza mediante un puntatore al contenuto
• il coordinatore dell’aggregazione deve:
•Creare oggetto contenuto
•Definire e inizializzare un puntatore ad esso
•Costruire oggetto contenitore passando puntatore al contenuto
43
Composizione
• Rappresenta un tipo di contenimento tra classi
• Contenimento stretto: B = contenitore, A = contenuto
• l’oggetto contenuto non ha una vita propria
• l’oggetto contenitore è responsabile della costruzione e distruzione
• si realizza con un oggetto contenuto interno al contenitore
• è responsabilità del coordinatore
• creare l’oggetto contenitore
• fornire valori oggetto contenuto
• il compilatore richiama il costruttore e il distruttore del contenuto
44
Confronto tra contenimento e derivazione

Consideriamo i due casi:




Interfacce:



La classe B contiene la classe A (contenimento)
La classe B è derivata dalla classe A (ereditarietà)
In entrambi i casi l’oggetto B contiene l’oggetto A
Contenimento: l’interfaccia di A e B indipendenti
Derivazione: interfaccia di B comprende quella di A
Ereditarietà più forte del contenimento:



B può eseguire overriding delle funzioni di A
Un puntatore a B può essere assegnato a puntatore a A
Un oggetto B può essere assegnato ad un oggetto A
45
Esempio di aggregazione tra classi
Automobile
Marca : stringa
Modello : stringa
Velocità : float
Accelerazione : float
MuoviAvanti()
MuoviIndietro()
MarciaSu()
Avvia()
•Carrozzeria e Motore hanno vita propria!!
•Ogni istanza di Automobile ha una
Carrozzeria e un Motore
 Contenimento LASCO
Carrozzeria
NumeroSerie : stringa
Colore : enum […]
Peso : float
Motore
NumeroSerie : stringa
Marca : stringa
NumeroValvole : enum[…]
NumeroCilindri : enum[…]
Peso : float
Start : Boolean
46
Associazioni tra classi

Associazione uno-a-uno
associazione

Come si realizza?



Con un puntatore alla classe associata
Ogni classe ha un metodo ‘collegati al partner’
Il coordinatore:



Crea oggetti a e b
Collega a con b
Collega b con a
47
Associazioni tra classi
• Associazione uno a uno con indicazione dei ruoli
associazione
Ruolo di A
Ruolo di B
• Associazione uno a molti
associazione
• Ad un oggetto della classe A corrispondono più
* oggetti della classe B
• Ad un oggetto della classe B corrisponde un oggetto di A
• Nella classe A c’è una lista di puntatori alla classe B
• lista statica se si conosce il numero massimo di oggetti
• altrimenti  lista dinamica
48
Associazioni tra classi

Esempio: associazione Persona-Automobile
coproprietario
possiede
guida
pilota
0..1
0..1
vettura
• l’associazione ‘possiede’ ha
-Molteplicità 1 a (0..1)
una persona possiede 0 o 1 automobile
Una automobile è posseduta da 1 persona
Direzionalità: da Persona a Automobile
(Automobile non ha traccia della associazione)
49
Associazioni tra classi

l’associazione ‘guida’ ha

Molteplicità 1 a (0..1)




una persona può guidare 0 oppure 1 automobile
Una automobile è guidata da 1 persona
Direzionalità: bidirezionale (Automobile e persona hanno
traccia della associazione ‘guida’)
l’associazione ‘coproprietario’


Riflessiva
Molteplicità 0..1 a 0..1
50
Relazioni tra oggetti e classi

Molteplicità (esempi)
Persona
coordinatore
dipendente
Persona
nome
indirizzo
nome
indirizzo
Persona
=
coordinatore
nome
indirizzo
dipendente
valutazione
valutazione
Azienda
Persona
nome
indirizzo
nome
indirizzo
Stipendio
mansione
File
Utente
nome
nome
Permessi
51
Esempio (I)

Dato il seguente diagramma degli oggetti
tracciare il corrispondente diagramma delle
classi
Punto
-10
10
Punto
10
10
Poligono
Punto
-10
-10
Punto
10
-10
52
Soluzione esempio (I)

Diagramma delle classi
Poligono

3..*
Punto
x:coordinata
(ordinata) y:coordinata
Note:


Il più piccolo nr di punti = 3
Associazione ‘ordinata’ = indica che i punti sono in
sequenza
53
Esempio (II)

Diagramma degli oggetti per due triangoli con
un lato in comune

Se un punto appartiene ad un solo triangolo
Punto
0,1
Punto
-1,0
Poligono
Punto
1.0
Punto
0,-1
Punto
-1,0
Poligono
Punto
1.0
54
Esempio (III)

Se un punto appartiene ad uno o più triangoli
Punto
0,1
Poligono
Punto
-1,0
Poligono
Punto
1.0
Punto
0,-1
55
Esempio (IV)

Diagramma ad oggetti per descrivere grafi
non orientati
Grafo non orientato
0..*
0..*
0..*
Vertice
nome del vertice
2
Lato
nome del lato
56
Esempio (V)

Diagramma ad oggetti per descrivere grafi
orientati
Grafo orientato
0..*
Vertice
nome del vertice
0..*
da
a
0..*
Lato
nome del lato
0..*
57
Linguaggi di programmazione a oggetti

C++ (Stroustrup ‘83)


Ispirato principalmente da Simula67
Java
1.
2.
3.
4.
5.
6.
7.
8.
JDK 1.0 (January 23, 1996)
JDK 1.1 (February 19, 1997)
J2SE 1.2 (December 8, 1998)
J2SE 1.3 (May 8, 2000)
J2SE 1.4 (February 6, 2002)
J2SE 5.0 (September 30, 2004)
Java SE 6 (December 11, 2006)
1.
Java SE 6 Update 10
Java SE 7
58
Integrated Developments Environments



Eclipse
http://download.netbeans.org/netbeans/6.1/fi
nal/
Jbuilder
59
Riferimenti (specificatore &)





sinonimi (alias) per lo stesso oggetto
il tipo dell’oggetto determina il tipo del riferimento
puo’ essere visto come un tipo speciale di puntatore
deve essere inizializzato e agisce solo su un oggetto
uso principale: argomenti e risultati di una funzione
//oop3.cpp
#include <iostream.h>
main(){
float p;
float &rp=p;
//rp=riferimento a p (alias di p)
//
}
p=3.14;
rp=6.28;
cout << "p =" << p << " rp=" << rp << '\n';
const float &rp1=p; //rp1 e' alias di p, ma l'oggetto riferito e' costante
//rp1 non puo' modificare l'oggetto
rp1=3.1; ILLEGALE: non si puo' modificare un oggetto costante!
cout << "rp1=" << rp1 <<'\n';
Output:
p =6.28 rp=6.28
rp1=6.28
60

Uso dei riferimenti come argomenti e risultati di funzione
senza passare esplicitamente l’indirizzo
//opp4.cpp
#include <iostream.h>
int incrementa(int &val)
{
val++;
if(val>65000) val=65000;
return 0;
}
int incrementa(int &val, int v)
{
int t=v;
t++;
if(t>65000) t=65000;
return t;
}
main()
{
int i=7;
cout << " i=" << i;
incrementa(i);
cout << " i=" << i << " i=" << incrementa(i,i) << " i=" << i << '\n';
}
Output: i=7 i=8 i=9 i=8
61
//Altri esempi di alias
#include <iostream.h>
//oop5.cpp
void scambia(int &rx, int &ry)
{
int t=rx;
rx=ry; ry=t;
}
main()
{
int x=20; int y=30;
cout << "x, y =" << x << ' ' << y;
scambia(x,y);
cout << "x, y =" << x << ' ' << y;
}
//oop6.cpp *************************************************************
#include <iostream.h>
int &max(int &a, int &b)
{
if(a>=b) return a;
return b;
}
main()
{
int x, y;
cin >> x >> y;
cout << " il massimo tra " << x << " e " << y << "e' " << max(x,y);
}
Altra versione:
int &max(const int &a, const int &b)
{
if(a>=b) return (int &)a;
//il casting e’ necessario per via di const
return (int &)b;
}
62
Argomenti di default in una funzione
//opp7.cpp
#include <iostream.h>
void build(float *val, int size=10)
{
for(short i=0; i<size; i++) val[i]=(float)i; }
main() {
float A[100];
int N=10;
}


build(A); //non e' necessario usare build(A,N): viene usato il valore di default
for(short i=0; i<10; i++) cout << A[i] << ' ';
specificatore “inline”: inline void funzione(..) sostituisce il codice della
funzione alle chiamate di funzione. : attenzione alla crescita delle dimensioni del
codice!
campo di visibilità delle dichiarazioni:







identificatori: dalla dichiarazione fino alla fine della funzione
identificatori globali sono visibili dalla dichiarazione alla fine del file
identificatore locale maschera un identificatore globale con un stesso nome
Scope o operatore di visibilità “::”  specifica la variabile da utilizzare
identificatori locali non sono visibili all'esterno della funzione
l’identificatore “::var” identifica la variabile globale
blocco: sequenza di istruzioni tra graffe
63





una funzione e’ un blocco
visibilita’ locale: identificatori definiti all’interno di un blocco
visibilita’ a livello di file: funzioni e identificatori definiti fuori da tutte le
funzioni
visibilita’ degli identificatori di blocchi annidati
visibilita’ delle etichette: nel corpo della funzione a cui il blocco appartiene
//oop8.cpp
#include <iostream.h>
int a=1;
main()
{
int aext=a; int a=2;
{
int aext=a; int a=3;
{
int aext=a; int a=4;
cout << "exta=" << aext << " interno a=" << a << " ::a=" << ::a << endl;
}
cout << "aext=" << aext << " esterno a=" << a << " ::a=" << ::a << endl;
}
cout << "aext=" << aext << " main
a=" << a << " ::a=" << ::a << endl;
}
Output:
aext=3 interno a=4 ::a=1
aext=2 esterno a=3 ::a=1
aext=1 main
a=2 ::a=1
64
Le classi in C++




una classe è il modello-prototipo-al quale si conformano gli oggetti che
istanziano la classe
struttura di una classe:
class nome_classe
{
private:
// dati e metodi accessibili solo ai metodi della classe. Sono quindi
nascosti all’esterno (non accessibili direttamente)
protected:
// privati all’esterno; dati e metodi accessibili solo all’interno della
classe e tramite classi derivate
public:
// dati e metodi accessibili pubblicamente a tutte le funzioni dello
stesso scope dell’oggetto
};
le componenti funzionali dichiarati in una struttura possono essere definite
all'interno, (inline) o all'esterno
una classe introduce un nuovo tipo di dati
65
Le classi in C++


il tipo di dato definito con le classi, in cui cioè la struttura interna è
inaccessibile, e dal quale si possano istanziare oggetti manipolabili solo per
mezzo delle operazione associate, è detto “tipo di dato astratto” (ADT)
esempio di tipo di dato astratto “contatore”
class contatore
{
private:
unsigned int valore;
public:
contatore(); //un costruttore
void incrementa();
void decrementa();
void set(unsigned int n);
unsigned int val();
};

l'implementazione della classe può essere realizzato in un file separato o
inline
66
Un contatore
67
Le classi in C++
i metodi vengono attivati inviando all'oggetto un messaggio con il nome del
metodo usando l’operatore punto “.”:



c1.incrementa();//invia all’oggetto c1 la richiesta di
attivare
//incrementa
c1.visualizza();//analogamente
Puntatore ad oggetto: operatore freccia a destra “->”:

#include <iostream.h> //per la cout
#include "contatore.h" //definizioni e metodi della classe contatore precedente
contatore::contatore(){valore=0;};
void contatore::incrementa(){if(valore<65535) valore++;};
void contatore::decrementa(){if(valore>0) valore--;};
void contatore::set(unsigned int n){if((valore>=0)&&(valore<65535)) valore=n;};
unsigned int contatore::val(){return valore;};
void main()
{
contatore c1;
contatore *c3=new contatore;
cout << "c1=" << c1.val() << "c3=" << c3->val() << endl;;
c1.set(10);
c3->set(5);
cout << "c3->val()=" << c3->val() << endl;
for(short i=0; i<10; i++){
c1.incrementa(); c3->incrementa();
}
cout << "valore finale di c1=" << c1.val() << " finale di c3=" << c3->val() ;
}
68
Le classi in C++





invio di dati ad una procedura vs. invio di un messaggio all'oggetto
ma: quando un oggetto riceve un messaggio, determina come deve
essere elaborato il dato sottostante usando i metodi associati al dato
non posso elaborare direttamente i dati! Es. c1.valore non è
possibile
i metodi possono essere definiti anche in più file
la classe contatore potrebbe anche essere realizzata con una struttura:
#include <stdio.h>
struct contatore
{
unsigned int valore;
};
main()
{
contatore c1, c2;
c1.valore++;
c2.valore++;
}

ma: in questa forma i dati sono pubblici e la funzione principale accede
direttamente al dato sottostante
69
Strutture dati astratte ‘punto’ e ‘stringa’
70
Le classi in C++
Abstract Data Type : classe punto
#include <iostream.h>
class punto
{
int x,y; //coordinate private
public:
punto(){x=0; y=0;};
//costruttore di default
punto(int a, int b) {x=a; y=b;}; //altro costruttore (overloading delle funzioni)
void MuoviPunto(int d1, int d2)
{
x+=d1; y+=d2; return;
}
void StampaPunto(){ cout << "x=" << x <<" y=" << y;}
};
main()
{
punto p1;
punto p2(1,2);
p2.MuoviPunto(1,1);
//attiva il secondo costruttore
//attiva MuoviPunto
p2.StampaPunto();
}
71
Le classi in C++

Costruttori e distruttori delle classi




necessità di inizializzare le variabili
ciclo di vita di una variabile locale: nello scope in cui e’ definita
ciclo di vita di una variabile dinamica: programma
quando viene generata una variabili di tipo classe, si attiva
automaticamente una funzione che inizializza le variabili della classe:
costruttore: funzione con lo stesso nome della classe






non richiede tipo di ritorno; puo’ avere una lista di argomenti
attivata automaticamente quando si crea un'oggetto con new
sono possibili costruttore diversi, che devono avere liste di argomenti
diversi
costruttore di default: senza argomenti.
quando la variabile termina il suo ciclo di vita viene attivata
automaticamente -se disponibile- una funzione di eliminazione:
distruttore (ad esempio delete di variabili nella memoria libera)
Costruttore di copia:


Quando si passa o si ritorna un oggetto ad una funzione
In generale quando si copia un oggetto
72
#include <iostream.h>
// Esempio di costruttori per copia
class stringa
{
int len;
char *ch;
public:
stringa() {cout << "costruttore di default" << endl; len=0;}//costruttore di default
stringa(const char *s) //costruttore con argomenti; s e' puntatore a stringa costante
{ cout << "costr. con argomenti" << endl; len=strlen(s); ch=new char[len+1];
strcpy(ch,s);}
stringa(const stringa&s)
//costruttore di copia
{ cout << "costruttore di copia" << endl; len=s.len; ch=s.ch;}
void list(){cout<<ch<<endl;}
int val(){return len;}
void set(int n){len=n;}
void setp(char *ps){ch=ps;}
};
int lung(stringa s){return s.val();} //usa l'inizializzazione di copia
stringa crea(int l)
{ stringa s; char *ps; s.set(l); ps=new char[l+1]; s.setp(ps); return s;} //usa l’iniz. di copia}
main()
{
stringa a;
//costruttore di default
stringa b("Luigi"); //costruttore con argomenti
stringa c=b;
//costruttore di copia
c.list();
cout << lung(c); a=crea(10); cout << lung(a);
}
Output:
costruttore di default
Luigi
costruttore di default
10
Costr. con argomenti
costruttore di copia
costruttore di copia
costruttore di copia
5
costruttore di copia
73
Un numero complesso
74

numeri complessi
//
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
class complesso
{
private:
float pr, pi;
public:
complesso(){pr=0;pi=0;}
complesso(float x,float y);
void cadd(complesso arg);
void csub(complesso arg);
void cmult(complesso arg);
void visualizza();
};
// definizione funzioni
complesso::complesso(float x, float y)
{
pr=x; pi=y; }
void complesso::cadd(complesso arg)
{
pr+=arg.pr; pi+=arg.pi; }
void complesso::csub(complesso arg)
{
pr-=arg.pr; pi-=arg.pi; }
void complesso::cmult(complesso arg)
{
float temp1, temp2;
//costruttore di default
//altro costruttore
//operazione binaria
//operazione binaria
temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; pr=temp1; pi=temp2;
}
75
void complesso::visualizza()
{
if(pi<0)
cout << '\n' << "complesso: " << pr << "- j" << abs(pi);
else
cout << '\n' << "complesso: " << pr << "+ j" << pi;
}
main()
{
complesso a(1,3), b(2,2); complesso *c;
c=new(complesso(3.14,1.2));
a.visualizza(); b.visualizza();
c->visualizza();
a.cadd(b); b.cadd(b);
a.visualizza(); b.visualizza();
a.csub(b);
a.visualizza(); b.visualizza();
a.cmult(b);
a.visualizza(); b.visualizza();
}
Output:
complesso:
complesso:
complesso:
complesso:
complesso:
complesso:
complesso:
complesso:
1+ j3
2+ j2
3+ j5
4+ j4
-1+ j1
4+ j4
-8+ j0
4+ j4
76
ADT nodo ADT lista
77
//esempio di ADT nodo ADT lista
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
class nodo
{
private:
nodo *next;
int valore;
public:
nodo(){next=NULL;}
void loadn(nodo *a){next=a;}
void loadv(int a){valore=a;}
nodo *getn(){return next;}
int getv(){return valore;}
};
class lista
{
private:
nodo *head;
public:
lista(){head=NULL;} //costruttore
~lista(){} //distruttore: lasciato per esercizio!
void insert(int n);
//at the top
void add(int n);
//at the bottom
int hremove();
//toglie dalla cima
int tremove();
//toglie dalla coda
void type();
//visita dalla cima e stampa il contenuto
};
78
void lista::insert(int n)
{
nodo *temp;
temp=new nodo;
temp -> loadv(n);
temp -> loadn(NULL);
if(head) {temp -> loadn(head); head=temp;}
else {temp -> loadn(NULL); head=temp;}
}
void lista::add(int n)
{
nodo *temp, *prec;
if(head){
temp=head;
while(temp){
prec=temp;
temp=temp->getn();
}
prec->loadn(new nodo);
prec=prec->getn();
prec->loadv(n); prec->loadn(NULL);
} else {
head=new nodo;
head -> loadv(n);
head -> loadn(NULL);
}
}
79
int lista::hremove()
{
int n;
if(head){
n=head->getv();
head=head->getn();
return(n);
} else return(65536);
}
//65536 means empty
int lista::tremove()
{
int n;
nodo *temp, *prec;
temp=head;
if(head){
while(temp->getn()) {
prec=temp;
temp=temp->getn();
}
n=temp->getv(); prec->loadn(NULL);
delete(temp);
return(n);
} else return(65536);
//65536 means empty
}
80
void lista::type()
{
nodo *temp;
temp=head;
while(temp){
cout << temp->getv() << '\n';
temp=temp->getn();
}
}
main()
{
lista L1, L2;
int n;
for(int i=0; i<5; i++) L1.insert(i);
cout << "L1:" << '\n'; L1.type();
L2.add(10); L2.add(100);
cout << "L2:" << '\n'; L2.type();
L1.add(5); L1.add(6); L1.add(7);
cout << "L1 after add" << '\n';
L1.type();
cout << "L1hrem " << L1.hremove() <<
cout << "L1hrem " << L1.hremove() <<
while( (n=L2.tremove())!=65536) cout
while( (n=L1.hremove())!=65536) cout
'\n';
'\n';
<< "L2 trem " << n << '\n';
<< "L1 hrem " << n << '\n';
}
81
Le classi in C++

Autoriferimento nelle classi: l'argomento implicito 'this‘




una classe può contenere oggetti di altre classi, puntatori a oggetti di altre classi, puntatori
a oggetti della stessa classe (autoriferimento)
ogni oggetto contiene un puntatore, chiamato this, che contiene l'indirizzo dell'oggetto
stesso
Nota: ogni oggetto contiene al proprio interno le variabili definite nella classe, ma non i
metodi: ci possono essere molte istanze di una classe ma una sola istanza delle funzioni
il puntatore all'oggetto ‘this’ viene passato implicitamente alle funzioni della classe al
momento della loro attivazione, per sapere qual è l'oggetto attivatore
#include <iostream.h>
class contatore
{
unsigned int valore; //privato!
//
contatore *const this; questa definizione e' creata implicitamente
public:
contatore(); void inc(); void dec(); void set(unsigned int n); unsigned int val();
};
contatore::contatore(){this->valore=0;};
void contatore::inc(){if(this->valore<65535) this->valore++;};
void contatore::dec(){if(this->valore>0) this->valore--;};
void contatore::set(unsigned int n){ this ->valore=n;};
unsigned int contatore::val(){return this->valore;};
main()
{ //invariato
contatore c1,c2; c2.set(10); for(short i=0; i<10; i++){ c1.inc(); c2.inc(); }
cout << "valore finale di c1=" << c1.val() << " finale di c2=" << c2.val();
}
82
Le classi in C++

Esempio di autoriferimento: concatenazione di stringhe
#include <iostream.h>
class stringa
{
public:
int len;
//dati privati
char *str;
//definizione dei metodi
stringa(int=0);
stringa(const char *);
stringa &concat(const stringa&);
char *visualizza();
};
//in questo modo è possibile scrivere:
main()
{
stringa a(80);
stringa b("sequenza");
stringa c(" di questa");
stringa d(" prova");
a=b.concat(c).concat(d);
cout << a.visualizza();
}
83
//implementazione dei metodi
stringa::stringa(int n)
{ len=n;
if(n>0){ str=new char (len+1);
str[0]='\0'; } }
stringa::stringa(const char *s)
{ len=strlen(s); str=new char[len+1]; strcpy(str,s); }
char* stringa::visualizza()
{ return str; }
stringa& stringa::concat(const stringa &s)
{
len += s.len;
char *temp=new char[len+1];
strcpy(temp,str);
strcat(temp, s.str);
//temp="sequenza di questa"
str=temp;
//str e' la stringa dell'oggetto che ha attivato concat
return *this; //ritorna l'oggetto che ha attivato concat
}
Output:
sequenza di questa prova
84
Le classi in C++

Overloading degli operatori



ridefinizione di simboli del linguaggio
notazione infissa anche fra tipi diversi
limiti:






solo operatori gia’ definiti
l’operatore che viene ridefinito conserva le sue caratteristiche di associativita’, precedenza
e numero di argomenti
almeno uno degli argomenti deve essere di tipo classe
non si possono usare operatori che non hanno significato in C (es. **)
Specificatore: operator <operatore da sovrapporre>
operatore binario: definito da un metodo interno con un argomento - a.add(b) – oppure
con due argomenti – a=a.add(a,b) -
classe C
{
priv; ...
public:
C binary_op(C);
C binary_op(C, C);
}
classe binary_op(classe arg){return classe(priv+arg.priv);}
classe binary_op(classe arg1, classe arg2){ return classe(arg1.priv+arg2.priv);}
main(){
a.binary_op(b);
a=a.binary_op(a,b);
}
85
Le classi in C++

+
=
|=
||
Operatori del C++ che possono essere sovrapposti:
<
<<
++
*
>
>>
--
/
+=
>>=
[]
%
-=
<<=
()
^
*=
==
new
&
|
/=
%=
!=
<=
delete
~
^=
>=
!
&=
&&
86
Le classi in C++

operatore unario: metodo intero ad una classe senza argomenti operatore
unario U: l'espressione argomento U oppure U argomento può essere:


argomento.U() oppure U(argomento)
non è possibile realizzare applicazione prefissa e postfissa
/* Uso degli operatori unari e binari */
//
#include <iostream.h>
void main()
{
int a=1;
int b;
cout << "prima a= " << a << '\n';
b = a++; // l'operatore post-incremento e' unario: prima assegna e poi incrementa
cout << "dopo a++: a= " << a << " b=" << b <<'\n';
a=1;
b = ++a; /* l'operatore pre-incremento e' unario: prima incrementa e poi assegna*/
cout << "dopo ++a: a= " << a << " b=" << b <<'\n';
a=1;
b = a+1; /* l'operatore somma e' binario: prima somma e poi assegna */
cout << "dopo a+1: a= " << a << " b=" << b <<'\n';
}
87
Sovrapposizione degli operatori: esempio
88
Sovrapposizione degli operatori: esempio

overloading di operatori unari
#include <iostream.h>
//
class contatore
{
unsigned int valore;
public:
contatore(){valore=0;}
void operator++(){if(valore<65535) valore++;}//overloading di ++
void operator--(){if(valore>0) valore--;}//overloading di ()
void operator()(unsigned int n){if((valore>=0)&&(valore<65535)) valore=n;}
unsigned int val(){return valore;}
};
main()
{
contatore c1,c2;
c2(10);
for(short i=0; i<10; i++){
c1++; c2++;
}
cout << "valore finale di c1=" << c1.val() << " finale di c2=" << c2.val();
}
Output:
Valore finale di c1=10 finale di c2=20
89

Sovrapposizione operatori e numeri complessi
//
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
class complesso
{
private:
float pr, pi;
public:
complesso(){pr=0;pi=0;}
complesso(float x,float y);
void cadd(complesso arg);
void csub(complesso arg);
void cmult(complesso arg);
void visualizza();
};
// definizione funzioni
complesso::complesso(float x, float y)
{
pr=x; pi=y; }
void complesso::cadd(complesso arg)
{
pr+=arg.pr; pi+=arg.pi; }
void complesso::csub(complesso arg)
{
pr-=arg.pr; pi-=arg.pi; }
void complesso::cmult(complesso arg)
{
float temp1, temp2;
//costruttore di default
//altro costruttore
//operazione binaria
//operazione binaria
temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; pr=temp1; pi=temp2;
}
90
void complesso::visualizza()
{
if(pi<0)
cout << '\n' << "complesso: " << pr << "- j" << abs(pi);
else
cout << '\n' << "complesso: " << pr << "+ j" << pi;
}
main()
{
complesso a(1,3), b(2,2);
a.visualizza(); b.visualizza();
a.cadd(b); b.cadd(b);
a.visualizza(); b.visualizza();
a.csub(b);
a.visualizza(); b.visualizza();
a.cmult(b);
a.visualizza(); b.visualizza();
}
Output:
complesso:
complesso:
complesso:
complesso:
complesso:
complesso:
complesso:
complesso:
1+ j3
2+ j2
3+ j5
4+ j4
-1+ j1
4+ j4
-8+ j0
4+ j4
91

Overloading operatori e numeri complessi: seconda versione
//
#include <iostream.h>
#include <math.h>
class complesso
{
private:
float pr, pi;
public:
complesso(){pr=0;pi=0;}
//costruttore di default
complesso(float x,float y);
//altro costruttore
complesso cadd(complesso arg);
complesso csub(complesso arg);
complesso cmult(complesso arg);
void visualizza();
};
complesso::complesso(float x, float y){
pr=x; pi=y; }
complesso complesso::cadd(complesso arg){complesso t; t.pr=pr+arg.pr; t.pi=pi+arg.pi;
return t;}
complesso complesso::csub(complesso arg){complesso t; t.pr=pr-arg.pr; t.pi=pi-arg.pi;
return t;}
complesso complesso::cmult(complesso arg) { complesso t; float temp1, temp2;
temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; t.pr=temp1; t.pi=temp2;
return t;
}
92
void complesso::visualizza()
{
if(pi<0)
cout << '\n' << "complesso: " << pr << "- j" << abs(pi);
else
cout << '\n' << "complesso: " << pr << "+ j" << pi;
}
main()
{
complesso a(1,3), b(2,2);
a.visualizza(); b.visualizza();
a=a.cadd(b); b=b.cadd(b);
a.visualizza(); b.visualizza();
a=a.csub(b);
a.visualizza(); b.visualizza();
a=a.cmult(b);
a.visualizza(); b.visualizza();
}
93

overloading degli operatori e numeri complessi
//
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
class complesso
{
private:
float pr, pi;
public:
complesso(){pr=0;pi=0;}
//costruttore di default
complesso(float x,float y);
//altro costruttore
complesso operator+(complesso arg);
complesso operator-(complesso arg);
complesso operator*(complesso arg);
complesso operator*(float arg);
void visualizza();
};
// definizione funzioni
complesso::complesso(float x, float y)
{ pr=x; pi=y; }
complesso complesso::operator+(complesso arg) //complesso operator+(complesso
b){
{ complesso t; t.pr=pr+arg.pr; t.pi=pi+arg.pi; return t;}
complesso complesso::operator-(complesso arg)
{ complesso t; t.pr=pr-arg.pr; t.pi=pi-arg.pi; return t;}
94
complesso complesso::operator*(complesso arg)
{ complesso t;
float temp1, temp2;
temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; t.pr=temp1;
t.pi=temp2; return t;
}
complesso complesso::operator*(float arg){ //prodotto con tipo diverso!
return complesso(arg*pr, arg*pi);
}
void complesso::visualizza()
{
if(pi<0)
cout << '\n' << "complesso: " << pr << "- j" << abs(pi);
else
cout << '\n' << "complesso: " << pr << "+ j" << pi;
}
main()
{
complesso a(1,3), b(2,2), c, d;
a.visualizza(); b.visualizza();
a=a+b; b=b+b;
a.visualizza(); b.visualizza();
a=a-b; a.visualizza(); b.visualizza();
a=a*b; a.visualizza(); b.visualizza();
a=a*2; //attenzione: non e’ possibile 2*a!
a.visualizza(); c=a+a; a=((a+b-c)*c)*2; a.visualizza();
}
95
La classe A può dichiarare ‘amica’ la classe B
96
Relazioni tra oggetti e classi:
generalizzazione/specializzazione
Mammiferi
Cani
Gatti
97
Relazioni tra oggetti e classi:
generalizzazione/specializzazione




Introducono una gerarchia di classe
Generalizzazione: una superclasse fattorizza le proprietà
comuni di un insieme di classi
Generalizzazione: asimmetrica, non riflessiva, transitiva
Simbolo: Classe meno generale
Classe più generale
classi
più
specializzate
superclasse
subclasse
Specializzazione
Generalizzazione
classi
più
generali
98
Relazioni tra oggetti e classi:
generalizzazione/specializzazione

Attributi, operazioni e relazioni della superclasse
vengono ereditate dalle sottoclassi se protetti
Figura
Figura
posizione
posizione
colore
colore
=
display
display
Arco
Segmento
Rettangolo
Arco
Segmento
Rettangolo
raggio
Coordinate
Vertici
raggio
Coordinate
Vertici
angolo iniziale
display
display
angolo iniziale
display
display
ancolo finale
ancolo finale
display
display
99
Relazioni tra oggetti e classi:
generalizzazione/specializzazione

Top-down:
Classe base
(componente complesso)
Automobile
ruota
carrozzeria
motore
Sottoclassi (componenti minime)

Bottom-up:
veicolo
Classe base
(componente minimo)
Veicolo
a motore
Veicolo
senza motore
moto
Sottoclassi (componenti via via piu’ complesse)
auto
aereo
taxi
100
Relazioni tra oggetti e classi:
generalizzazione/specializzazione

Ereditarietà multipla
Veicolo
Veicolo
a motore
Veicolo
a vento
Camion
Veicolo
di terra
Veicolo
d’acqua
Barca a vela
101
Le classi in C++

Costruttori/distruttore nelle classi derivate



legato alla visibilità tra oggetti derivati e oggetti base
se un oggetto di classe derivata viene inizializzato, il costruttore deve assicurarsi
che venga eseguita una inizializzazione anche dell'oggetto della classe di baseinterna alla classe derivata-.
il costruttore della classe derivata attiva uno dei costruttore della classe base:
class Base
{
int a;
protected:
int bb;
public:
int b;
void Base(){a=0;}
}
class Derivata:public Base
{
int c;
public:
Derivata():Base(){c=0;}
int funz(){c=c+bb+b+d; return c;}
}
class Derivata2: public Derivata(){... public: derivata2():
Derivata()}
102
Derivazione (I)
103
Derivazione (II)
104
//ESEMPIO DI CLASSE BASE
//file complesso.h
class complesso {
protected:
float pr, pi;
public:
complesso(){pr=0;pi=0;}
complesso(float x,float y);
//costruttore di default
//altro costruttore
void add(complesso arg);
void sub(complesso arg);
void mpy(complesso arg);
void visualizza();
};
// definizione funzioni
complesso::complesso(float x, float y)
{
pr=x; pi=y; }
void complesso::add(complesso arg) //complesso operator+(complesso b){ co
{
pr=pr+arg.pr; pi=pi+arg.pi; }
void complesso::sub(complesso arg)
{
pr=pr-arg.pr; pi=pi-arg.pi; }
void complesso::mpy(complesso arg)
{
float temp1, temp2;
temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; pr=temp1; pi=temp2;
}
void complesso::visualizza()
{
if(pi<0) cout << '\n' << "pr,pi " << pr << "- j" << abs(pi); else cout << '\n' << "pr,pi " << pr << "+ j" << pi; }
105
#include <iostream.h>
#include <stdlib.h>
#include <math.h>
#include "complesso.h"
class comp:public complesso
{
private:
float modulo;
//valori trigonometrici
float fase;
public:
comp(float x, float y):complesso(x, y) //costruttore
{
modulo=sqrt(x*x+y*y);
fase=atan(y/x);
}
void c2t()
{
float x=pr; float y=pi;
modulo=sqrt(x*x+y*y);
fase=atan(y/x);
}
void t2c()
{
pr=modulo*cos(fase); pi=modulo*sin(fase);
}
void mult(comp arg)
{
modulo=modulo*arg.modulo; fase=fase+arg.fase; }
void div(comp arg)
{
modulo=modulo/arg.modulo; fase=fase-arg.fase; }
void visualizza()
{ complesso::visualizza(); cout << " modulo=" << modulo << " fase=" << fase;}
};
main()
{
comp a(1,1); comp b(1,2);
a.visualizza();
b.visualizza();
a.mult(b); a.t2c();
a.visualizza(); a.div(b); a.t2c();
a.visualizza();
}
106
//
//derivazione
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
class complesso
{
protected:
float pr, pi;
public:
complesso(float x,float y);
//altro costruttore
complesso cadd(complesso arg);
complesso csub(complesso arg);
void visualizza();
};
// definizione funzioni
complesso::complesso(float x, float y)
{
pr=x; pi=y;
}
complesso complesso::cadd(complesso arg)
{
pr+=arg.pr;
pi+=arg.pi;
}
107
complesso complesso::csub(complesso arg)
{
pr-=arg.pr;
pi-=arg.pi;
}
void complesso::visualizza()
{
cout << '\n' << "complesso: " << pr << "+ j" << pi;
}
class comp: public complesso
//derivazione per estendere la classe
{
public:
comp(float x, float y):complesso(x, y){};//costruttore
comp cmult(comp arg);
comp cdiv(comp arg);
void visualizza(char a);
};
//
comp comp::cmult(comp arg)
{
float temp1, temp2;
temp1=pr*arg.pr - pi*arg.pi;
temp2=pr*arg.pi + pi*arg.pr;
pr=temp1; pi=temp2;
}
108
comp comp::cdiv(comp arg)
{
float temp, temp1, temp2;
temp=arg.pr*arg.pr + arg.pi*arg.pi;
temp1 = (pr*arg.pr + pi*arg.pi)/temp;
temp2 = (pr*arg.pi - pi*arg.pr)/temp;
pr=temp1; pi=temp2;
}
void comp::visualizza(char a)
{
cout << '\n' << a;
complesso::visualizza();
}
main()
{
comp a(1,2), b(2,2);
a.complesso::visualizza(); b.complesso::visualizza();
a.cadd(b); b.cadd(b);
a.visualizza('a'); b.visualizza('b');
a.csub(b);
a.visualizza('a'); b.visualizza('b');
a.cmult(b);
a.visualizza('a');
b.cdiv(b);
b.visualizza('b');
}
109
Derivazione (III)
110
// liste derivate
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <alloc.h>
class nodo
{
protected:
nodo *next;
int valore;
public:
nodo(){next=NULL;valore=0;}
void loadpun(nodo *a){next=a;}
nodo *getpun(){return next;}
void loadval(int a){valore=a;}
int getval(){return valore;}
};
class nodo_ext: public nodo
{
protected:
char *nome;
int flag;
public:
nodo_ext(char *n, int f):nodo(){strcpy(nome,n);flag=f;}
nodo_ext():nodo(){flag=0;nome="";}
void loadnome(char *n){nome=new char[strlen(n)+1]; strcpy(nome,n);}
char *getnome(){return nome;}
void loadflag(int a){flag=a;}
int getflag(){return flag;}
};
111
class lista
{
private:
nodo_ext *head;
public:
lista(){head=NULL;} //costruttore
void add(int val, char *n, int f);
//at the bottom
int tremove();
//toglie dalla coda e restituisce il nome
void type();
//visita dalla cima e stampa il contenuto
};
void lista::add(int val, char *n, int f)
{
nodo_ext *temp, *prec;
if(head){
temp=head;
while(temp){
prec=temp; temp=(nodo_ext *)temp->getpun();
}
prec->loadpun(new nodo_ext); prec=(nodo_ext*)prec->getpun();
prec->loadval(val); prec->loadflag(f);
prec->loadnome(n); prec->loadpun(NULL);
} else {
head=new nodo_ext; head -> loadval(val);
head -> loadflag(f); head -> loadnome(n);
head -> loadpun(NULL);
}
}
112
int lista::tremove()
{
int n; nodo_ext *temp, *prec;
temp=head;
if(head){
while(temp->getpun()) { prec=temp; yemp=(nodo_ext*)temp->getpun(); }
n=temp->getval(); prec->loadpun(NULL); delete(temp);
return(n);
} else return(65536);
//65536 means empty
}
void lista::type()
{
nodo_ext *temp;
temp=head;
while(temp){
cout << "val=" << temp->getval() << " nome=" << temp->getnome() << " flag="
cout << temp->getflag() << '\n'; temp=(nodo_ext*)temp->getpun();
}
}
main()
{
lista L1, L2;
int n;
for(int i=0;i<5;i++) L1.add(i,"primo",0);
L1.type();
cout << "inizio a rimuovere dalla coda" << '\n';
while((n=L1.tremove())!=65536) cout << "remove L1 " << n << '\n';
}
113
Derivazione (IV)
Derivazione multipla
114
Regole di visibilita’

Classe base (superclasse)  classe derivata (sottoclasse)

Ricerca di una componente interna ad una variabile di sottoclasse:


Prima nella sottoclasse - Poi nelle componenti ereditate
Funzioni ridefinite nella sottoclasse:nasconde la funzione della
superclasse
Tutte le funzioni sono ancora attive! Si possono chiamare o con casting –
((superclasse) oggetto sottoclasse).funzione – o con
Oggetto_sottoclasse.superclasse::funzione


Riprendiamo la classe Studente. l’abbinamento funzione-oggetto e’
fatto STATICAMENTE dal compilatore (all’atto della compilazione) sulla
base di tipo oggetto e argomenti
Ma: con i puntatori?
115
Regole di visibilita’

Puntatori:
Studente *giorgio; Persona *giulio;
giorgio=new Studente(“Giorgio Bianchi", "ingegneria", 23,4);
giorgio -> presentati();

Attenzione: i puntatori possono puntare a oggetti diversi!
giorgio -> presentati();
giulio=giorgio; giulio->presentati(); // la associazione e’ fatta sulla base del
// tipo del puntatore e non dell’oggetto!!


giulio e’ una persona ma punta ad uno studente!
delete giulio cancella solo la persona: spreco spazio
Funzioni virtuali: associazione sulla base del tipo di oggetto
116
//oop45.cpp
#include <iostream.h>
class Persona
{
protected:
int eta;
char *nome;
public:
Persona(const char *n, int e){ nome=new char[strlen(n)+1]; strcpy(nome,n); eta=e;}
virtual void presentati()
{
cout << "sono una persona, mi chiamo " << nome << " ed ho " << eta << " anni“
<< endl;
}
};
class Studente:public Persona
{
private:
int anno;
char *facolta;
public:
Studente(char *n, char *f, int e, int a):Persona(n,e)
{
facolta=new char[strlen(f)+1]; strcpy(facolta,f); anno=a;
}
virtual void presentati(){
cout<<"sono uno studente di nome "<<nome<<" ho "<<eta<<" anni e sono iscritto a
"<<facolta<<" al "<<anno<<" anno di corso" << endl;
}
};
117
main()
{
Persona mario("Mario Verdi", 22);
Studente luigi("Luigi Rossi", "ingegneria", 24, 5);
mario.presentati();
luigi.presentati();
Studente *giorgio; Persona *giulio;
giorgio=new Studente("Giorgio Bianchi", "ingegneria", 23,4);
giorgio -> presentati();
giulio=giorgio; giulio->presentati();
}
Output con funzioni virtuali:
sono una persona, mi chiamo Mario Verdi ed ho 22 anni
sono uno studente di nome Luigi Rossi ho 24 anni e sono iscritto a ingegneria al 5 anno di corso
sono uno studente di nome Giorgio Bianchi ho 23 anni e sono iscritto a ingegneria al 4 anno di corso
sono uno studente di nome Giorgio Bianchi ho 23 anni e sono iscritto a ingegneria al 4 anno di corsOutput o
Output senza funzioni virtuali
sono una persona, mi chiamo Mario Verdi ed ho 22anni
sono uno studente di nome Luigi Rossi ho 24 anni e sono iscritto a ingegneria al 5 anno di corso
sono uno studente di nome Giorgio Bianchi ho 23 anni e sono iscritto a ingegneria al 4 anno di corso
sono una persona, mi chiamo Giorgio Bianchi ed ho 23anni
118
Le classi in C++

Polimorfismo e funzioni virtuali






Polimorfismo: capacità di rispondere in modo differenziato agli stessi
comandi
 realizzato con overloading delle funzioni e con le funzioni virtuali
overloading delle funzioni: la scelta della funzione da attivare è effettuata
esaminando una lista degli operandi o il tipo di oggetti tramite cui
vengono operate le richieste alle operazioni
 abbinamento statico(static binding): deciso alla compilazione
 abbinamento dinamico(dynamic binding): deciso in run-time
overloading quando gli oggetti vengono rappresentati con puntatore:
i puntatori possono puntare a oggetti di tipo diverso!
ma l'abbinamento statico si basa sul tipo di puntatore e non sul tipo di
oggetto puntato!
funzione virtuale: funzione il cui abbinamento con l'oggetto è fatto in runtime
sintassi: virtual int funz(){..........}
119
Le classi in C++



una funzione definita virtuale nella classe base in una gerarchia di
derivazione, rende virtuali tutte le funzioni con stesso prototipo e
componenti la classe derivata
l'abbinamento dinamico oggetto-funzione con le funzioni virtuali funziona
solo se gli oggetti sono gestiti con puntatore. Se l'oggetto gestito con il
nome, l'associazione e' statica.
tre casi in cui la chiamata di una funzione virtuale è risolta staticamente:




quando la chiamata e’ effettuata con un oggetto e non con un
puntatore
quando si usa scope (::) alla classe nella chiamata con puntatore
quando una funzione virtuale è chiamata all'interno di costruttore
o distruttore
costruttori e distruttori virtuali


Un costruttore non puo’ essere mai dichiarato virtuale (deve essere dichiarato
prima)
Distruttori possono essere virtuali!
120
Vantaggi del polimorfismo







Permette di scrivere codice generico che si adatta automaticamente alle
specializzazioni future
Permette di creare nuovi metodi senza cambiare il resto del codice
Semplice estensione del codice pre-esistente  riutilizzabilita’ del codice
Attenzione: se l’impostazione e’ corretta, si puo’ cambiare molto lavorando
poco…
…se si modifica troppo il codice originale, l’impostazione e’ sbagliata!
Modifiche concentrate  migliore manutenzione
Attenzione: i vantaggi si pagano con una certa perdita di efficienza!
121
#include <iostream.h>
class SuperficiePiana
{
protected:
float dim1;
public:
SuperficiePiana(float d) {dim1=d;}
virtual void presentati()
{ cout << “Sono una superficie piana, la mia prima dimensione e' " << dim1 ; }
virtual float Area(){ return 0;}
};
class triangolo: public SuperficiePiana
{
private:
float dim2;
public:
triangolo(float d1, float d2) : SuperficiePiana(d1)
{
dim2=d2; }
virtual void presentati()
{ cout<<“Sono un triangolo di dimensioni " << dim1 <<" e " << dim2 ; }
virtual float Area(){ return dim1*dim2/2.; }
};
class cerchio: public SuperficiePiana
{
public:
cerchio(float d1):SuperficiePiana(d1)
{}
virtual void presentati()
{ cout<< “Sono un cerchio" ; }
virtual float Area(){ return 3.14 * dim1*dim1; }
};
122
main()
{
SuperficiePiana * f1;
f1=new SuperficiePiana(2.);
f1->presentati();
cout << ". La mia area = " << f1->Area() << endl;
f1=new triangolo(2.,4.);
f1->presentati();
cout << ". La mia area = " << f1->Area() << endl;
}
//============================================================================
// aggiunta della classe trapezio
class trapezio:public SuperficiePiana
{
private:
float dim2;
float dim3;
public:
trapezio(float d1, float d2, float d3):SuperficiePiana(d1)
{dim2=d2;dim3=d3;}
void presentati()
{ cout << "sono un trapezio con basi=" << dim1 << ", " << dim2 <<
" e altezza= " << dim3 ;
}
float Area(){return (dim1+dim2)*dim3/2; }
};
123
Ricapitolando …

Campo variabili
Metodo1
Metodo2
Metodo3
Una classe (ADT):
class casa
{ ... };



privato
pubblico
Un oggetto e’ una istanza della classe:
casa a;
Piu’ oggetti hanno diversi valori delle variabili e stesso comportamento
Piu’ oggetti hanno diverse variabili, il codice e’ rientrante:
casa a, mia, tua;
ogg.a
ogg. mia
Puntatore ‘this’
ogg. tua
Puntatore ‘this’
Codice dei metodi

mia.metodo1; //attiva metodo1 mediante l’invio dell’indirizzo di mia al codice di metodo1

Comunicazione tra oggetti tramite invio di messaggi di attivazione
124
Ricapitolando …

Comunicazione tra oggetti
Campo variabili
Metodo1
Metodo2
Metodo3
Chiama tua.metodo2
a
Campo variabili
Metodo1
Metodo2
Metodo3
Campo variabili
Metodo1
Metodo2
Metodo3
tua
Chiama mia.metodo1
mia
125
Ricapitolando …

Terminologia:



Classe derivata: classe ottenuta mediante specializzazione di un’altra
classe
Classe base: la classe dalla quale una classe è derivata
Ereditarietà: una classe derivata eredita da una classe base

Ereditarietà impropria: quando la classe base ha una capacità che la
classe derivata non può soddisfare (esempio: nella derivazione
struzzo:uccello la classe base ha un metodo vola())

Costruttori/distruttori: inizializzazione var-rilascio spazio





Istanziazione oggetto/terminazione oggetto
nome uguale alla classe, senza return
parametri opzionali, possibili costruttori multipli
Costruttore di default / di copia
Attenzione: l’inizializzazione del costruttore segue l’ordine di definizione variabili
126
Ricapitolando …

Ereditarietà



Relazione has-a (composizione)
Relazione is-a (specializzazione/derivazione)
Esempio:

Se il problema si descrive con la frase: …un veicolo contiene una o più
ruote…
 Implementare la classe ‘ruota’ e poi la classe ‘veicolo’:
class veicolo{
private:
Ruota r1,r2,r3;
}

Se si descrive con la frase: …un’auto è un veicolo…
 Implementare la classe ‘veicolo’ e poi la classe ‘auto’:
class auto:public veicolo{
private:
...
}
auto *a=new auto(); veicolo *v=new veicolo();
v=a; //lecito
a=v; //errato
127
Ricapitolando …

Array di oggetti:



il costruttore e il distruttore vengono chiamati per ciascun elemento dell'array
per un vettore di oggetti appartenenti ad una classe con un costruttore, la
classe deve avere un costruttore senza argomenti
Costruttori/distruttore nelle classi derivate



legato alla visibilità tra oggetti derivati e oggetti base
se un oggetto di classe derivata viene inizializzato, il costruttore deve
assicurarsi che venga eseguita una inizializzazione anche dell'oggetto della
classe di base-interna alla classe derivata-.
il costruttore della classe derivata attiva uno dei costruttore della classe base
128
Ricapitolando …

Polimorfismo:






Capacità degli oggetti di differenti classi legate da ereditarietà
di rispondere differentemente alla stessa chiamata
Ottenuto mediante overloading delle funzioni e funzioni virtuali
Abbinamento statico delle funzioni agli oggetti
Statico: legato al tipo del puntatore, non al tipo dell’oggetto
puntato
‘casting’ per indicare esplicitamente il tipo del puntatore
Funzioni virtuali:



Abbinamento dinamico della funzione all’oggetto
I costruttori NON possono essere virtuali
I distruttori possono invece esserlo: recuperano lo spazio
dell’oggetto puntato
129
Ricapitolando …

Funzioni virtuali come base per la derivazione:


Non definiscono il contenuto di alcuni metodi:
Public: virtual void stampa(){ };
Funzioni virtuali pure





Definite ma mai utilizzate per istanziare oggetti
Dichiarate con uno zero:
Public: virtual void stampa() = 0;
Classe che contiene una o più funzioni virtuali pure :

classe astratta (indica com’è fatta la classe in modo astratto)

Usata come base per la derivazione
Non è possibile istanziare da una classe astratta
Una classe astratta è una interfaccia per la derivazione
130
Polimorfismo e funzioni virtuali


Polimorfismo: capacità di rispondere in modo differenziato agli
stessi comandi
 realizzato con overloading delle funzioni e con le funzioni virtuali
overloading delle funzioni: la scelta della funzione da attivare è
effettuata esaminando una lista degli operandi o il tipo di oggetti
tramite cui vengono operate le richieste alle operazioni






abbinamento statico(static binding): deciso alla
compilazione
abbinamento dinamico(dynamic binding): deciso in
run-time
overloading quando gli oggetti vengono rappresentati con puntatore:
i puntatori possono puntare a oggetti di tipo diverso!
ma l'abbinamento statico si basa sul tipo di puntatore e non sul tipo
di oggetto puntato!
funzione virtuale: funzione il cui abbinamento con l'oggetto è fatto in
run-time
131
Polimorfismo e funzioni virtuali



Una funzione definita virtuale nella classe base in una gerarchia di
derivazione, rende virtuali tutte le funzioni con stesso prototipo e
componenti la classe derivata
L'abbinamento dinamico oggetto-funzione con le funzioni virtuali funziona
solo se gli oggetti sono gestiti con puntatore. Se l'oggetto gestito con il
nome, l'associazione e' statica.
Tre casi in cui la chiamata di una funzione virtuale è risolta staticamente:




quando la chiamata e’ effettuata con un oggetto e non con un
puntatore
quando si usa scope (::) alla classe nella chiamata con puntatore
quando una funzione virtuale è chiamata all'interno di costruttore
o distruttore
Costruttori e distruttori virtuali


Un costruttore non puo’ essere mai dichiarato virtuale (deve essere dichiarato
prima)
Distruttori possono essere virtuali!
132
Vantaggi del polimorfismo







Permette di scrivere codice generico che si adatta automaticamente alle
specializzazioni future
Permette di creare nuovi metodi senza cambiare il resto del codice
Semplice estensione del codice pre-esistente  riutilizzabilita’ del codice
Attenzione: se l’impostazione e’ corretta, si puo’ cambiare molto lavorando
poco…
…se si modifica troppo il codice originale, l’impostazione e’ sbagliata!
Modifiche concentrate  migliore manutenzione
Attenzione: i vantaggi si pagano con una certa perdita di efficienza!
133
Polimorfismo (I)
134
Polimorfismo (II)
135
Lista non polimorfica senza friend
136
Lista non polimorfica con friend
137
Inserimento di una categoria aggiuntiva nella lista
non polimorfica
138
Lista polimorfica
139
//
//lista polimorfica. Header file
#include <iostream.h>
class persona
{
friend class lista;
protected:
char cognome[10];
char nome[10];
int anni;
int codice_fiscale;
persona *ptr;
persona *next;
public:
persona(char *co, char *no, int a, int cf);
persona();
~persona();
void set_cognome(char *c);
void set_nome(char *n);
void set_anni(int a);
void set_cf(int cf);
virtual void stampa();
virtual void insert();
};
140
//(continua)
class studente:public persona
{
friend class lista;
private:
int matricola;
int anno_di_corso;
public:
studente(char *co, char *no, int a, int cf, int mat, int an):persona(co, no, a, cf)
{ matricola=mat; anno_di_corso=an; }
studente():persona()
{ matricola=0; anno_di_corso=0;}
void set_matricola(int m);
void stampa();
void set_anno_corso(int ac);
void insert();
};
class lavoratore:public persona
{
friend class lista;
private:
float stipendio;
public:
lavoratore(char *co, char *no, int a, int cf, float s):persona(co, no, a, cf){stipendio=s;}
lavoratore():persona() { stipendio=0;}
void set_stipendio(float s);
void stampa(); void insert();
};
141
//(continua)
class pensionato:public persona
{
friend class lista;
private:
int anni_quiescenza;
public:
pensionato(char *co, char *no, int a, int cf, int q):persona(co, no, a, cf)
{ anni_quiescenza=q; }
pensionato():persona()
{ anni_quiescenza=0;}
void set_quiescenza(int q);
void stampa();
void insert();
};
class lista
{
private:
persona *radice;
public:
lista();
~lista();
void inserisci(persona *n);
void rimuovi(char *c);
void stampa();
};
142
//Lista polimorfica
//Implementazione dei metodi della lista polimorfica
#include <iostream.h>
#include "lista4.h"
persona::persona(char *co, char *no, int a, int cf)
{ strcpy(cognome,co); strcpy(nome,no);anni=a; codice_fiscale=cf; next=0; }
persona::persona()
{ strcpy(cognome,"\0"); strcpy(nome,"\0"); anni=0; codice_fiscale=0; next=0; }
persona::~persona(){};
void persona::set_cognome(char *c) { strcpy(cognome,c); }
void persona::set_nome(char *n) { strcpy(nome,n); }
void persona::set_anni(int a) { anni=a; }
void persona::set_cf(int cf) { codice_fiscale=cf; }
void persona::insert()
{ ptr=new persona(cognome, nome, anni, codice_fiscale); }
void persona::stampa()
{ cout << cognome << " " << nome << "\t anni " << anni << " CF= " << codice_fiscale ;}
void studente::set_matricola(int m) { matricola=m; }
void studente::set_anno_corso(int ac) { anno_di_corso=ac;}
void studente::stampa()
{ persona::stampa();
cout << " Studente, matricola=" << matricola << " anno di corso="<<anno_di_corso<<endl;
}
void studente::insert()
{ ptr=new studente(cognome, nome, anni, codice_fiscale, matricola, anno_di_corso); }
143
//Lista polimorfica
void lavoratore::set_stipendio(float s)
{ stipendio=s; }
void lavoratore::stampa()
{
persona::stampa(); cout << " Lavoratore, stipendio=" << stipendio <<endl;
}
void lavoratore::insert()
{ ptr=new lavoratore(cognome, nome, anni, codice_fiscale, stipendio); }
void pensionato::set_quiescenza(int q)
{ anni_quiescenza=q;}
void pensionato::stampa()
{ persona::stampa(); cout << " Pensionato, anni di quiescenza=" << anni_quiescenza <<endl;}
void pensionato::insert()
{ ptr=new pensionato(cognome, nome, anni, codice_fiscale, anni_quiescenza); }
lista::lista()
{ radice=0; }
lista::~lista()
{ // naturalmente per cancellare lo spazio degli oggetti bisogna avere una lista
// bidirezionale. Si lascia per esercizio
persona *p,*q;
do{ p=q=radice; while(p->next!=0){q=p;p=p->next;} q->next=0; delete p; } while(q!=radice);
delete radice;
}
144
//(continua). Lista polimorfica
void lista::inserisci(persona *n)
{
persona *p, *q;
p=q=radice;
n->insert();
if(p==0) {p=radice=n->ptr;} else { while(p!=0){q=p; p=p->next;} q->next=n->ptr;
}
}
void lista::rimuovi(char *c)
{// in questo esempio non e' stata scritta. Si lascia per esercizio }
void lista::stampa()
{
persona *p;
p=radice; while(p!=0) { p->stampa(); p=p->next; }
}
main()
{
lista l; persona t;
studente st("Terreni", "Piero", 30, 2222, 23, 5);
lavoratore la("Pierucci", "Piero", 40, 1111, 2000);
pensionato pen("Rossi", "Luigi", 70, 3276, 5);
l.inserisci(&st);
l.inserisci(&la); l.inserisci(&pen);
l.stampa();
}
145
//Introduzione di una classe aggiuntiva. Lista polimorfica. Header file lista5.h
#include <iostream.h>
class persona
{
friend class lista;
protected:
char cognome[10];char nome[10];int anni;int codice_fiscale;persona *ptr;persona *next;
public:
persona(char *co, char *no, int a, int cf);
persona(); ~persona();
void set_cognome(char *c); void set_nome(char *n); void set_anni(int a);
void set_cf(int cf);
virtual void stampa(); virtual void insert();
};
class studente:public persona
{
friend class lista;
private:
int matricola; int anno_di_corso;
public:
studente(char *co, char *no, int a, int cf, int mat, int an):persona(co, no, a, cf)
{ matricola=mat; anno_di_corso=an; }
studente():persona() { matricola=0; anno_di_corso=0;}
void set_matricola(int m); void set_anno_corso(int ac); void stampa(); void insert();
};
146
//lista5.h (continua)
class lavoratore:public persona
{
friend class lista;
private:
float stipendio;
public:
lavoratore(char *co, char *no, int a, int cf, float s):persona(co, no, a, cf)
{ stipendio=s; }
lavoratore():persona() { stipendio=0;}
void set_stipendio(float s); void stampa(); void insert();
};
class pensionato:public persona
{
friend class lista;
private:
int anni_quiescenza;
public:
pensionato(char *co, char *no, int a, int cf, int q):persona(co, no, a, cf)
{ anni_quiescenza=q; }
pensionato():persona() { anni_quiescenza=0;}
void set_quiescenza(int q); void stampa(); void insert();
};
147
//lista5.h (continua)
Classe aggiunta nell’header file
class disoccupato:public persona
{
friend class lista;
private:
int mesi_disoccupazione;
int nr_impieghi;
public:
disoccupato(char *co, char *no, int a, int cf, int md, int ni):persona(co, no, a, cf)
{ mesi_disoccupazione=md; nr_impieghi=ni; }
disoccupato():persona() { mesi_disoccupazione=0; nr_impieghi=0; }
void set_disoccupazione(int md) { mesi_disoccupazione=md; }
void set_impieghi(int ni) { nr_impieghi=ni; }
void stampa() { persona::stampa(); cout << " Disoccupato da " << mesi_disoccupazione;
cout << " mesi. Nr. impieghi=" << nr_impieghi << endl; }
void insert()
{
ptr=new disoccupato(cognome,nome,anni,codice_fiscale,mesi_disoccupazione,nr_impieghi);
};
class lista
{
private:
persona *radice;
public:
lista(); ~lista(); void inserisci(persona *n); void rimuovi(char *c); void stampa();
};
148
};
//implementazione dei metodi della lista polimorfica
#include <iostream.h>
#include "lista5.h"
persona::persona(char *co, char *no, int a, int cf)
{ strcpy(cognome,co); strcpy(nome,no); anni=a; codice_fiscale=cf; next=0; }
persona::persona()
{ strcpy(cognome,"\0"); strcpy(nome,"\0"); anni=0; codice_fiscale=0; next=0; }
persona::~persona(){};
void persona::set_cognome(char *c) { strcpy(cognome,c); }
void persona::set_nome(char *n) { strcpy(nome,n); }
void persona::set_anni(int a) { anni=a; }
void persona::set_cf(int cf) { codice_fiscale=cf; }
void persona::insert() { ptr=new persona(cognome, nome, anni, codice_fiscale); }
void persona::stampa()
{ cout << cognome << " " << nome << "\t anni " << anni << " CF= " << codice_fiscale ;}
void studente::set_matricola(int m) { matricola=m; }
void studente::set_anno_corso(int ac) { anno_di_corso=ac;}
void studente::stampa()
{
persona::stampa();
cout << " Studente, matricola=" << matricola << " anno di corso="<<anno_di_corso<<endl;
}
void studente::insert()
{ ptr=new studente(cognome, nome, anni, codice_fiscale, matricola, anno_di_corso); }
149
//(continua)
void lavoratore::set_stipendio(float s) { stipendio=s; }
void lavoratore::stampa()
{ persona::stampa(); cout << " Lavoratore, stipendio=" << stipendio <<endl; }
void lavoratore::insert()
{ ptr=new lavoratore(cognome, nome, anni, codice_fiscale, stipendio); }
void pensionato::set_quiescenza(int q) { anni_quiescenza=q;}
void pensionato::stampa()
{ persona::stampa(); cout << " Pensionato, anni di quiescenza=" << anni_quiescenza <<endl;}
void pensionato::insert()
{ ptr=new pensionato(cognome, nome, anni, codice_fiscale, anni_quiescenza); }
lista::lista()
{ radice=0; }
lista::~lista()
persona *p,*q;
do{ p=q=radice; while(p->next!=0){q=p;p=p->next;} q->next=0; delete p; } while(q!=radice);
delete radice;
}
void lista::inserisci(persona *n)
{ persona *p, *q;
p=q=radice; n->insert();
if(p==0) {p=radice=n->ptr;} else { while(p!=0){q=p; p=p->next;} q->next=n->ptr; }
}
void lista::rimuovi(char *c)
{// in questo esempio non e' stata scritta. Si lascia per esercizio }
150
//(continua)
void lista::stampa()
{
persona *p;
p=radice;
while(p!=0)
{
p->stampa(); p=p->next;
}
}
main()
{
lista l; persona t;
studente st("Terreni", "Piero", 25, 2222, 23, 5);
lavoratore la("Pierucci", "Piero", 40, 1111, 2000);
pensionato pen("Rossi", "Luigi", 70, 3276, 5);
disoccupato dis("Ferri", "Luigi", 40, 2323, 8, 1);
l.inserisci(&st);
l.inserisci(&la);
l.inserisci(&pen);
l.inserisci(&dis);
l.stampa();
}
151
Esempio di calcolo con i polinomi mediante
programmazione ad oggetti
152
class CFunction{
public:
CFunction(){ if (dbg) cout << "Costruttore classe base CFunction" <<
endl;}
virtual ~CFunction(){ if (dbg) cout << "Distruttore classe base
CFunction" << endl;}
virtual double GetY(double x) = 0;
};
class CPoly: public CFunction{
protected:
int Order;
//Grado del polinomio
double *Coeffs;
public:
CPoly();
//C default crea ma non definisce ordine e
coefficienti
CPoly(int g, double* c); //C numeratore grado g e coefficienti di *c,
denominatore 1
CPoly(const CPoly& p);
//C di copia
CPoly(int g, double c);
//costruttore di polinomio grado 0 coeff=c
~CPoly();
//Distruttore
void Visualizza()const;
//stampa
CPoly &operator=(const CPoly& p);
CPoly operator+(const CPoly& p);
CPoly operator-(const CPoly& p);
CPoly operator*(const CPoly& p);
int GetOrder();
double GetCoeffs(int i);
bool nullo();
//verifica se il polinomio è nulloù
bool unitario();
double GetY(double x){}
};
153
class CPolyF: public CPoly{ //definisce polinomio base
protected:
char *nome;
//nome del polinomio
int OrderF;
//Grado del polinomio
double *CoeffsF;
//Vettore di coefficienti
public:
CPolyF();
//C default crea ma non definisce ordine e coefficienti
CPolyF(int g, double* c); //C numeratore grado g e coefficienti di *c,
denominatore 1
CPolyF(int g, double* c, int gF, double *cF); //C numeratore grado g e
coefficienti di *c, denominatore 1
CPolyF(const CPolyF& p);
//C di copia
CPolyF(const CPoly& a, const CPoly& b);
//C per parti
CPolyF(const CPoly& a); //C polinomi interi
~CPolyF();
//Distruttore
void Visualizza()const;
//stampa
CPolyF &operator=(const CPolyF& p);
//assegnazione
CPolyF operator+(const CPolyF& p);
//somma
CPolyF operator-(const CPolyF& p);
//differenza
CPolyF operator*(const CPolyF& p);
//moltiplicazione
CPolyF operator/(const CPolyF& p);
//divisione
void SetNome(char *n);
//assegna il nome al polinomio
void SetNum(CPoly n);
void SetDen(CPoly d);
char* GetNome();
void Semplifica();
//ricerca fattori semplificabili
//CPoly GetDen();
double GetY(double x){}
//friend class CPolyF;
};
154
CPoly::CPoly(int g, double* c){ //Costruttore
int i=0;
for (i=g; i>0; i--){
//i coefficienti sono congruenti con il grado?
if (c[i]==0) g--;
else break;
}//end for
Order=g;
if (g>=0){
Coeffs=new double[g+1];
for (i=0; i<=g; i++){
Coeffs[i]=c[i];
}
}
else Coeffs=NULL;
}
CPoly::~CPoly(){
//distruttore
if (Coeffs) delete [] Coeffs; //se è definito CoeffsF lo dealloca
}
void CPoly::Visualizza()const{
if (Order<0){
//polinomio definito?
cout << "Polinomio non definito" << endl;
return;
}//end if
stampa(Order, Coeffs); //stampa del solo numeratore
cout << endl; //a capo
}
//e stampa il risultato
CPoly &CPoly::operator=(const CPoly& p){
if (Order!=p.Order){
if (Coeffs) delete [] Coeffs;
Order=p.Order;
Coeffs=new double[Order+1];
}
//copia dei coefficienti
for (int i=0; i<=Order; i++) Coeffs[i]=p.Coeffs[i];
if (dbg) cout << "\nOperatore CPoly =" << endl;
return *this;
}
155
CPolyF::CPolyF():CPoly(){
//Costruttore di default
nome=NULL;
OrderF=-1;
//denominatore
CoeffsF=NULL;
//nè per numeratore nè per denominatore
if (dbg) cout << "C CPolyF default" << endl;
//debug
}
CPolyF &CPolyF::operator=(const CPolyF& p){
//se gli ordini sono diversi si devono riallocare i coefficienti
if (Order!=p.Order){
if (Coeffs) delete [] Coeffs; //deallocando i precedenti
Order=p.Order;
//acquisendo il nuovo ordine
Coeffs=new double[Order+1];
//e allocando quelli nuovi
}
//copia dei coefficienti
for (int i=0; i<=Order; i++) Coeffs[i]=p.Coeffs[i];
if (OrderF!=p.OrderF){
if (CoeffsF) delete [] CoeffsF; //deallocando i precedenti
OrderF=p.OrderF;
//acquisendo il nuovo ordine
CoeffsF=new double[OrderF+1];
//e allocando quelli nuovi
}
//copia dei coefficienti
for (int i=0; i<=OrderF; i++) CoeffsF[i]=p.CoeffsF[i];
if (dbg) cout << "\nOperatore CPolyF =" << endl;
return *this;
}
156
CPolyF CPolyF::operator-(const CPolyF& p){
CPolyF ris;
bool den_uguali=true;
CPoly *n1, *d1, *n2, *d2;
if (OrderF==p.OrderF){
for (int i=0; i<=p.OrderF; i++){ if (CoeffsF[i]!=p.CoeffsF[i]) den_uguali=false; }
if (den_uguali){
n1=new CPoly(Order, Coeffs); n2=new CPoly(p.Order, p.Coeffs); d1=new CPoly(OrderF, CoeffsF);
ris=CPolyF((*n1)-(*n2),(*d1));
delete n1, n2, d1;
return ris;
}
}
n1=new CPoly(Order, Coeffs);
d1=new CPoly(OrderF, CoeffsF);
n2=new CPoly(p.Order, p.Coeffs);
d2=new CPoly(p.OrderF, p.CoeffsF);
ris=CPolyF((*n1)*(*d2)-(*n2)*(*d1),(*d1)*(*d2));
delete n1 , n2, d1, d2;
return ris;
}
CPolyF CPolyF::operator+(const CPolyF& p){
CPolyF ris;
bool den_uguali=true;
CPoly *n1, *d1, *n2, *d2;
if (OrderF==p.OrderF){
for (int i=0; i<=p.OrderF; i++){ if (CoeffsF[i]!=p.CoeffsF[i]) den_uguali=false; }
if (den_uguali){
n1=new CPoly(Order, Coeffs); n2=new CPoly(p.Order, p.Coeffs); d1=new CPoly(OrderF, CoeffsF);
ris=CPolyF((*n1)+(*n2),(*d1));
delete n1, n2, d1;
return ris;
}
}
n1=new CPoly(Order, Coeffs);
d1=new CPoly(OrderF, CoeffsF);
n2=new CPoly(p.Order, p.Coeffs);
d2=new CPoly(p.OrderF, p.CoeffsF);
ris=CPolyF((*n1)*(*d2)+(*n2)*(*d1),(*d1)*(*d2));
delete n1, n2, d1, d2;
return ris;
}
157
CPolyF CPolyF::operator*(const CPolyF& p){
CPolyF ris;
bool n1_d2_uguali=true;
bool n2_d1_uguali=true;
CPoly *n1, *d1, *n2, *d2;
if (Order==p.OrderF){ //controllo uguaglianza num1-den2
for (int i=0; i<=p.OrderF; i++){
if (Coeffs[i]!=p.CoeffsF[i]){
n1_d2_uguali=false;
break;
}
}
}
else n1_d2_uguali=false;
if (n1_d2_uguali){
n1=new CPoly(0, 1);
d2=new CPoly(0, 1);
}
else{
n1=new CPoly(Order, Coeffs);
d2=new CPoly(p.OrderF, p.CoeffsF);
}
//fine uguaglianza num1-den2
if (OrderF==p.Order){ //controllo uguaglianza num2-den1
for (int i=0; i<=p.Order; i++){
if (CoeffsF[i]!=p.Coeffs[i]){
n2_d1_uguali=false;
break;
}
}
}
else n2_d1_uguali=false;
if (n2_d1_uguali){
n2=new CPoly(0, 1);
d1=new CPoly(0, 1);
}
else{
n2=new CPoly(p.Order, p.Coeffs);
d1=new CPoly(OrderF, CoeffsF);
}
//fine uguaglianza num2-den1
ris=CPolyF((*n1)*(*n2),(*d1)*(*d2));
delete n1, n2, d1, d2;
return ris;
}
158
Esempio di calcolo vettoriale mediante programmazione
ad oggetti
159
#include
#include
#include
#include
<iostream.h>
<stdlib.h>
<conio.h>
<math.h>
typedef int inte;
//stream di input e output
//libreria standard
//console di input e output
//libreria con funzioni matematiche (radice)
//Il vettore é di tipo intero
class matrix
//classe matrice
{
//definita da righe,colonne e dove sono colocate
friend class vettore;
//classe vettore può usare oggetti matrice
protected:
//protette per derivazione
int r,c;
//variabili numero righe(r) e colonne(c)
int **m;
//doppio puntatore
public:
matrix(int a,int b);
//costruttore con argomenti numero righe e colonne
matrix(matrix& y);
//costruttore copia
virtual inte& accedi(int i,int j);
//accesso alle variabili:ne restituisce il valore
matrix operator+(matrix& mat);
//somma di 2 matrici;overloading di +
matrix operator-(matrix& mat);
//sottrazione di 2 matrici;overloading di matrix operator*(matrix& mat);
//moltiplicazione di 2 matrici;overloading di *
void errore(char c[]);
//segnala l'errore e esci dal programma
virtual void stampa(char *s1);
//visualizza la matrice
};//matrix
matrix::matrix(int a,int b)
//costruttore
{
r=a;
//assegna numero di righe
c=b;
//assegna numero di colonne
m=new inte*[r];
//crea un "oggetto" di r puntatori,poi ad ogni puntatore
for(int i=0;i<r;i++)
//alloca una diversa riga
{
m[i]=new inte[c];
//l'i-esimo elemento di m(per ogni riga) diventa
}//for i
//un nuovo elemento di colonna
}//costruttore
160
class matrice_quad:public matrix
//matrice quadrata,sottoclasse di matrice:è un esempio di derivazione
{
//questo programma non richiede la dichiarazione friend,poiché nel main la classe
vettore
private:
//non usa oggetti matrice_quad
bool sim,diag;
//variabili simmetrica e diagonale
public:
matrice_quad(int a,int b,bool si,bool dia):matrix(a,b)
//costruttore che prende in
{
//derivazione numero di righe e di colonne(=righe) dal costruttore della superclasse matrice
sim=si;
//inizializzate le variabili simmetrica e diagonale
diag=dia;
}//costruttore
matrice_quad(matrice_quad& x):matrix(x)
//costruttore copia con derivazione
{
//delle protected di matrice e
sim=x.sim;
//private di matrice quadrata
diag=x.diag;
}//costruttore copia
void check_sim();
//controlla se simmetrica
void check_dia();
//controlla se diagonale
inte& accedi(int i,int j);
//accedi alle variabili
void errore(char c[]);
//segnala l'errore e esci dal programma
void stampa(char *s1);
//visualizza la matrice quadrata
};//matrice_quad
class vettore
//classe vettore
{
//definita dal numero di elementi(size) e dove sono collocati(*p)
private:
int size;
//quanti elementi ci sono
inte *p;
//dove sono questi elementi
public:
vettore(int n);
//costruttore con argomento numero di elementi
vettore(vettore& v);
// costruttore copia
inte& operator[](int i);
//accesso all'elemento i-esimo
vettore operator+(vettore& v);
//somma di 2 vettori;overloading di +
vettore operator-(vettore& v);
//sottrazione di 2 vettori;overloading di inte operator*(vettore& v);
//prodotto scalare;overloading di *
inte operator|(vettore& v);
//calcolo del modulo del vettore;overloading di |
vettore molt_per_matrice(vettore& v,matrix& mat);
//moltiplicazione di 1 vettore per una matrice
void errore(char c[]);
//segnala l'errore e esci dal programma
void scrivi(char *s1);
//visualizza il vettore
};//vettore
161
matrix matrix::operator+(matrix& mat)
//somma di matrici con overloading
{
matrix loc(mat);
//crea una copia locale di matrice
if(mat.r!=r)
//se il numero delle righe delle 2 matrici non coincide
{
mat.errore("matrici con numero di righe incompatibili");
//messaggio di errore
}//if
if(mat.c!=c)
//se il numero delle colonne delle 2 matrici non coincide
{
mat.errore("matrici con numero di colonne incompatibili");
//messaggio di errore
}//if
for(int i=0;i<r;i++)
//ciclo di riga
{
for(int j=0;j<c;j++)
//ciclo di colonna
{
loc.m[i][j]=m[i][j]+mat.m[i][j];
//somma gli elementi delle 2 matrici
}//for j
}//for i
return loc;
//restituisci la matrice "somma"
}//operator+
matrix matrix::operator-(matrix& mat)
//sottrazione di matrici con overloading
{
matrix loc(mat);
//crea una copia locale di matrice
if(mat.r!=r)
//se il numero delle righe delle 2 matrici non coincide
{
mat.errore("matrici con numero di righe incompatibili");
//messaggio di errore
}//if
if(mat.c!=c)
//se il numero delle colonne delle 2 matrici non coincide
{
mat.errore("matrici con numero di colonne incompatibili");
//messaggio di errore
}//if
for(int i=0;i<r;i++)
//ciclo di riga
{
for(int j=0;j<c;j++)
//ciclo di colonna
{
loc.m[i][j]=m[i][j]-mat.m[i][j];
//sottrai agli elementi,quelli della matrice in entrata
}//for j
}//for i
return loc;
//restituisci la matrice "differenza"
}//operator-
162
matrix matrix::operator*(matrix& mat)
//moltiplica 2 matrici;overloading di *
{
matrix loc(mat);
//crea una copia locale di matrice
if(c!=mat.r)
//se il numero di colonne della prima é diverso dal
{
//numero di righe della seconda
mat.errore("Errore!Matrici incompatibili per il prodotto");
//messaggio di errore
}//if
for(int i=0;i<r;i++)
//finché ho righe da completare
{
for(int j=0;j<mat.c;j++)
//finché ho colonne da completare
{
loc.m[i][j]=0;
//azzero il valore degli elementi
for(int k=0;k<mat.r;k++)
//finché ho righe della matrice in entrata
{
//faccio la somma del prodotto dell'elemento di riga i e colonna k
loc.m[i][j]=loc.m[i][j]+m[i][k]*mat.m[k][j];
//per l'elemento di riga k e colonna j della
}//for k
//matrice in entrata
}//for j
}//for i
return loc;
//restituisci la matrice "prodotto"
}//operator*
void matrix::stampa(char *s1)
//visualizza
{
cout << "la matrice " << s1 << ": \n";
for(int i=0;i<r;i++)
//finché ho righe
{
for(int j=0;j<c;j++)
//finché ho colonne
{
cout << m[i][j] << ' ';
}//for j
cout << '\n';
//vai a capo
}//for i
}//stampa
void matrice_quad::stampa(char *s1)
//visualizza
{
matrix::stampa(s1);
//chiama la stampa di matrix
passandogli la stringa s1
cout << "quadrata di ordine " << r << 'x' << c << " " ;
//aggiungi le informazioni
check_sim();
//su simmetrica e
check_dia();
//diagonale
}//stampa
163
vettore::vettore(int n)
//costruttore di vettore a n elementi
{
size=n;
//assegna il numero di elementi
p=new inte[n];
//crea un vettore di n elementi
}// costruttore
inte& vettore::operator[](int i)
//accesso all'i-esimo elemento del vettore;overloading di []
{
if((i<0)||(i>=size))
//se l'indice è sbagliato
{
cout << "L'indice del vettore é errato!";
//messaggio di errore
}//if
return (p[i]);
//restituisci l'elemento i-esimo
}//operator[]
vettore vettore::operator+(vettore& v)
//somma 2 vettori;overloading di +
{
vettore loc(v);
//crea una copia locale del vettore in entrata
if(v.size != size)
//se il numero di elementi dei 2 vettori non coincide
{
v.errore("I vettori sono incompatibili e non si possono sommare");
//messaggio di errore
}//if
for(int i=0; i<size;i++)
//finché ho elementi
{
loc.p[i]=p[i]+v.p[i];
//aggiungo il corrispondente elemento della
}//for
//matrice in entrata
return loc;
//restituisci il vettore "somma"
}//operator+
vettore vettore::operator-(vettore& v)
//sottrazione di vettori;overloading di {
vettore loc(v);
//crea copia locale di vettore in entrata
if(v.size!=size)
//se il numero di elementi dei 2 vettori non coincide
{
v.errore("I vettori sono incompatibili e non si possono sottrarre");
//messaggio di errore
}//if
for(int i=0;i<size;i++)
//finché ho elementi
{
loc.p[i]=p[i]-v.p[i];
//sottraggo dagli elementi del vettore,quelli del
}//for
//vettore in entrata
return loc;
//restituisci il vettore "differenza"
}// operator-
164
inte vettore::operator*(vettore& v)
//prodotto scalare dei vettori;overloading di *
{
if(v.size!=size)
//se il numero di elementi dei 2 vettori non coincide
{
v.errore("I due vettori sono incompatibili e non si possono moltiplicare");
//messaggio di errore
}//if
inte s=0;
//inizializza e azzera il valore del prodotto scalare
for(int i=0;i<size;i++)
//finché ho elementi
{
s=s+p[i]*v.p[i];
//somma il prodotto dell'elemento i-esimo del
}//for
//vettore con lo stesso del vettore in entrata
return s;
//restituisci il valore del prodotto scalare
}//operator*
inte vettore::operator|(vettore& v)
//calcola il modulo del vettore
{
inte a=0;
//inizializza e azzera il valore del modulo del vettore
for(int i=0;i<size;i++)
//finché ho elementi
{
a=a+v.p[i]*v.p[i];
//somma i quadrati di tutti gli elementi
}//for
return sqrt(a);
//restituiscine la radice
}//operator|
vettore vettore::molt_per_matrice(vettore& v,matrix& mat)
//moltiplica un vettore
{
//per una matrice
vettore loc(v);
//crea una copia locale del vettore in entrata
if(size!=mat.r)
//se il numero di elementi del vettore è diverso
{
//dal numero di righe della matrice
v.errore("Errore!Il prodotto tra vettore e matrice non é possibile!");
//messaggio di errore
}//if
for(int i=0;i<size;i++)
//finché ho elementi nel vettore
{
loc.p[i]=0;
//azzero il valore dell'elemento i-esimo del vettore risultante
for(int k=0;k<mat.r;k++)
//finché ho righe della matrice in entrata
{
loc.p[i]=loc.p[i]+p[k]*mat.m[k][i];
//sommo il prodotto dell'elemento
}//for k
//k-esimo del vettore con l'elemento
}//for i
//di riga k e colonna i della matrice
return loc;
//restituisci il vettore "prodotto" V x M
}//molt_per_matrice
165
void main()
//esempio di main
{
//definizione variabili
vettore v1(d),v2(d);
//costruisce 2 vettori di dimensione d
//leggi i valori dei vettori
cin >> v1[i];
//inserisco i valori degli elementi del primo vettore da tastiera
cin >> v2[i];
//inserisco i valori degli elementi del secondo vettore da tastiera
//
v1=v1+v2;
//somma i 2 vettori
//
v1=v1-v2;
//sottrai i 2 vettori
//
dato=v1*v2;
//moltiplica i 2 vettori
//
dato=v1|v1;
//calcola il modulo del primo vettore
//
matrix m1(h,k);
//crea l'oggetto matrice m1
//leggi i valori della matrice
cin >> m1.accedi(i,j);
//assegna i valori consecutivi a m1
//
matrix m2(a,b);
//crea l'oggetto matrice m2
//leggi i valori
cin >> m2.accedi(i,j);
//assegna i valori consecutivi a m2
//
m1=m1+m2;
//somma m1 con m2,assegna il risultato a m1
//
m1=m1-m2;
//sottrai m2 a m1,assegna il risultato a m1
//
m1=m1*m2;
//moltiplica m1 con m2,assegna il risultato a m1
//
v1=v1.molt_per_matrice(v1,m1);
//moltiplica v1 per m1,assegna il risultato
//
matrice_quad t(h,h,0,0),t1(h,h,0,0);
//costruisci 2 matrici quadrate
//leggi i valori
cin >> t.accedi(i,j);
//inserisci i valori della prima
cin >> t1.accedi(i,j);
//inserisci i valori della seconda
}//main
166
Esempio di utilizzo
scrivi il numero di elementi dei vettori:3
scrivi i valori del primo vettore:1 2 3
scrivi i valori del secondo vettore:4 5 6
il vettore v1: 1 2 3
il vettore v2: 4 5 6
dopo la somma v1 modificato=v1+v2 il vettore v1: 5 7 9
dopo la differenza v1 modificato=v1-v2 il vettore v1: 1 2 3
Il prodotto scalare di v1 vale 32
Il modulo di v1 é:3
Scrivi rispettivamente il numero di righe e di colonne della prima matrice:3 3
scrivi i valori della prima matrice:
1 2 3
4 5 6
7 8 9
la matrice m1:
1 2 3
4 5 6
7 8 9
Scrivi rispettivamente il numero di righe e di colonne della seconda matrice:3 3
scrivi i valori della seconda matrice:
9 8 7
6 5 4
3 2 1
la matrice m2:
9 8 7
6 5 4
3 2 1
dopo la somma m1 modificata=m1+m2 la matrice m1:
10 10 10
10 10 10
10 10 10
...
167
Scarica

Introduzione alla programmazione in C++