Introduzione al C++ e alla
programmazione ad oggetti
Corso Specialistico CNTC
Bologna, 19-23 febbraio 2001
Andrea Dell’Acqua e Claudio Grandi
Introduzione al C++ e alla programmazione ad oggetti
Introduzione
• Le due componenti principali dei programmi:
– Algoritmi: l’insieme delle istruzioni che svolgono un
particolare compito
– Dati: ciò su cui gli algoritmi agiscono per produrre una
soluzione unica
• La relazione fra queste componenti definisce il
paradigma di programmazione
– Programmazione procedurale: problemi modellati
dagli algoritmi. Dati immagazzinati in aree comuni o
passate agli algoritmi
– Programmazione ad oggetti: problemi modellati dalle
relazioni fra tipi di dati astratti (ADT, Abstract Data
Types), chiamati generalmente oggetti
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
2
Il rapporto Dato-Algoritmo
Livello di astrazione
Programmazione
Linguaggio
macchina
Assemblers
Compilatori
Linguaggi
strutturati
Ada (Modula)
Object Oriented
Introduzione al C++ e alla programmazione ad oggetti
Dati
Algoritmi
Bits
Bits
Symbolic
Words
Variables &
Types
Data
structures
Abstract
Data Types
Objects
Op-code
Statements
Subroutines
Packages
(Modules)
Objects
19-23 febbraio 2001
3
Cos’è un oggetto?
• Né più né meno di quello che potreste trovare
scritto in un vocabolario…
– Un oggetto è un’entità che si possa immaginare dotata
di determinate caratteristiche e funzionalità.
• Lo stato di un oggetto è rappresentato da dati che
ne descrivono le caratteristiche in un certo istante
• Le funzionalità di un oggetto sono le operazioni
che può svolgere quando glie lo si richiede (cioè
quando riceve un messaggio)
• Nella nostra vita quotidiana siamo molto più
abituati a ragionare per oggetti che non in modo
strutturato!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
4
Un esempio...
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
5
Soldato
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
6
… cos’è un oggetto:
Un insieme di dati e funzioni:
Dato
Dato
Dato
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
7
Incapsulazione
• Netta divisione fra interfaccia e implementazione
• Da fuori si vede solo l’interfaccia che definisce i
messaggi accettati dall’oggetto
• I dettagli dell’implementazione (dati e codice delle
funzioni) sono invisibili dall’esterno
• Ogni oggetto ha in se tutto ciò che gli serve per
rispondere alle chiamate (o deve sapere a chi
chiedere…)
• Il confinamento di informazioni e funzionalità in
oggetti permette livelli maggiori di astrazione e
semplifica la gestione di sistemi complessi.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
8
Approccio OO
• Sono le strutture di dati che svolgono le azioni,
non le subroutines
• Il lavoro è svolto dal server, non dal client
• “Cos’ è?” “Com’ è fatto?”
 Data Oriented
• “Cosa può fare per me?”
 Object Oriented
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
9
Perché programmare per
oggetti?
• Programmare per oggetti non velocizza
l’esecuzione dei programmi...
• Programmare per oggetti non ottimizza l’uso
della memoria...
E allora perchè programmare per oggetti?
• Programmare per oggetti facilita la progettazione
e il mantenimento di sistemi software molto
complessi!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
10
Caratteristiche del software
non mantenibile
• Rigidità
– non può essere cambiato con faciltà
– non può essere stimato l’impatto di una modifica
• Fragilità
– una modifica singola causa una cascata di modifiche
successive
– i bachi sorgono in aree concettualmente separate
dalle aree dove sono avvenute le modifiche
• Non riusabilità
– esistono molte interdipendenze, quindi non è possibile
estrarre parti che potrebbero essere comuni
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
11
Programmazione ad oggetti
• La programmazione ad oggetti, attraverso
l’incapsulazione, consente di:
– ridurre la dipendenza del codice di alto livello dalla
rappresentazione dei dati
– riutilizzare del codice di alto livello
– sviluppare moduli indipendenti l’uno dall’altro
– avere codice utente che dipende dalle interfacce ma
non dall’implementazione
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
12
C++ e Object Orientation
• Il C++ può essere usato come linguaggio
procedurale o per programmazione ad oggetti
• Object Orientation implementata attraverso il
concetto di classe
• Prima di affrontare il problema della
programmazione OO con C++ dobbiamo:
– capire dove la programmazione procedurale fallisce
– affrontare la sintassi del C++
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
13
Programmazione
procedurale
• Esempio: cinematica relativistica
Idea:
perché non usare una
function?
COMMON /MYDATA/ P1(4), P2(4),
+
P3(4), P4(4)
REAL P1(4), P2(4), P3(4), P4(4)
COSTHETA12 = (P1(1)*P2(1) + P1(2)*P2(2) +
+
P1(3)*P2(3))/...
COSTHETA13 = (P1(1)*P3(1) + P1(2)*P3(2) +
+
P1(3)*P3(3))/...
COSTHETA14 = (P1(1)*P4(1) + P1(2)*P4(2) +
+
P1(3)*P4(3))/...
FUNCTION COSTHETA(P1, P2)
REAL P1(4), P2(4)
COSTHETA = (P1(1)*P2(1) + P1(2)*P2(2) +
+
P1(3)*P2(3))/...
END
COMMON /MYDATA/ P1(4), P2(4),
+
P3(4), P4(4)
REAL P1(4), P2(4), P3(4), P4(4)
COSTHETA12 = COSTHETA(P1, P2)
COSTHETA13 = COSTHETA(P1, P3)
COSTHETA14 = COSTHETA(P1, P4)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
14
Evoluzione del codice
• Se cambia il formato del common block?
COMMON /MYDATA/ P(4),
P1(4),E(4),
P2(4),
THETA(4),
P3(4), P4(4)
PHI(4)
• Bisogna cambiare la funzione (gli argomenti sono
FUNCTION COSTHETA1(THETA1, THETA2,
diversi)
+
PHI1,
PHI2)
COSTHETA1 = SIN(THETA1)*SIN(THETA2) *
+
COS(PHI1-PHI2) + COS(THETA1)*COS(THETA2)
END
• ...e il codice!
COMMON /MYDATA/ P(4), E(4),
+
THETA(4), PHI(4)
COSTHETA12 = COSTHETA1(THETA(1),THETA(2),
+
PHI(1), PHI(2))
COSTHETA13 = COSTHETA1(THETA(1),THETA(3),
+
PHI(1), PHI(3))
COSTHETA14 = COSTHETA1(THETA(1),THETA(4),
+
PHI(1), PHI(4))
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
15
Il concetto di dipendenza
• Nell’esempio precedente il codice di analisi (“alto
livello”) dipende dai dettagli della struttura dati
(“basso livello”).
FUNCTION COSTHETA(P1, P2)
REAL P1(4), P2(4)
COSTHETA = (P1(1)*P2(1) + P1(2)*P2(2) +
+
P1(3)*P2(3))/...
END
COMMON /MYDATA/ P1(4), P2(4),
+
P3(4), P4(4)
COSTHETA12 = COSTHETA(P1, P2)
COSTHETA13 = COSTHETA(P1, P3)
COSTHETA14 = COSTHETA(P1, P4)
Introduzione al C++ e alla programmazione ad oggetti
COSTHETA dipende
dalla struttura dei dati
P1 e P2
Il codice di analisi dipende
dalla struttura del common
block MYDATA
19-23 febbraio 2001
16
OO riduce le dipendenze!
• Riduce la dipendenza del codice di alto livello
dalla rappresentazione dei dati
Permette il riutilizzo del codice di alto livello
• Nasconde i dettagli di implementazione
Supporta tipi di dati astratti
(vedere seguito  ...)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
17
Sintassi: FORTRAN vs C/C++
• Struttura del programma
In C/C++ non è necessario un particolare formato il codice
PROGRAM TEST
C esempio di programma
int main() {
// esempio di programma
...
...
spazi...
return 0; // fine
END
}
Il C/C++ è case sensitive
INTEGER I
INTEGER*4 J
REAL X
REAL*8 D
Introduzione al C++ e alla programmazione ad oggetti
Istruzioni separate da “;”
int i;
long j;
float x;
double d;
19-23 febbraio 2001
18
Il main program
• Ogni programma in C++, per essere
eseguibile, deve contenere una funzione
main() da cui l’esecuzione comincerà
• main() deve avere un tipo (decidere quale è
compito del programmatore). Regola generale
è che main() ritorni un intero, a significare il
return code dell’applicazione
int main()
{
// il piu` semplice programma in C++
return 0;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
19
I/O: lettura e scrittura
• Non esiste nel C++ nativo. Si usa: iostream
#include <iostream>
– Gli operatori << e >> sono usati per definire la
direzione del flusso
– cin, cout e cerr rappresentano lo standard input,
output e error del programma
#include <iostream>
int main()
{
cout << “Hello, world !” << endl;
return 0;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
direttiva al
preprocessore
end of line
20
Commenti
• Esistono due tipi di commento in C++
– inline:
const int Ntries; // questo e` un commento inline
// il resto della linea e’ trattato come un commento
– multiline (come in C):
const int Ntries;
/* questo e` un commento multiline:
tutto viene trattato come un commento
fino a quando il commento stesso non
viene chiuso con uno */
– I due tipi possono essere usati indifferentemente, ma
si raccomanda di usare l’inline (più semplice e meno
ambiguo)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
21
Tipi predefiniti in C++
• Sono definiti una serie di tipi numerici che
permettono di rappresentare numeri interi, reali e
caratteri
int
long
float
double
long double
unsigned int
unsigned double
char
bool
intero in singola precisione
intero in doppia precisione
reale in singola precisione
reale in doppia precisione
reale in precisione estesa
intero senza segno
reale senza segno in doppia precisione
carattere singolo
variabili logiche
– char (un solo byte) viene normalmente usato per
rappresentare interi inferiori a 256
– stringhe e numeri complessi sono implementati come
tipi derivati
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
22
Tipi predefiniti in C++ (2)
Costanti carattere
Esempi di costanti
123
123
0x123
123l
123u
‘A’
3.14f
‘1’
‘\t’
3.1415 3.1415L
300e-2 .03e2
interi costanti,
decimale, ottale,
esadecimale
interi, long,
unsigned
caratteri, tab
float, double,
long double
double, notazione
esponenziale
stringa costante
boolean
30e-1
“Nome”
true
false
‘\a’
‘\\’
‘\b’
‘\r’
‘\”’
‘\f’
‘\t’
‘\n’
‘\0’
‘\’’
‘\v’
‘\101’
‘\x041’
alert
backslash
backspace
carriage return
double quote
form feed
tab
newline
carattere nullo
single quote
vertical tab
101 ottale, ‘A’
esadecimale, ‘A’
Stringhe costanti
“”
“nome”
“una \”stringa\””
“una stringa \
su piu` linee”
Introduzione al C++ e alla programmazione ad oggetti
stringa nulla (‘\0’)
‘n’ ‘o’ ‘m’ ‘e’ ‘\0’
stampa: una “stringa”
un \ alla fine della linea
per continuare la stringa
19-23 febbraio 2001
23
Tipi predefiniti in C++ (3)
OS
OS
OS
16 bit 32 bit 64 bit
char[1]
8
8
8
int[1]
16
32
32
bool
16
32
32
short[1]
16
16
16
long[1]
32
32
64
float
32
32
32
double
64
64
64
long double
64
128
Introduzione al C++ e alla programmazione ad oggetti
128
[1] Può essere unsigned
19-23 febbraio 2001
24
Identificatori
• Un identificatore è composto da uno o più caratteri
• Il primo carattere deve essere una lettera o un
underscore. Caratteri successivi possono essere
lettere, numeri o underscore const int Ntries;
double _attempts;
double 2A; // errore!
• Non c’ è un limite in lunghezza, anche se alcuni
sistemi si limitano a considerare i primi 31 caratteri
• Gli identificatori che iniziano con un doppio
underscore o con un underscore e una lettera
maiuscola sono riservati ad usi di sistema
• C++ e` case sensitive!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
25
Keywords
• Alcuni identificatori sono esplicitamente riservati al
sistema (hanno un preciso significato in C++) e non
possono essere usati
asm
auto
bool
break
case
catch
char
class
const
const_cast
continue
default
delete
do
double
dynamic_cast
else
enum
explicit
extern
false
float
for
friend
goto
if
inline
int
long
mutable
namespace
new
Introduzione al C++ e alla programmazione ad oggetti
keyword
operator
private
protected
public
register
reinterpret_cast
return
short
signed
sizeof
static
static_cast
struct
switch
template
this
19-23 febbraio 2001
throw
true
try
typedef
typeid
typename
union
unsigned
using
virtual
void
volatile
wchar_t
while
26
const
• La keyword const viene utilizzata per
dichiarare un oggetto costante
Esempi di const
const int N=100;
double w[N];
const int vect[5]=
{10,20,30,40,50};
N non puo` essere cambiato
N usato come per dimensionare
un vettore
le componenti di vect non
possono essere cambiate
• In C le costanti vengono normalmente dichiarate
usando il preprocessore #define N 100
– in questo caso N e` una costante senza tipo ed il
preprocessore sostituisce N ovunque lo trovi nel
programma, senza rispettare le regole di scope (da
evitare)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
27
Dichiarazione
• Le dichiarazioni associano un significato ad
un identificatore
• in C++ ogni cosa deve essere dichiarata per
poter essere usata
const int i;
double max(double r1,double r2);
// la variabile i
// la funzione max
• Una dichiarazione è spesso anche una
definizione. Per variabili semplici questo
consiste nell’associare un valore alla variabile
al momento della dichiarazione
const double pi=3.1415926;
double max(double r1, double r2) {
return (r1>r2) ? r1: r2;
}
Introduzione al C++ e alla programmazione ad oggetti
// definizione
// dichiarazione
// definizione di max
19-23 febbraio 2001
28
typedef
• L’istruzione typedef viene utilizzata per
creare un alias per tipi esistenti
typedef int INTEGER;
typedef int BOOLEAN;
typedef void (*ptr_f)();
//
//
//
//
//
per i nostalgici del fortran
usato prima che bool venisse
implementato
ptr_f e` un puntatore ad una
procedura (subroutine)
• typedef NON può essere usato per
implementare nuovi tipi, ma solo per definire
un alias
typedef mela frutto;
Introduzione al C++ e alla programmazione ad oggetti
// compila soltanto se mela
// e` gia` stata definita
19-23 febbraio 2001
29
Enumeratori
• In C++ sono supportati tipi definiti dall’utente
enum Color
{
red, green, blue
};
Color screenColor = blue;
Color windorColor = red;
int
n = blue; // valido
Color c = 1;
// errore
enum Seme
{
cuori, picche, quadri, fiori
};
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
30
Scope
• Le variabili possono essere dichiarate e definite
quasi ovunque in un programma in C++
• la visibilità (scope) di una variabile dipende da
dove la variabile è stata dichiarata
int func()
{
…
const int n=50;
for (int i=0;i<100;i++)
{
double r;
...
}
cout<<“n “<< n <<endl;
cout<<“i “<< i <<endl;
cout<<“r “<< r <<endl;
…
}
Introduzione al C++ e alla programmazione ad oggetti
// function scope
// i e` locale
// r e` locale
// OK
// errore! Ma...
// errore!
19-23 febbraio 2001
31
Scope (2)
• Attenzione! La stessa variabile può essere ridichiarata (con visibilità diversa). Questo è da
evitare (se possibile) per non rendere il
programma oscuro e a rischio di errore!
int i;
int func()
{
int i=50;
// file (global) scope
// function scope, nasconde
// la i a file scope
for (int i=0;i<100;i++)
// block scope. Nasconde
// la i a function scope
{
int i;
// questo e` un errore...
...
}
cout<<“i “<< i <<“ “<< ::i <<endl;
...
}
Introduzione al C++ e alla programmazione ad oggetti
Scope resolution operator
19-23 febbraio 2001
32
namespace
• Funzioni e variabili definite a global scope sono
visibili dappertutto in un programma in C++
– Per evitare che funzioni diverse (definite in librerie
diverse) con lo stesso nome possano interferire (name
clash), C++ implementa il concetto di namespace, che
introduce un ulteriore, più alto livello di scope
namespace mynames
{
int i;
float max(float, float);
}
// la mia dichiarazione di i
// la mia dichiarazione di max
float mynames::max(float a, float b) // implementazione della
{
// funzione max appartenente
return (a>b) ? a : b;
// al namespace mynames
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
33
namespace (2)
• Per utilizzare variabili e funzioni racchiuse in
un namespace si può:
– o accedere all’intero namespace
using namespace mynames;
...
float r = max (2.1f, 5.3f);
– oppure accedere alla singola variabile o funzione
float r = mynames::max (2.1f, 5.3f);
– oppure dichiarare la singola funzione
using mynames::max;
...
float r = max (2.1f, 5.3f);
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
34
Operatori
Espressioni Aritmetiche
Auto-incremento
e decremento
k
k
k
k
=
=
=
=
++j;
j++;
--j;
j--;
+w
a/b
a+b
a-b
i%2
a=3;
Espressione
j=j+1; k=j;
k=j; j=j+1;
j=j-1; k=j;
k=j; j=j-1;
bit-wise
~i;
i&j;
i|j
i^j
i<<n
i>>n
-i
a*b
significato
piu` e meno unari
moltiplicazione,
divisione, modulo
addizione e
sottrazione binarie
assegnazione
Operatori relazionali
<
>
<=
>=
==
!=
!
&&
||
Complemento bit a bit
AND bit a bit
OR bit a bit
XOR bit a bit
shift a sinistra di n pos.
shift a destra di n pos.
Introduzione al C++ e alla programmazione ad oggetti
Commento
minore di
maggiore di
minore o uguale
maggiore o uguale
uguale
diverso
Negazione unaria
and logico
or logico
19-23 febbraio 2001
Fortran
.LT.
.GT.
.LE.
.GE.
.EQ.
.NE.
.NOT.
.AND.
.OR.
35
Espressioni di assegnazione
• Le espressioni di assegnazione sono valutate da
destra a sinistra
a = j++;
j viene incrementato ed il risultato assegnato ad a
• Le assegnazioni multiple sono permesse
a = b = c = d = 100;
• alcuni operatori di assegnazione combinano
assegnazione ed altri operatori
a *= b;
a -= b;
// equivale ad
// equivale ad
a = a*b;
a = a-b;
• Assegnazioni possono essere fatte all’interno di
espressioni aritmetiche
a = b + ( c = 3 );
Introduzione al C++ e alla programmazione ad oggetti
// equivale a c=3; a=b+c;
19-23 febbraio 2001
36
Statements
Statement
C++
commenti
vuoto
espressione
composto
;
j=j+k;
{ . . . . }
goto
if
goto label;
if (p==0)
cerr<<“error”;
if (x==y)
cout<<“the same”;
else
cout<<“different”;
for (j=0;j<n;j++)
a[j]=0;
while (i != j)
i++;
do
y=y-1;
while (y>0);
break;
continue;
if-else
for
while
do-while
break
continue
Introduzione al C++ e alla programmazione ad oggetti
usato in funzioni, if..
Costituisce un blocco
da non usarsi
un solo branch
due branch
le dichiarazioni sono
permesse
0 o piu` iterazioni
1 o piu` iterazioni
esce dal blocco
prossima iterazione
19-23 febbraio 2001
37
Statements (2)
Statement
switch
C++
commenti
dichiarazione
switch (s) {
case 1:
++i;
case 2:
--i;
default:
++j;
};
int i=7;
try
try {. . . .}
label
error:
cerr<<“Error!”;
return x*x*x;
return
Introduzione al C++ e alla programmazione ad oggetti
si deve usare break per
evitare di cadere nei
casi successivi e
aggiungere un caso di
default alla fine della
lista
in un blocco, file o
namespace
usato per trattare le
eccezioni
usato con goto
valore di ritorno di
una funzione
19-23 febbraio 2001
38
Statement composti
• Uno statement composto in è costituito da una
serie di statement contenuti fra parentesi graffe
• Usato normalmente per raggruppare istruzioni in
un blocco (if, for, while, do-while, etc.)
• Il corpo di una funzione è sempre uno statement
composto
• La dichiarazione di una variabile può avvenire
ovunque all’interno di un blocco, in questo caso lo
scope della variabile sarà il blocco stesso
• Ovunque si possa usare uno statement singolo si
può definire un blocco
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
39
if
• Attenzione all’uso di = e ==
if (i=1)
{. . . .}
// questo e` sempre vero!!!
• Nel dubbio, usare sempre un blocco…
if (i != 0)
a++;
a/=i;
// possibile divisione per 0
// mancano delle {}?
• Attenzione agli else!
if (i == 0)
if (a<0)
{
// possibile divisione per 0
cerr<<“a e` negativo!”;
}
else
b=a/i;
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
40
while e do-while
• La forma generale di un while è :
while (condizione)
statement;
• Lo statement verrà eseguito fino a quando la
condizione verrà verificata (true). A seconda del
volore della condizione, lo statement verrà
eseguito zero o più volte
• la sintassi di un do-while è invece:
do
statement;
while (condizione);
• Lo statement verrà quindi eseguito almeno una
volta
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
41
break e continue
• break e continue sono utilizzati nei loop per
saltare alla fine del loop o fuori dal loop stesso
int i,n=0;
int a[100];
cin>>i;
// leggo il valore di i
while (1)
// loop infinito
{
if (i<0) break;
if (n>=100) continue;
a[n]=i;
n++;
// continue salta qui
}
// break salta qui
• break e continue possono solamente essere
utilizzati nel corpo di un for, while o dowhile. break e` anche usato negli switch
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
42
switch
• Lo switch è uno statement condizionale che
generalizza lo if-else
switch (condizione)
(statement);
• lo statement è generalmente composito e
consiste di diversi case e, opzionalmente, di
un default
switch (n) {
case 0:
cout<<“ n e` nullo”<<endl; break;
case 1: case 3: case 5: case 7: case 9:
cout<<“ n e` dispari”<<endl; break;
case 2: case 4: case 6: case 8: case 10:
cout<<“ n e` pari”<<endl; break;
default:
cout<<“ n non e` compreso tra 0 e 10”<<endl;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
43
switch (2)
• Non si puo` dichiarare una variabile in uno dei case
switch (k)
case 0:
int
. .
case 1:
. .
}
{
j=0;
.
// Illegale! Errore!
.
• … ma si puo` creare una variabile locale definendo
uno statement composto...
switch (k) {
case 0:
{
int j=0;
. . .
}
case 1:
. . .
Introduzione al C++ e alla programmazione ad oggetti
}
// OK, questo compila
19-23 febbraio 2001
44
L’operatore ?
• L’operatore ? e` l’unico esempio di operatore
ternario in C++
expr1 ? expr2 : expr3;
– Equivale a:
if(expr1)
expr2;
else
expr3;
– Esempio:
double max(double a, double b)
{
double max = (a>b) ? a : b;
return max;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
45
Sintassi: FORTRAN vs C/C++
• Controllo di flusso del programma
DO I = 1, 10
. . .
ENDDO
IF (I.EQ.10 .AND. J.GT.4 .OR. X) THEN
. . .
ENDIF
DO WHILE(X .NE. 5)
. . .
ENDDO
Introduzione al C++ e alla programmazione ad oggetti
for (i = 1; i <= 10; i++)
{
. . .
}
if (i == 10 && j > 4 || x)
{
. . .
}
while( x != 5 )
{
. . .
}
19-23 febbraio 2001
46
Funzioni matematiche
• In C++ non esistono funzioni predefinite
#include <iostream>
#include <cmath>
cmath.h definisce sin, cos, ...
int main()
{
double r, theta, phi;
cin >> r >> theta >> phi ;
double x = r * sin( theta ) * sin( phi );
double y = r * sin( theta ) * cos( phi );
double z = r * cos( theta );
cout << x << “, “ << y << “, “ << z << endl;
return 0;
}
• Potenze: pow(b,exp) (non si può usare ** )
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
47
Array
• Sono supportati gli array di dimensione fissa
int main()
{
int x[10];
for ( int i = 0; i < 10, i++ )
x[i] = 0;
double m[5][5];
for ( int i = 0; i < 5; i++ )
for ( int j = 0; j < 5; j++ )
m[i][j] = i * j;
return 0;
}
• Inizializzazione:
int x[] = { 1, 2, 3, 4 };
char[] t =
{ ‘C’, ‘i’, ‘a’, ‘o’, ‘\0’ };
char[] s = “Ciao”;
int m[2][3] =
{ {11, 12, 13}, {21, 22, 23} };
• L’indice va da 0 a n-1. Usare un indice
maggiore di n-1 può causare un crash.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
48
Esempio con gli arrays
• Moltiplicazione fra matrici:
int main() {
const int DIM=3;
float m[DIM][DIM], m1[DIM][DIM], m2[DIM][DIM];
// Assumiamo che m1 ed m2 vengano riempiti qui...
// Moltiplicazione:
for (int i=0; i<DIM; i++) {
for (int j=0; j<DIM; j++) {
float sum=0;
for (int k=0; k<DIM; k++)
sum += m1[i][k] * m2[k][j];
m[i][j] = sum;
}
}
return 0;
Introduzione al C++ e alla programmazione ad oggetti
}
19-23 febbraio 2001
49
Puntatori
• Riferimento ad una locazione di memoria
#include <iostream>
ptr
j
24
12
int main()
{
int j = 12;
int *ptr = &j;
cout << *ptr << endl;
j = 24;
cout << *ptr << endl;
cout << ptr << endl;
return 0;
}
12
24
0x7b03a928
Introduzione al C++ e alla programmazione ad oggetti
indirizzo di memoria
19-23 febbraio 2001
50
Puntatori
• Puntatore nullo
#include <iostream>
ptr
j
12
int main()
{
int j = 12;
int *ptr = 0;
cout << *ptr << endl; // crash !
return 0;
}
Segmentation violation (core dumped)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
51
Puntatori e array
• In C gli array sono trattati come puntatori
X[0]
1.5
X[1]
2.5
x
X+1
int main()
{
float x[5];
int j;
for (j = 0; j < 5; j++)
x[j] = 0;
float *ptr
*ptr
=
*(ptr+1) =
*(ptr+3) =
X[2]
0.0
X[3]
3.5
X[4]
0.0
X+3
= x;
1.5; // x[0] = 1.5
2.5; // x[1] = 2.5
3.5; // x[3] = 3.5
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
52
Puntatori: allocazione
dinamica
• Riferimento ad una locazione di memoria
#include <iostream>
ptr
12
int main()
{
int *ptr = new int;
*ptr = 12;
cout << *ptr << endl;
delete ptr;
return 0;
}
• Attenzione:
– Non usare delete fa accumulare locazioni di
memoria inutilizzate (memory leak)
– Utilizzare puntatori prima del new o dopo il
delete causa il crash del programma
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
53
Puntatori: allocazione
dinamica
• Riferimento a più locazioni di memoria
#include <iostream>
int main()
{
int *ptr = new int[3];
ptr[0] = 10;
ptr[1] = 11;
ptr[2] = 12
delete [] ptr;
return 0;
}
ptr
10
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
11
12
54
new e delete
• Gli operatori new and delete vengono utilizzati
per allocazione/deallocazione di memoria dinamica
– la memoria dinamica (heap), è un’area di memoria libera
provvista dal sistema per quegli oggetti la cui durata di
vita è sotto il controllo del programmatore
operatore new
int *i=new int;
char *c=new char[100];
int *i=new int(99);
char *c=new char(‘c’);
int *j=new int[n][4];
commenti
alloca un
alloca un
caratteri
alloca un
alloca un
alloca un
intero, returna il puntatore
array (stringa) di 100
intero e lo inizializza a 99
carattere inizializzato a c
array di puntatori ad intero
• new riserva la quantità necessaria di memoria
richiesta e ritorna l’indirizzo di quest’area
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
55
new e delete (2)
• L’operatore delete è usato per restituire una
certa area di memoria (allocata con new) allo heap
• Ogni oggetto allocato con new deve essere
distrutto con delete se non viene piu` utilizzato,
altrimenti l’area di memoria che esso occupata
non potra` piu` essere ri-allocata (memory leak)
• L’argomento di delete è tipicamente un
puntatore inizializzato preventivamente con new
operatore delete
delete ptr;
delete p[i];
delete [] p;
Introduzione al C++ e alla programmazione ad oggetti
commenti
distrugge un puntatore ad un oggetto
distrugge l’oggetto p[i]
distrugge ogni oggetto di tipo p
19-23 febbraio 2001
56
new e delete (3)
• Attenzione
– la dimensione dello heap non e` infinita
– l’allocazione con new può fallire, nel qual caso new
restituisce un puntatore nullo o suscita un’eccezione.
Nel caso di allocazione di memoria importante
bisogna verificare che l’operazione abbia avuto
successo prima di usare il puntatore
– ogni oggetto creato con new deve essere distrutto
con delete, ogni oggetto creato con new [] deve
essere distrutto con delete [] , queste forme
NON sono intercambiabili
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
57
Regole di conversione e
cast
• In C++ esistono conversioni esplicite ed implicite.
– Le conversioni implicite (e.g. intfloat) nelle
espressioni aritmetiche, nel passare i parametri ad una
funzione o nel ritornare un valore da una funzione
rendono il meccanismo di conversione molto
conveniente ma anche potenzialmente pericoloso
(errori a run time)
Conversioni implicite
•char, short e bool vengono promossi ad int
•Tipi interi che non possono essere rappresentati con un int vengono
promossi a unsigned
•In una espressione di tipo misto, gli operandi di ordine inferiore
vengono promossi all’ordine superiore secondo la gerarchia:
int<unsigned<long<unsigned long<float<double<long double
•bool e` un tipo intero, con true che viene promosso a 1 e false a 0
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
58
Regole di conversione e cast (2)
• Ogni genere di puntatore può essere convertito in
un puntatore generico a void
• Al contrario di quanto avviene in C, un puntatore
generico non è compatibile con un puntatore di tipo
arbitrario ma richiede un cast esplicito
char *ch;
void *generic_p;
. . .
generic_p=ch;
// OK, char* va in void*
ch=generic_p;
// OK in C, illegale in C++
ch=(char *)generic_p; // OK, C e C++ arcaico
• Ogni puntatore puo` essere inizializzato a 0 senza
bisogno di un cast esplicito.
• In C++ usare 0 e non NULL per i puntatori!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
59
Casting in ANSI C++
• Data la complessità delle operazioni di casting in
C++ nuovi operatori di casting sono stati aggiunti a
quelli già esistenti in C
Cast
commenti
x=(float) i;
cast in C++ - notazione C
x=float(i);
cast in C++, notazione funzionale
x=static_cast<float>(i);
ANSI C++ - raccomandato
i=reinterpret_cast<int>(&x)
ANSI C++, non portabile e system
dependent
dove C_var e` una variabile dichiarata
const. Usato per eliminare la
“const-ness” per chiamare func
func(const_cast<int>(c_var))
• Esiste anche un dynamic_cast, utilizzato per
riconoscere il tipo di un oggetto a run-time (RTTI)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
60
Funzioni
• In C++ le funzioni sono caratterizzate da un nome,
dal tipo della variabile ritornata e da una lista di
parametri (opzionali)
Tipo ritornato
Corpo della
funzione
Parametri
double max( double a, double b)
{
return (a>b) ? a : b;
}
Valore di ritorno
• La lista dei parametri (anche se vuota) deve
essere esplicitata
• Il valore ritornato deve essere compatibile, a meno
di conversione esplicita, con il tipo della funzione
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
61
Funzioni (2)
Tipo di dichiarazione
C++
commenti
funzione
double cube(double x)
{ return x*x*x; }
parametri passati
“by value”
procedura
void pr_square(int i)
{ cout<<i*I<<endl; }
subroutine, non si
usa return
senza argomenti
void hello ()
{ cout<<“Hello”<<endl; }
puo` anche essere
void hello(void)
argomenti passati
per riferimento
void swap(int& i,int& j)
{ int t=i; i=j; j=t; }
i e j hanno i loro
valori scambiati
variabile
int scanf(const char,
inline
inline double cube(int x)
codice inline
argomenti di
default
int power(int i, int n=2)
il 2do argomento
puo` essere
tralasciato
Introduzione al C++ e alla programmazione ad oggetti
…)
chiamata con un
qualsiasi numero
di argomenti
19-23 febbraio 2001
62
Prototipi delle funzioni
• Prima di essere usata, una funzione deve essere
dichiarata (nel file che la usa)
main.cc
max.cc
#include <iostream>
double max (double a, double b)
double max(double, double);
{
int main()
return (a>b) ? a : b;
{
}
double m = max(1, 3);
cout<<“Il massimo e` “<<m<<endl;
Prototipo di max
return 0;
}
(normalmente in max.h)
• I prototipi rendono le funzioni in C++ “type safe”,
nel senso che i valori reali degli argomenti
vengono all’occorrenza convertiti nei tipi formali
specificati dal prototipo
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
63
Call-by-Reference
• L’uso dei riferimenti permette ad una funzione di
modificare il valore dei suoi argomenti
bool greater(int& i, int& j) { // se i>j scambia i e j
if (i>j) {
int temp=i;
Argomenti passati “by reference”
i=j;
possono essere modificati dalla
j=temp;
funzione stessa
return true;
}
else
return false;
}
– Per ragioni di efficenza, oggetti di grandi dimensioni (in
termini di memoria) vengono normalmente passati “by
reference”.
– Per evitare che possano essere modificati dalla
funzione, il riferimento viene definito const
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
64
Funzioni inline
• La keyword inline suggerisce al compilatore
che ogni chiamata alla funzione deve essere
convertita in codice eseguibile (la definizione
della funzione viene sostituita alla chiamata
dovunque nell codice)
• Le funzioni inline vengono usate per ragioni di
efficienza e (per non sovraccaricare il
compilatore) devono essere semplici
• Il compilatore può decidere autonomamente (per
esempio se la funzione è troppo lunga) di
ignorare la direttiva inline
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
65
Argomenti di default
• Ad ogni parametro di una funzione può essere
assegnato un valore di default. Questo permette di
chiamare la funzione tralasciando quei parametri il
cui valore di default risulta appropriato
main.cc
pow.cc
int pow(int , int);
int main()
{
int r=3;
int a1=pow(3,3);
int a2=pow(3);
return 0;
}
// a1=27
// a2=9
int pow (int a, int k=2)
{
if (k==2) return a*a;
else return a*pow(a, k-1);
}
Argomento di default
• Solo ai parametri più a destra nella calling
sequence può essere dato un default.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
66
Overloading
• Funzioni diverse possono avere lo stesso nome
• La funzione che viene chiamata è scelta dal
compilatore in base al tipo di ritorno ed al
numero e tipo degli argomenti
average_array.cc
double average_array(const int a[], int size)
{
int sum=0;
for (int i=0;i<size;i++) sum+=a[i];
return double(sum)/size;
}
double average_array(const double a[], int size)
{
double sum=0;
for (int i=0;i<size;i++) sum+=a[i];
return sum/size;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
67
Overloading (2)
• La lista dei tipi degli argomenti di una funzione è
chiamata signature
• Il tipo ritornato dalla funzione non fa parte della
signature, mentre il numero e l’ordine degli
argomenti è cruciale
void print(int i=0) {. . .}
// (1)
void print(int i, double x) {. . .} // (2)
void print(double y, int i) {. . .} // (3)
. . .
print(‘A’);
// ‘A’ e` convertito a int, chiama (1)
print(str[]); // errore! Non e` possibile una conversione
print(15,9);
// errore! Ambiguita` fra (2) e (3)
print(15,9.); // OK, chiama (2)
print();
// OK, chiama (1) con il default
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
68
L’algoritmo di selezione
Ricerca della corrispondenza esatta
Promozioni standard degli argomenti
int  long
Conversioni standard dei tipi
int  float
Conversioni definite dall’utente
traccia  int
Corrispondenza con l’ellipsi (…)
• L’utente può sempre utilizzare una conversione
forzata (type cast) per ottenere una corrispondenza
• Il compilatore segnala tutti i casi in cui esiste
ambiguità
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
69
Funzioni esterne
• Si possono chiamare funzioni FORTRAN da C++:
SUBROUTINE HBOOK1(ID, TITLE, NBIN, MIN, MAX, OPT)
SUBROUTINE HFILL(ID,X, Y, WEIGHT)
extern “C” void hbook1_(int&, char*, int&, float&, float&,
float&, int);
extern “C” void hfill_(int&, float&, float&, float&);
...
hbook1_(100, title, ……)
// BUS ERROR!!! (il FORTRAN passa
// sempre “by-reference”
int id=100;
hbook1_(id, title, ……)
Introduzione al C++ e alla programmazione ad oggetti
// OK!
19-23 febbraio 2001
70
Parametri del programma
• Dotando main() di una lista di argomenti, è
possibile avere accesso ai parametri passati dalla
command line:
#include <iostream.h>
int main(int argc, char *argv[])
{
cout<<“ argc e`: “<<argc<<endl;
cout<<“ il nome dell’eseguibile e` “<<*argv<<endl;
for (int i=1; i<argc; i++)
cout<<“Argomento #”<<i<<“ = “<<*(argv+i)<<endl;
return 0;
}
• argc è il numero di parametri passati dalla
command line (sempre almeno 1, il nome del
programma) mentre il vettore di stringhe argv
contiene ogni singolo parametro
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
71
Parametri del programma
(2)
• Lanciato con il comando
prompt> mytest questo e un test
• il programma produrra` il seguente output:
argc e` : 5
il nome dell’eseguibile e`/user/andrea/myprogram
Argomento #1 = questo
Argomento #2 = e
Argomento #3 = un
Argomento #4 = test
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
72
Organizzazione dei files
• Normalmente, le dichiarazioni delle interfacce e le
specifiche sono separate dall’implementazione
– header files (.h o .hh)
• inclusi nei file sorgente utilizzando direttive del precompilatore
#include <iostream.h>
• non contengono codice eseguibile (con l’eccezione delle definizioni delle
funzioni inline)
• non devono essere inclusi piu` di una volta, per evitare problemi con il
linker
#ifndef MyHeader_H
#define MyHeader_H
// dichiarazioni
…..
#endif
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
73
Organizzazione dei files (2)
– Files sorgente (.C,.cxx,.cpp,.cc)
• contengono l’implementazione di funzioni e metodi
• codice eseguibile
• includono gli header files utilizzando le direttive del
preprocessore
• vengono compilati
– Funzioni inline (.icc)
• La definizione di una funzione inline deve essere visibile
là dove viene usata.
• Normalmente implementate negli header files o in files
separati (con estensione .icc) che devono essere
inclusi nel files sorgente che ne facciano uso
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
74
C++ e Object Orientation
• Definizione di nuovi tipi (oltre a int, float,
double) come:
• numeri complessi,
• vettori,
• matrici, . . .
• ma anche:
• traiettorie,
• superfici,
• elementi di apparati sperimentali,...
• Gli oggetti permettono di modellare una
problema che rappresenti la realtà
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
75
…C++ e Object Orientation
• Object Orientation implementata in C++
attraverso il concetto di classe:
• I dati privati (o attributi) di una classe definiscono
lo stato dell’oggetto
• Le funzioni (o metodi) di una classe
implementano la risposta ai messaggi
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
76
Una classe C++
Attributo
Attributo
Attributo
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
77
Classe Vector2D
• Un esempio: un vettore bidimensionale
Vector2D.h
costruttore
class Vector2D
{
public:
Vector2D(double x, double y);
double x();
double y();
Vector2D.cc
double r();
double phi();
#include “Vector2D.h”
private:
Vector2D::Vector2D(double x, double y): x_(x),
double x_;
y_(y) {
double y_
}
};
double Vector2D::x() {
return x_;
}
funzioni o metodi
dati o attributi
Punto e virgola!
double Vector2D::r() {
return sqrt( x_*x_ + y_*y_);
}
...
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
78
Interfaccia e
implementazione
• Gli attributi privati non sono accessibili al di fuori
della classe
• I metodi pubblici sono Vector2D.cc
gli unici visibili
#include “Vector.h”
Vector2D.h
class Vector2D
{
public:
Vector2D(double x, double y);
double x();
double y();
double r();
double phi();
private:
double x_;
double y_;
};
Introduzione al C++ e alla programmazione ad oggetti
Vector2D::Vector2D(double x,
double y) :
x_(x), y_(y)
{}
double Vector2D::x()
{
return x_;
}
double Vector2D::r()
{
return sqrt(x_*x_ + y_*y_);
}
19-23 febbraio 2001
79
Costruttori e distruttori
• Un costruttore è un metodo il cui nome è quello
della classe a cui appartiene
• Lo scopo di un costruttore è quello di costruire
oggetti del tipo della classe. Questo implica
l’inizializzazione degli attributi e, frequentemente,
allocazione di memoria dallo heap
• Un costruttore la cui lista di argomenti è vuota o
composta di argomenti di default viene
normalmente chiamato costruttore di default
Vector2D::Vector2D() {. . . .}
// costruttore di default
#include “Vector2D.h”
. . .
Vector2D v;
// oggetto costruito con il
// costruttore di default
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
80
Costruttori e distruttori (2)
• Un costruttore del tipo che ha come argomento un
riferimento ad un oggetto della stessa classe viene
chiamato copy constructor
Vector2D::Vector2D(const Vector2D& v) {. . . .}
• Il copy constructor viene normalmente utilizzato:
– quando un oggetto è inizializzato per assegnazione
Vector2D v(v1);
// dove v1 e` di tipo Vector2D
– quando un oggetto è passato come argomento ad una
funzione
– quando un oggetto è ritornato da una funzione
• Se non viene fornito esplicitamente dall’utente, il
compilatore ne genererà uno automaticamente
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
81
Costruttori e distruttori (3)
• Gli attributi di una classe possono essere
inizializzati nel costruttore per mezzo di una lista di
inizializzatori, che precede il corpo della funzione
Vector2D::Vector2D(double x, double y) : x_(x), y_(y)
{
. . .
}
• Quando uno degli attributi è esso stesso una
classe, il costruttore appropriato viene scelto sulla
base dei parametri forniti nell’inizializzazione
• E` obbligatorio inizializzare gli attributi (non statici)
che siano o riferimenti o const
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
82
Costruttori e distruttori (4)
• Il distruttore è un metodo il cui nome è quello della
classe a cui appartiene preceduto da una tilde (~)
• Il distruttore viene chiamato automaticamente
quando un oggetto sta per essere distrutto (sia
perchè delete è stato invocato sia perchè
l’oggetto è finito fuori scope
• Il compito del distruttore è di assicurarsi che
l’oggetto per cui è invocato verrà distrutto senza
conseguenze. In particolare, se memoria è stata
allocata nel costruttore, il distruttore dovrà
assicurarsi di restituirla allo heap
Vector2D::~Vector2D()
Introduzione al C++ e alla programmazione ad oggetti
{}
// vuoto, in questo caso
19-23 febbraio 2001
83
Costruttori e distruttori (5)
• I costruttori con un solo parametro sono
automaticamente trattati come operatori di
conversione
Vector2D::Vector2D(int i) {. . .}
// costruisce un vettore a partire da un intero, ma puo`
// essere usato per convertire un intero in vettore
v=Vector2D(i);
• Per evitare la conversione si puo` usare explicit
explicit Vector2D(int);
Introduzione al C++ e alla programmazione ad oggetti
// solo costruttore
19-23 febbraio 2001
84
Classe Vector2D
• Come usare Vector2D:
main.cc
#include <iostream.h>
#include “Vector2D.h”
invoca il constructor
int main()
{
Vector2D v(1, 1);
cout << “ v =
<< v.x()
<< v.y()
cout << “ r =
cout << “ phi
return 0;
(“
<< “,”
<< “)” << endl;
“ << v.r();
= “ << v.phi() << endl;
}
Output:
v = (1, 1)
r = 1.4141 phi = 0.7854
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
85
Classe Vector2D
• … oppure attraverso un puntatore...
main.cc
#include <iostream.h>
#include “Vector2D.h”
Allocazione sullo heap
int main()
{
Vector2D *v = new Vector2D(1, 1);
cout << “ v = (“
<< v->x() << “,”
<< v->y() << “)” << endl;
cout << “ r = “ << v->r();
cout << “ phi = “ << v->phi() << endl;
delete v;
return 0;
}
Attenzione!
Introduzione al C++ e alla programmazione ad oggetti
Output:
v = (1, 1)
r = 1.4141 phi = 0.7854
19-23 febbraio 2001
86
Interfaccia e
implementazione
• La struttura interna dei dati (x_, y_) che
rappresentano l’oggetto della classe Vector2D
sono nascosti (private) agli utilizzatori della
classe.
• Gli utilizzatori non dipendono dalla struttura
interna dei dati (come lo erano gli utilizzatori dei
common blocks Fortran)
• Se la struttura interna cambia
(es.: r_, phi_), il codice che usa Vector2D non
deve essere modificato.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
87
Classe Vector2D
• Protezione dell’accesso ai dati:
main.cc
#include <iostream>
#include “Vector2D.h”
int main()
{
Vector2D v(1, 1);
cout <<
<<
<<
cout <<
cout <<
“ V = (“
v.x_ << “,”
//
v.y_ << “,” << endl; // non compila !
“ r = “ << v.r();
“ phi = “ << v.phi() << endl;
}
• I metodi di una classe hanno libero accesso ai dati
privati e protetti di quella classe
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
88
Selettori e modificatori
• Selettore: metodo che non modifica lo stato
(attributi) della classe. E’ dichiarato const
• Modificatore: metodo che può modificare lo stato
Vector2D.cc
della classe
Vector2D.h
#include “Vector2D.h”
class Vector2D
{
void Vector2D::scale(double s)
public:
{
Vector2D(double x, double y);
x_ *= s; y_ *= s;
double x() const;
}
double y() const;
double r() const;
Selettori (const) main.cc
double phi() const;
void scale(double s);
#include “Vector2D.h”
private:
int main()
double x_, y_;
modificatore
{
};
const Vector2D v(1, 0);
double r = v.r() // OK
v.scale( 1.1 ); // errore!
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
89
friend
• La keyword friend puo` essere usata perche`
una funzione (o una classe) abbia libero
accesso ai dati privati di un’altra classe
class A {
. . .
friend int aFunc();
friend void C::f(int);
};
class B {
…
friend class C;
};
class C {
. . .
};
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
90
friend (2)
• friend (nonostante il nome) e` nemico
dell’incapsulamento e quindi dell’Object
Orientation
• Un uso eccessivo di friend è quasi sempre
sintomo di un cattivo disegno
• Esistono anche situazioni in cui un friend può
essere accettabile
– Overloading di operatori binari
– Considerazioni di efficienza
– Relazione speciale fra due classi
“A programmer must confer with an architect before making friend declarations”
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
91
static
• Attributi dichiarati static in una classe sono
condivisi da tutti gli oggetti di quella classe
• Metodi dichiarati static non possono accedere
ad attributo non statici della classe
• Attiributi statici possono essere usati e modificati
soltanto da metodi statici
• Nonostante l’utilizzo di static sembri imporre
condizioni troppo restrittive, esso risulta utile
nell’implementazione di:
– contatori
– singleton (vedi oltre)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
92
Un contatore
Class MyClass {
private:
static int counter;
static void increment_counter() { counter++; }
static void decrement_counter() { counter--; }
public:
MyClass() { increment_counter(); }
~MyClass() { decrement_counter(); }
static int HowMany() { return counter; }
};
Un membro statico deve essere
#include <iostream.h>
inizializzato una e una sola volta
#include “MyClass.h”
int MyClass::counter=0;
nel codice eseguibile
Un metodo statico puo` essere
int main() {
invocato cosi`...
MyClass a,b,c;
MyClass *p=new MyClass;
cout<<“ How many? “<< MyClass::HowMany() <<endl;
delete p;
cout<<“ and now? “<< a.HowMany() <<endl;
return 0;
}
… o cosi`...
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
93
Un singleton
• Un singleton è una classe di cui, ad ogni
momento nel corso del programma, non può
esistere più di una copia (istanza)
class aSingleton {
Pattern utile per
private:
static aSingleton *ptr;
l’implementazione di
aSingleton () {}
classi “manager” di cui
public:
static aSingleton *GetPointer(){
deve esistere una sola
if (ptr==0)
istanza
ptr=new aSingleton;
return ptr;
#include “aSingleton.h”
}
};
aSingleton *aSingleton::ptr=0;
Attenzione a non farlo
diventare l’equivalente
di un common block!
Introduzione al C++ e alla programmazione ad oggetti
int main() {
aSingleton *mySing=
aSingleton::GetPointer();
. . .
Return 0;
19-23 febbraio 2001
94
}
Operatori
• E’ possibile ridefinire +, -, *, [], ++, ==, . . .
Vector2D.h
class Vector2D
{
public:
Vector2D(double x, double y);
double x() const;
double y() const;
double r() const;
double phi() const;
private:
double x_;
double y_;
};
Vector2D operator+(const
const
Vector2D operator-(const
const
Vector2D&
Vector2D&
Vector2D&
Vector2D&
Introduzione al C++ e alla programmazione ad oggetti
Vector2D.cc
Vector2D operator+(const
const
{
return Vector2D(v1.x()
v1.y()
}
v1,
v2);
v1,
v2);
Vector2D operator-(const
const
{
return Vector2D(v1.x()
v1.y()
}
19-23 febbraio 2001
Vector2D& v1,
Vector2D& v2)
+ v2.x(),
+ v2.y());
Vector2D& v1,
Vector2D& v2)
- v2.x(),
- v2.y());
95
Operatori (2)
• Esempio:
main.cc
#include <iostream>
#include “Vector2D.h”
int main()
{
Vector2D v1(1, 0), v2(0, 1);
Vector2D v;
Sintassi alternativa (!#@!?) :
v.operator=( operator+(v1, v2) );
v = v1 + v2;
cout << “ v = “ << v << endl;
cout << “ r = “ << v.r();
cout << “ phi = “ << v.phi() << endl;
}
Output:
ridefinizione di <<
v = (1, 1)
r = 1.4141 theta = 0.7854
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
96
Operatori (3)
• Esempio:
main.cc
#include
#include
#include
#include
<iostream>
<cmath>
“Vector3D.h”
“Matrix.h” // matrice 3x3
p greco
int main()
{
Vector3D v1(1, 1, 0);
double phi = M_PI/3;
double c = cos(phi), s = sin(phi);
Matrix m(1, 0, 0,
0, c, s,
0, -s, c);
Vector3D u = m * v;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
97
this
• In una classe è automaticamente definito un
attributo particolare: this
– this è un puntatore all’oggetto di cui fa parte
– E’ particolarmente utile quando si definisce un
operatore di assegnazione (=):
Vector2D.h
Vector2D.cc
Vector2D& operator=(const Vector2D& v){
class Vector2D {
x_=v.x();
public:
y_=v.y();
Vector2D& operator=(const Vector2D& );
return *this;
// ...
}
private:
main.cc
double x_, y_;
};
#include “Vector2D.h”
L’operatore = ritorna una
int main() {
Vector2D null(0, 0);
referenza a se stesso.
Vector2D a, b;
Permette assegnazioni
a=b=null;
}
multiple
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
98
Overloading di operatori
• possono esistere funzioni con lo stesso nome ma
con argomenti diversi
Vector2D.h
class Vector2D {
public:
// ...
private:
double x_, y_;
};
Vector2D operator*(const Vector2D &,
double);
double operator*(const Vector2D&,
const Vector2D&);
Vector2D.cc
Vector2D operator*(const Vector2D&,
double s) {
return Vector2D( v.x() * s,
v.y() * s);
}
double
operator*(const Vector2D& v1,
const Vector2D& v2) {
return ( v1.x() * v2.x() +
v1.y() * v2.y() );
}
• Non bisogna pero` esagerare! Ogni operatore
deve avere un significato ben preciso, per ragioni
di chiarezza.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
99
Overloading di operatori (2)
• Permette di utilizzare tipi definiti dall’utente come
se fossero tipi fondamentali
• La cardinalita`, l’associativita` e la precedenza di
un operatore non possono essere modificati
• Operatori unari sono implementati come metodi
senza argomenti (l’oggetto è l’argomento implicito)
• Operatori binari possono essere implementati
come metodi con un argomento (il primo
argomento, implicito, è l’oggetto il cui operatore
agisce) o come funzioni friend a due argomenti.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
100
Programmazione generica
• Il C++ fornisce un metodo per creare un
polimorfismo parametrico. E’ possibile utilizzare lo
stesso codice per tipi differenti: il tipo della variabile
diventa un parametro
template<class T>
T max( T p1, T p2 ) {
if ( p1 < p2 ) return p2;
else return p1;
}
Per il tipo T deve essere
definito l’operatore <
Introduzione al C++ e alla programmazione ad oggetti
Main.cc
int main() {
Vector v1,v2;
cout << max<int>(10,20) << endl;
cout << max<float>(2.6,1.0) << endl;
cout << max<Vector>(v1,v2) << endl;}
19-23 febbraio 2001
101
Sintassi
template < class identifier >
function definition
typename
template < class identifier >
class definition
• Ogni volta che nella definizione della funzione o
della classe appare identifier questo viene sostituito
dal compilatore con il tipo fornito nella chiamata.
• La dichiarazione e l’implementazione del template
devono essere nello stesso file ove il template
viene utilizzato
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
102
Parametri templati
• Parametri interi possono essere inclusi nella
dichiarazione del template
template <typename T=int , int n=10>
class array_n {
...
private:
T items[n];
esplicitamente
// n istanziato
};
array_n<complex, 1000> w;
di complessi
// w array
• I parametri di default possono essere tralasciati
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
103
Templates di templates
• L’argomento di un template puo` essere esso
stesso un template
template <class T1, template <class T2> class T3 >
• questo permette la creazione e l’utilizzo di metatemplates (templates istanziati con templates)
molto sofisticati
• la Standard Template Library fa uso di questa
possibilita`
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
104
Funzioni template e
parametri
• Una buona parte dei compilatori accetta una
sintassi ristretta per quel che riguarda le funzioni
template. ANSI/C++ prevede invece che anche
parametri numerici possano essere inclusi nella
definizione del template
template <class T>
void swap(T& x, T& y){
T temp;
temp=x;
x=y;
y=temp;
}
OK per ogni compilatore
template <class T, int n=10>
T aFunc(){
T temp[n];
. . .
}
ANSI/C++, ma la maggior
parte dei compilatori lo rifiuta
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
105
Membri statici
• Per le classi template, gli attributi statici non sono
universali ma specifici di ogni istanza
template <class T>
class MyClass {
public:
static int
counter;
...
};
MyClass<int> a,b;
MyClass<double> c;
• Le variabili statiche MyClass<int>::counter e
MyClass<double>::counter sono diverse
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
106
Un esempio: lo stack di
interi
Contenuto
val
Stack
top
...
next
Stack
top
Lo stack vuoto
Contenuto
Contenuto
val
val
next
next
class Contenuto {
...
private:
Contenuto* next;
int val;
};
class Stack {
...
private:
Contenuto* top;
};
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
107
Un esempio: lo stack di
interi
class Stack {
public:
Stack() {top = 0;}
~Stack() {}
void push ( int i ) {
Contenuto* tmp = new
Contenuto(i,top );
top = tmp; }
int pop () {
int ret = top->getVal();
Contenuto* tmp = top;
top = top->getNext();
delete tmp;
return ret;
}
private:
Contenuto* top;
};
class Contenuto {
public:
Contenuto ( int i, Contenuto* ptn ) {
val=i; next=ptn; }
int getVal (){ return val; }
Contenuto* getNext() {return next;}
private:
Contenuto* next;
int val;
};
User code
int main() {
Stack s;
s.push ( 10 );
s.push ( 20 );
cout << s.pop() << “ - “ << s.pop;
return 0;
};
Output
>> 10 - 20
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
108
Lo stack “templato”
template <class T>
class Stack {
public:
Stack() {top = NULL;}
~Stack() {;}
void push ( T i ) {
Contenuto<T>* tmp = new
Contenuto<T> (i,top );
top = tmp; }
T pop () {
T ret = top->getVal();
Contenuto<T>* tmp = top;
top = top->getNext();
delete tmp;
return ret;
}
private:
Contenuto<T>* top;
};
Introduzione al C++ e alla programmazione ad oggetti
template <class T>
class Contenuto {
public:
Contenuto ( T i, Contenuto*
ptn ) { val = i; next = ptn; }
T getVal (){ return val; }
Contenuto* getNext() {return
next;}
private:
Contenuto* next;
T val;
};
User code
int main() {
Stack<int> s;
s.push ( 10 );
s.push ( 20 );
Stack<double> s1;
Stack<Shape *> s2;
cout << s.pop() << “ “ << s.pop;
return 0;};
19-23 febbraio 2001
109
La Standard Template Library
• La libreria standard STL e’ una libreria di classi di
contenitori, algoritmi ed iteratori.
• STL e’ una libreria generica: tutti i suoi componenti
sono parametrizzati mediante l’utilizzo dei template
puntatori intelligenti
vettori, liste, mappe, ….
find, replace, reverse, sort, ….
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
110
Iteratori (puntatori intelligenti)
• Gli iteratori sono dei puntatori agli elementi di un
contenitore e ci permettono di muoverci all’interno
di esso:
– Iteratori monodirezionali: Permettono di accedere
all’elemento successivo o al precedente
– Iteratori bidirezionali : Permettono di accedere sia
all’elemento successivo che al precedente
– Iteratori ad accesso casuale : Permettono di accedere
ad un qualunque elemento del contenitore
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
111
Contenitori
• Un contenitore è un oggetto capace di
immagazzinare altri oggetti e che possiede metodi
per accedere ai suoi elementi.
– Ogni contenitore ha un iteratore associato che permette
di muoversi tra gli elementi contenuti
– Una sequenza è un contenitore di lunghezza variabile i
cui elementi sono organizzati linearmente. E’ possibile
aggiungere e rimuovere elementi
– Un contenitore associativo è una sequenza che
permette un efficiente accesso ai suoi elementi basato
su una chiave.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
112
Sequenze
• vector
– Tempo costante di inserimento e cancellazione di
elementi all’inizio e alla fine del vettore.
– Tempo lineare con il numero di elementi per
inserimento e cancellazione di elementi all’interno del
vettore
– Iteratore ad accesso casuale
• list
– Tempo costante di inserimento e cancellazione di
elementi in ogni punto della lista
– Iteratore bidirezionale
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
113
vector
begin()
end()
0
1
2
...
9
++ p
p
p
p
p
push_back()
p
• Le locazioni di memoria sono contigue
– Accesso casuale, veloce l’accesso agli elementi, lenti
inserimento ed estrazione
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
114
list
nodo
val
list
...
next
top
bottom
prev
nodo
nodo
val
val
next
next
prev
prev
• Simile allo stack, ma consente di muoversi in due
direzioni
• Le locazioni di memoria non sono contigue
– Lenta la ricerca, veloci inserimento ed estrazione
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
115
Contenitori associativi
• Sono contenitore di coppie ( key, value ) e
possiedono un iteratore bidirezionale
• map
– Viene richiesto l’operatore < per la chiave
– Gli elementi sono ordinati secondo la chiave
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
116
Algoritmi
• Gli algoritmi sono delle funzioni globali capaci di
agire su contenitori differenti
sort
find
fill
count
copy
min, max
• Sono incluse operazioni di ordinamento (sort,
merge, min, max...), di ricerca (find, count,
equal...), di trasformazione (transform, replace,
fill, rotate, shuffle...), e generiche operazioni
numeriche (accumulate, adjacent difference...).
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
117
Esempio uso sequenze
#include <vector
list >
#include <algorithm>
#include <iostream>
int main() {
vector
list <int> container;
int val;
for (int i=0; i<10; i++) {
val = (int)((float)rand()/RAND_MAX*10);
container.push_back(val); }
vector
list <int>::iterator it1;
for ( it1=container.begin(); it1!=container.end();
it1++)
cout << "vector : " << *it1 << endl;
return 0;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
118
Esempio uso contenitori
associativi
#include <map>
#include <algorithm>
#include <iostream>
#include <string>
int main() {
map<string,int> amap;
amap["Primo”]=1;
amap[“Secondo”]=2;
cout << "Size : " << amap.size() << endl;
amap["Terzo"]=3;
amap["Quarto"]=4;
cout << "Size : " << amap.size() << endl;
map<string,int>::iterator it;
for ( it=amap.begin(); it!=amap.end(); it++)
cout << "map : " << it->first << " " << it->second << endl;
cout << amap.find("Terzo")->second << endl;
return 0;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
119
Assegnazione di un metodo
ad un messaggio
• I metodi pubblici di una classe costituiscono
l’interfaccia della classe (cioè i messaggi che
l’oggetto può interpretare)
• La funzione è assegnata al messaggio in fase
di codifica (early binding)
• Può essere necessario assegnare la funzione
al messaggio a run-time (late binding)

Polimorfismo
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
120
Controllo dei tipi
• Controllare i tipi significa verificare che ad un
oggetto vengano inviati solo messaggi che è
in grado di comprendere:
– controllo del nome del metodo
– controllo della lista degli argomenti
• In C++ il controllo è fatto dal compilatore
(strong typing)
• In altri linguaggi (ad esempio SmallTalk) è
fatto a run-time (weak typing)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
121
Typing & Binding
Consistenza dei
Definizione Strong tipi verificata
Typing dei messaggi
dal compilatore
Consistenza dei
e degli
Weak tipi verificata
argomenti
a run-time
Assegnazione
Binding di un metodo
ad un
messaggio
Introduzione al C++ e alla programmazione ad oggetti
In fase di
Early programmazione
INFLESSIBILE
A run-time
Late
POLIMORFISMO
19-23 febbraio 2001
122
Esempio: i soldati
• Tutti i soldati devono capire il messaggio
attacca. Il messaggio ha conseguenze
diverse a seconda del tipo di soldato:
– un arcere lancia una freccia
– un fante usa la spada
– un cavaliere lancia una lancia
• Il gestore della schermata vuole tenere una
lista di soldati e vuole poter dire ad ogni
soldato di attaccare indipendentemente dal
tipo ma basandosi solo sulla posizione.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
123
list<Soldato> lista;
riempiLista(lista);
Posizione unaPosizione=...;
list<Soldato>::iterator iter;
for(iter=lista.begin();iter!=lista.end();iter++){
Soldato unSoldato=(*iter);
if(unSoldato.posizione()==unaPosizione)
unSoldato.attacca();
}
class Soldato {
void attacca() {
// cosa scrivo qui?!? Per quale tipo di
// soldato implemento il metodo attacca()?
}
};
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
124
Polimorfismo
• Polimorfismo con tipi controllati dal
compilatore (Strong typing & late binding).
Come?
• In C++ viene implementato tramite il concetto
di ereditarietà (inheritance)
• Classe astratta: definisce i messaggi
• Classe concreta: assegna i metodi ai
messaggi
La classe concreta eredita da quella astratta
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
125
Ereditarietà
• Una classe può essere derivata da una classe
esistente usando la sintassi:
class newclass: (public|protected|private) oldclass {
dichiarazioni...
};
– public, protected e private specificano il tipo di
accesso ai membri della classe
• Se la classe base non ha un costruttore di default:
– La classe derivata deve implementarlo
• Se la classe base ha un costruttore di default:
– il costruttore della classe derivata deve esplicitamente
invocarlo nella sua lista di inizializzatione
• Il costruttore della classe base può così essere eseguito prima
che il costruttore della classe derivata sia eseguito
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
126
Ereditarietà (2)
• Una classe derivata pubblicamente è a tutti gli
effetti un sottotipo della classe base.
– Un oggetto della classe derivata può essere trattato
come se fosse un oggetto della classe base
– Un puntatore alla classe base può puntare ad oggetti
della classe derivata
– Un riferimento alla classe derivata può, se la cosa ha un
senso, essere implicitamente convertito ad un
riferimento alla classe base
– E` possibile dichiarare un riferimento alla classe base
ed inizializzarlo ad un oggetto della classe derivata
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
127
Ereditarietà (3)
• La definizione dell’interfaccia (metodi pubblici)
della classe base è estremamente importante
perchè determina il comportamento delle classi
derivate
• Un metodo della classe base può essere:
– dichiarato e definito normalmente
• la classe derivata eredita questo metodo e NON può ridefinirlo
– dichiarato virtual e definito normalmente
• la classe derivata eredita questo metodo e può ridefinirlo
– dichiarato virtual e non definito (=0)
• la classe derivata eredita il metodo e DEVE ridefinirlo
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
128
Classi base astratte
• Una funzione puramente virtuale è un metodo
virtuale non definito. E` dichiarato come:
virtual func_prototype = 0;
• Una classe che ha almeno un metodo puramente
virtuale è chiamata classe astratta
• Oggetti di una classe astratta non possono esistere
• Puntatori ad una classe base astratta possono
essere definiti ed usati polimorficamente (per
puntare ad oggetti delle classi derivate)
• Una classe base astratta viene introdotta per
specificare l’interfaccia di una categoria di classi
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
129
class Soldato {
virtual void attacca()=0;
};
class Arcere : public Soldato {
virtual void attacca() {
// lancia una freccia
}
};
class Fante : public Soldato {
virtual void attacca() {
// usa la spada
}
};
...
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
130
Erediarietà multipla
• L’ereditarietà multipla permette di derivare una
classe da due o più classi base. La sintassi viene
estesa per permettere una lista di classi base
class
. . .
};
class
. . .
};
A {
.
B {
.
class AplusB: public A, private B {
. . . .
};
• L’ ereditarietà multipla viene spesso utilizzata per
combinare un’interfaccia ed una implementazione,
ma è molte volte sintomo di un cattivo disegno
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
131
dynamic_cast
• dynamic_cast opera una conversione, se è
possibile, fra due tipi. Il puntatore ritornato NON è
nullo soltanto se il tipo dell’oggetto su cui si opera è
quello che ci si aspetta
class
. . .
};
class
. . .
Base {
.
// base implementation
Derived: public Base {
.
void new_method() ; // non e’ definito in Base!
};
void func(Base *ptr) // ptr e’ un obbetto dell classe Base
{
ptr->new_method(); // Errore!!!
Derived *p = dynamic_cast<Derived *> (ptr)
if (p !=0) {
p->new_method();
}
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
132
Ereditarietà (4)
• Una classe derivata estende la classe base e ne
eredita tutti i metodi e gli attributi
Track.h
class Track
{
public:
LorentzVector momentum()
{ return p_; }
protected:
LorentzVector p_;
};
DchTrack è una Track
che ha degli attributi in più
(hits_) e nuovi metodi
(DchHit* hit(int n),
int hits())
Introduzione al C++ e alla programmazione ad oggetti
DchTrack.h
#include “Track.h”
class DchTrack : public Track
{
public:
int hits()
{ return hits_->size(); }
DchHit* hit(int n)
{ return hits_[n]; }
protected:
list<DchHit> hits_;
};
19-23 febbraio 2001
133
Esempio: shape
• Tutti gli oggetti
nella finestra
hanno
comportamenti
comuni che
possono
essere
considerati in
astratto:
–
–
–
–
disegna
sposta
ingrandisc
etc...
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
134
Cerchi e quadrati
Quadrato
Introduzione al C++ e alla programmazione ad oggetti
Cerchio
19-23 febbraio 2001
135
Cerchio
Nome della classe
Circle.h
Costruttore
class Circle {
public:
Circle(Point2d center, double radius);
~Circle();
void moveAt(const Point2d & p);
void moveBy(const Point2d & p);
void scale(double s);
void rotate(double phi);
void draw() const;
void cancel() const;
private:
Point2d center_;
double radius_;
};
Distruttore
Point2d: classe che rappresenta
un punto in 2 dimensioni.
Interfaccia Pubblica
Metodi: operazioni sugli oggetti
“Dati” privati
(Attributi, membri)
Punto e virgola!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
136
Circle.cc
#include “Circle.h”
Cerchio (2)
void Circle::draw() const
{
const int numberOfPoints = 100;
float x[numberOfPoints], y[numberOfPoints];
float phi = 0, deltaPhi = 2*M_PI/100;
for ( int i = 0; i < numberOfPoints; ++i )
{
x[i] = center_.x() + radius_ * cos( phi );
y[i] = center_.y() + radius_ * sin( phi );
phi += dphi;
}
polyline_draw(x, y, numberOfPoints, color_, FILL);
}
void Circle::moveAt( const Point2d& p )
{
cancel(); center_ = p; draw();
}
void Circle::scale( double s )
{
cancel(); radius_ *= s; draw();
}
Circle::Circle( Point2d c, double r ) :
center_( c ), radius_( r )
{ draw(); }
Main.cc
#include “Circle.h”
int main()
{
Circle c( Point2d(10, 10), 5 );
c.draw();
c.moveAt(Point2d(20, 30));
return 0;
}
Circle::~Circle()
{ cancel(); }
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
137
QuadratoSquare.cc
#include “Square.h”
Square.h
class Square {
public:
Square(const Point2d&, const Point2d&,
Color color = TRASPARENT);
~Square();
void moveAt( const Point2d& p );
void moveBy( const Point2d& p );
void changeColor( Color color );
void scale( double s );
void rotate( double phi );
void draw() const;
void cancel() const;
private:
Point2d center_;
Vector2d centerToUpperCorner_;
Color color_;
};
centerToUpperCorner_
upperCorner
loweCorner
Introduzione al C++ e alla programmazione ad oggetti
void Square::draw() const
{
float x[4], y[4];
Vector2d delta( centerToUpperCorner_ );
for ( int i = 0; i < 4; i++ )
{
Point2d corner = center_ + delta;
x[i] = corner.x();
y[i] = corner.y();
delta.rotate( M_PI_2 );
}
polyline_draw(x, y, 4, color_, FILL);
}
void Square::rotate( double phi )
{
cancel();
centerToUpperCorner_.rotate( phi );
draw();
}
Square::Square(const Point2d& lowerCorner,
const Point2d& upperCorner,
Color color) :
center_( median(lowerCorner, upperCorner) ),
centerToUpperCorner_( upperCorner - center_ ),
color_( color )
{ draw(); }
void Square::scale( double s )
{ cancel(); centerToUpperCorner_ *= s;
19-23 febbraio 2001
draw(); }
138
Codice Applicativo (Client)
Main.cc
#include “Circle.h”
#include “Square.h”
int main()
{
Circle c1( Point2d(2.,3.), 4.23 );
Square r1( Point2d(2.,1.), Point2d(4.,3.) );
Costruisce un vettore di puntatori a
e salva
Circle * circles[ 10 ];
cerchi, crea oggetti in memoria
for ( int i = 0; i < 10; ++i )
i loro puntatori nel vettore.
{
circles[ i ] = new Circle( Point2d(i,i), 2. );
}
for ( int i = 0; i < 10; ++i )
circles[ i ]->draw();
return 0;
}
Itera sul vettore e invoca draw()
per ogni elemento
Come gestire cerchi
e quadrati insieme?
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
139
Polimorfismo
Tutte le Shapes
hanno la stessa interfaccia:
draw, pick, move, fillColor...,
ma ogni sottotipo diverso
può avere la usa personale
implementazione
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
140
Interfaccia astratta
Shape.h
class Shape {
public:
Shape() { }
virtual ~Shape() { }
Main.cc
#include “Circle.h”
moveAt(const Point2d& where) = 0;#include “Square.h”
changeColor(Color newColor) = 0;
scale(double s) = 0;
int main()
rotate(double phi) = 0;
{
draw() const = 0;
Shape * shapes[ 20 ];
cancel() const = 0;
int index = 0;
for ( int i = 0; i < 10; i++ )
{
Shape * s;
s = new Circle( Point2d(i, i), 2.) );
shapes[ index ++ ] = s;
s = new Square( Point2d(i, i),
Point2d(i+1, i+2)) );
shapes[ index ++ ] = s;
}
#include “Shape.h”
for ( int i = 0; i < 20; i++ )
class Square : public Shape
shapes[ i ]->draw();
{
// …. Il resto tutto uguale a prima
return 0;
};
}
virtual
virtual
virtual
virtual
virtual
virtual
};
void
void
void
void
void
void
Interfaccia di metodi
puramente virtuali
Square.h
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
141
Ereditarietà e riuso del
codice
CenteredShape.h
Class CenteredShape: public Shape
{
public:
CenteredShape(Point2d c,
Color color = TRASPARENT)
: center_(c), color_(color)
{ /*draw();*/ }
~Circle()
{ /*cancel();*/ }
Non si possono chiamare
metodi virtuali in costruttori e
distruttori (troppo presto,
troppo tardi)
Square.h
#include “CenteredShape.hh”
void moveAt( const Point2d& );
void moveBy( const Vector2d& );
class Square : public CenteredShape
void changeColor( Color );
{
virtual void scale( double ) = 0; public:
virtual void rotate( double ) = 0;
Square( Point2d lowerCorner, Point2d upperCorner,
virtual void draw() const = 0;
Color col = TRASPARENT) :
virtual void cancel() const = 0;
CenteredShape( median(lowerCorner, upperCorner), col),
touc_(upperCorner - center_) { draw(); }
protected:
~Square() { cancel(); }
Point2d center_;
Color color_;
virtual void scale( double s )
};
{ cancel(); centerToUpperCorner_ *= s; draw(); }
virtual void rotate( double phi );
virtual void draw() const;
virtual void cancel() const;
private:
Vector2d touc_;
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
};
142
Attenzione alle
generalizzazioni...
Rectangle.h
• Attenzione: scegliere le
relazioni di ereditarietà
può essere non banale.
• Un quadrato è un
rettangolo?
class Rectangle
{
public:
Rectangle(double x0, double y0,
double lx, double ly) :
lx_(lx), ly_(ly), x0_(x0), y0_(y0) { }
void scaleX(double s);
void scaleY(double s);
protected:
double x0_, y0_;
Square.h
double lx_, ly_;
};
class Square : public Rectangle
{
public:
Square(double x0, double y0, double l) :
Rectangle(x0, y0, l, l) { }
};
Avere lx_ e ly_ è ridondante per Square
Cosa succede se si invoca scaleX o scaleY ?
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
143
Ereditarietà multipla
• Una classe può ereditare da più classi
DrawableObj.h
Shape.h
class DrawableObj
{
public:
virtual void draw() = 0;
};
class Shape
{
public:
virtual void scale(double s) = 0;
virtual void moveAt( Vector2d& ) = 0;
};
DrawableShape.h
class DrawableShape :
public DrawableObj, public Shape
{
public:
virtual void draw();
virtual void scale(double s);
virtual void moveAt( Vector2d& );
};
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
144
Strategie di sviluppo di un
progetto
•
•
•
•
•
•
Requisiti: cosa l’utente vuole
Analisi: la visione dell’informatico dei requisiti
Disegno: l’aspetto del sistema software
Produzione: codifica
Testing: debugging e verifica dei requisiti
Mantenimento: installazione del prodotto e controllo del
funzionamento per il resto della sua vita
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
145
Modello a cascata
Requisiti
Analisi
Disegno
Produzione
Testing
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
146
Modello evoluzionario
Requisiti
Analisi
Testing
Disegno
Produzione
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
147
Confronto fra i modelli di
sviluppo
A cascata
Evoluzionario
• Processo lineare (si torna al
passo precedente solo in caso
di problemi)
• Confinamento delle attività in
ogni fase
• Facile da gestire (gestione delle
scadenze)
• Difficile da modificare
• Prodotto utilizzabile solo alla
fine del processo
• Processo ciclico (brevi processi
completi)
• Attività distribuite su più fasi
• Difficile da gestire
• Facile da modificare e integrare
• Prototipo utilizzabile fin dal
primo ciclo
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
148
Requisiti
• Definizione delle richieste da parte dell’utente del
programma (o di una sua parte) sul sistema
• Si parla di programmazione per contratto perchè
l’utente richiede solamente la definizione del
servizio richiesto NON la metodologia seguita per
fornirglielo
– è possibile delegare parte del lavoro richiesto ad altri
– il sistema è indipendente da chi è il suo utente
INCAPSULAMENTO!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
149
Analisi
• Comprensione e razionalizzazione delle richieste
dell’utente
• Costruzione di un modello
– astrazione (semplificazione delle relazioni)
– rilevanza (identificazione degli oggetti chiave)
• Da non trascurare: analisi delle soluzioni esistenti.
Può far risparmiare molto tempo!!!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
150
Disegno
Definizione di oggetti
e classi
Definizione delle
interfacce
Definizione degli stati
e dell’implementazione
Definizione delle
relazioni
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
151
Disegno (2)
• Dopo ogni ciclo bisogna analizzare i rischi, la
stabilità del disegno e la complessità delle classi
• Se una classe è troppo complessa conviene
dividerla
• Ad ogni ciclo il numero di modifiche deve
diminuire
• Architetture troppo complesse devono essere
modularizzate
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
152
Codifica
• C’è poco da dire…
• Non sopravvalutate questa fase:
Suddivisione del tempo per il primo
ciclo
Testing
Analisi
20%
30%
Codifica
15%
Disegno
35%
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
153
Testing
• Debugging: è ovvio… il codice non deve dare errori.
• Use cases: specificano il comportamento del sistema in
una regione.
• Scenarios: sono esempi concreti di use cases. Per
definizione se tutti gli scenari sono soddisfatti
correttamente il test è positivo.
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
154
Metodi di sviluppo del
software
Un metodo comprende:
• Una notazione
mezzo comune per esprimere strategie e decisioni
• Un processo
specifica come deve avvenire lo sviluppo
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
155
Metodi Object Oriented
– Booch Method
by Grady Booch
– OMT
Grady Booch
by Jim Rumbaugh
– Objectory (Use Cases)
by Ivar Jacobson
– CRC
by R.Wirfs-Brock
Jim Rumbaugh
• Di recente introduzione: UML
– uno standard OMG (Object Management Group),
dal novembre 1997
Ivar Jacobson
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
156
UML per l’analisi e il
disegno
• Class Diagrams: aspetto statico del sistema. Classi con
attributi e metodi e relazioni tra di esse.
• Sequence e collaboration digrams: comportamento
dinamico del sistema. Sequenza dei messaggi scambiati
fra gli oggetti.
• Use case diagrams: illustra gli use cases, le relazioni
fra di essi e gli attori che vi partecipano.
• State diagrams: descrive gli stati in cui ogni oggetto si
può trovare e le modalità con cui passa da uno stato
all’altro
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
157
Concetti delle classi
rivisitati
• Relazioni tra oggetti
• Decomposizione funzionale all’interno di una
classe
– responsabilità dei metodi
• Decomposizione funzionale tra più classi
– responsabilità delle classi
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
158
Rappresentazione delle
classi
Nome
- dato
- dato
attibuti
pubblico
protetto
+ metodo(arg)
# metodo(arg)
- metodo(arg)
operatori
privato
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
159
Rappresentazione di una
classe C++ in UML
Nome.h
class Nome {
private:
Tipo1 variabile1;
Tipo2 variabile2;
Tipo3 variabile3;
public:
Nome();
~Nome();
Tipo4 funzione1 ( arg );
protected:
Tipo5 funzione2 ( arg );
private:
Tipo6 funzione3 ( arg );
};
Introduzione al C++ e alla programmazione ad oggetti
Nome
- variabile1:Tipo1
- variabile2:Tipo2
- variabile3:Tipo3
+ funzione1(arg):Tipo4
# funzione2(arg):Tipo5
- funzione3(arg):Tipo6
19-23 febbraio 2001
160
Attributi e metodi
Protetto (#)
Publico (+)
Notazione di
Rational Rose
Privato (-)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
161
Principali relazioni fra classi
• associazione
• aggregazione by reference
(il composito non vive senza il componente)
• aggregazione by value
(aggregazione fisica: esistenza contemporanea)
• dipendenza
• generalizzazione (inheritance)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
162
Aggregazione
(contenimento)
Autista
By reference (condivisa)
• un autista guida più automobili
Automobile
Motore
Introduzione al C++ e alla programmazione ad oggetti
By value (possesso)
• una automobile possiede
il suo motore
19-23 febbraio 2001
163
Cardinalità e direzionalità
Non navigabile
-_points
Polygone
1
Point
1..*
•Il punto non conosce
i poligoni
•Il poligono è costituito
da punti
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
164
Dipendenza
• Non c’è nessuna associazione
• C’è comunque relazione di uso
•Il CD non conosce
il CDPlayer
•Il CDPlayer usa il CD: se cambia
il formato del CD il CDPlayer deve
essere modificato
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
165
Generalizzazione
(ereditarietà)
Autista
#_autista
Automobile
#_motore
Motore
{virtual}
{virtual}
AutoSportiva
AutoDiLusso
Ereditarietà
virtuale!
Ferrari
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
166
Class Diagram di “Shape”
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
167
Class Diagram
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
168
Class Diagram
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
169
Object Sequence Diagram
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
170
Object Collaboration
Diagram
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
171
CRC
Classi, Responsabilità, Collaborazioni
B
A
z
s
x
y
C
p
F
f
Introduzione al C++ e alla programmazione ad oggetti
D
E
q
w
19-23 febbraio 2001
172
Assegnare Responsabilità
• Identificare i protagonisti
• Analizzare il ruolo dei vari oggetti
• Concentrarsi sul comportamento non la
rappresentazione
• Cercare Oggetti con proprietà comuni:
– appartiene a classi diverse, o sono solo oggetti diversi?
• Definire le interfacce (le operazioni che soddisfano
le responsabilità)
Una corretta assegnazione delle responsabilità è la chiave di
una buona modularità e riuso
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
173
Collaborazione tra classi
• Le responsabilità vanno suddivise tra i vari oggetti
del sistema
• non deve esistere un controllo centralizzato
• Un oggetto deve compiere le proprie
responsabilità e delegare ad altri operazioni
specifiche
– Legge di Demeter: non usate oggetti lontani:
Invece di: traiettoria.listapunti().aggiungi(Punto);
usare:
traiettoria.aggiungiPunto(Punto);
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
174
Identificare Relazioni
• Cercare collaborazioni
• Cercare aggregazioni
• Cercare generalizazioni
Come un client conosce il suo
service provider?
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
175
Relazioni
Logiche
• Generalizazione: Is-a
• Aggregazione: Has
• Dipendenza: Knows
Introduzione al C++ e alla programmazione ad oggetti
{
Implementazione
• Inheritance
• Template instantiation
• Composizione
by value
• Composizione
by reference
19-23 febbraio 2001
176
Avere o essere?
• Uno dei punti critici è distinguere se il
rapporto fra due oggetti è del tipo avere o
essere:
– Un LorentzVector è un Vector o ha un Vector?
– Una Traccia è un vector<Hit> o ha un
vector<Hit>?
– Un Rivelatore è una Superficie o ha una
superficie?
• Per risolvere il problema bisogna guardare a
cosa fanno!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
177
Principio di Liskov
• Gli oggetti figli possono essere usati ovunque
l’oggetto genitore è richiesto
– usare l’inheritance quando è richiesto il polimorfismo
– Non cambiare il comportamento della base class
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
178
Composizione by value o by
refrence
• In C++ la scelta fra aggregazione by value o by
refrence può seguire questo schema:
–
–
–
–
Tipi semplici (int, float, …): by value
Parte dello stato dell’oggetto: by value
Oggetti condivisi: by reference
Assegnati a run time: by reference
• Oggetti condivisi by reference: attenzione a chi ha
la responsabilità di crearli e cancellarli! (1 new 
1 delete!)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
179
Approccio Outside-in
• Il corretto approccio è quello di guardare il
sistema dall’esterno.
• Identificare prima di tutto gli oggetti che
interagiscono con l’utente esterno e i messaggi a
cui devono saper rispondere (think client!)
• In seguito identificare gli oggetti che forniscono
servizi a questi ultimi e così via
• Gli algoritmi vengono per ultimi!!!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
180
CRC Workshop
• Metodo per la definizione si una architettura
bilanciata
• Ogni partecipante svolge il ruolo di una classe.
–
–
–
–
Individuazione delle classi
Contrattazione delle responsabilità
Definizione delle collaborazioni
Difesa dal tentativo di assegnazione di responsabilità
contrarie alla natura della classe
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
181
Regole per il CRC workshop
• Tentate di rifuutare le responsabilità
– Dovrei? (Non sono io che lo devo fare!)
– Potrei? (Non ho i mezzi, o lo stato per farlo!)
• Cercate di fare poco lavoro
– Se avete dovuto accettare una responsabilità cercate
di far fare il lavoro a qualcun’altro
• Potenziate i collaboratori, non interferite
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
182
Design Patterns
• Sono elementi di software OO riutilizzabile
• Piccoli insiemi di classi che collaborano
implementando dei comportamenti tipici
– Creational patterns
– Structural patterns
– Behavioral patterns
• I principali sono raccolti in un libro:
E. Gamma et al., Design Patterns
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
183
Factory
I client possono
richiedere la
creazione di un
prodotto senza
dipendervi
Client
Factory
AbstractProduct
createProduct1 () : AbstractProduct
createProduct2 () : AbstractProduct
ConcreteProduct1
Introduzione al C++ e alla programmazione ad oggetti
La Factory
dipende dai
prodotti concreti,
mentre i client
dipendono solo da
quelli astratti
ConcreteProduct2
19-23 febbraio 2001
184
Proxy
Subject
Client
reques t( )
Proxy
RealSubject
_sub ject
_s ubject : RealSubject
reques t( )
reques t( )
1
Una richiesta da un client a un server, può
essere mediata dal Proxy, che può compiere
anche altre operazioni (I/O, caching, etc.)
Introduzione al C++ e alla programmazione ad oggetti
...
_s ubject->reques t();
...
19-23 febbraio 2001
185
Composite
Client
Com ponent
Il client può trattare
componenti e compositi
usando la stessa interfaccia.
La composizione può essere
ricursiva.
operation( )
1..*
_children
Com pos ite
operation( )
for c in all _children
c->operation();
Introduzione al C++ e alla programmazione ad oggetti
Leaf
operation( )
Esempio: programmi di
grafica
19-23 febbraio 2001
186
Gruppo di Shapes
Client
Shape
draw( )
_components
1..*
Il gruppo di shapes è il
Composite
La shape è il Component
Le shapes concrete (Circle,
Square, ecc...) sono le Leaf
GroupofShapes
draw( )
Introduzione al C++ e alla programmazione ad oggetti
Circle, Square, ...
draw( )
19-23 febbraio 2001
187
Codice del modello
composite
Shape.h
class Shape {
public:
Shape() {}
virtual void draw() const = 0;
// altri metodi virtuali ( = 0 )
};
Circle.h
#include “Shape.h”
class Circle: public Shape {
public:
Circle(Point2D c, double r):
Shape(), center_(c), radius_(r) {}
void draw() const { ; // draw circle }
// altri metodi definiti per Circle
private:
double radius_;
Point2D center_;
};
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
188
Codice del modello
composite
GroupofShapes.h
#include “Shape.h”
class GroupofShapes : public Shape {
public:
typedef vector<Shape *> Container;
typedef Container::const_iterator Iterator;
GroupofShapes(){}
void draw() const {
Iterator p=components.begin();
Iterator pe=components.end();
while (p!=pe)
{ (*p)->draw(); p++; }
return;
}
// gli altri metodi sono definiti operando
// sui componenti
protected:
Container components;
};
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
189
Strategy
{
...
Strategy* s ;
s ->doAlgorithm();
...
}
Il pattern Strategy permette di
scegliere l’algoritmo da eseguire a runtime.
Nuovi algoritmi possono essere
introdotti senza modificare il codice
utente.
Strategy
Client
doAlgorithm( )
ConcreteStrategyA
doAlgorithm( )
Introduzione al C++ e alla programmazione ad oggetti
ConcreteStrategyB
ConcreteStrategyC
doAlgorithm( )
19-23 febbraio 2001
doAlgorithm( )
190
Observer
Observer
Subject
_ob servers
update( )
_observers : Observer
attach (Observer)
notify ()
0..*
for all o in _
observables
o->update();
ConcreteObserver
ConcreteSubject
_status : Status
_subject . ConcreteSubject
_sub ject
_status : Status
status( )
return _status;
Lo stato dell’Observer
dipende dallo stato del
Subject.
Il Subject notifica a tutti gli
Observer registrati che il
suo stato è cambiato.
Introduzione al C++ e alla programmazione ad oggetti
update( )
_status =
_subject->status();
19-23 febbraio 2001
191
Appendice: strighe C-style
• Le variabili carattere sono gestite come array di
char (un char contiene un solo carattere)
– accesso agli elementi tramite la sintassi degli array
– carattere nullo usato come terminatore (‘\0’)
• Funzoni di libreria per la gestione dei char* :
– #include<cstring> per utilizzarle
– int strlen(const char*); lunghezza della
stringa
– int strcmp(const char*, const char*);
confronto di due stringhe
– char* strcpy(char*, const char*); copia la
seconda stringa nella prima
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
192
Appendice: la classe
string
• Per semplificare la gestione delle stringhe è stata
creata la classe string
– #include<string> per usarla
– Definiti gli operatori standard:
• = per l’assegnazione
• + e += per la concatenazione
• == e tutti gli altri operatori relazionali per il confronto
• [] per l’accesso agli elementi
– Disponibile sintassi simile a quella dei contenitori STL:
• iteratori: string::iterator e string::const_iterator
• funzioni begin() , end() , size() , ecc...
– Interoperabilità con char*:
char* c=“Pippo”; string s=c;
char* c1 = s.c_str(); s +=
c;
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
193
Confronto stringhe C-style e
string
#include<iostream>
#include<iostream>
#include<cstring>
int main(){
int err=0;int big=1000000;
char* c1=“LLLong string”;
for(int i=0;i<big;i++){
int len=strlen(c1);
char* c2=new char[len+1];
strcp(c2,c1);
if(strcmp(c2,c1))err++;
delete[] c2;
}
cout<<err<<“errori”<<endl;
return 0;
}
Introduzione al C++ e alla programmazione ad oggetti
#include<string>
int main(){
int err=0;int big=1000000;
string s1=“LLLong string”;
for(int i=0;i<big;i++){
// int len=s1.size();
string s2=s1;
if(s2!=s1)err++;
}
cout<<err<<“errori”<<endl;
return 0;
} // 2 volte piu’ veloce!!!
19-23 febbraio 2001
194
Appendice:operazioni di I/O
• Si utilizza la libreria iostream
– Gli operatori di stream >> e << dirigono il flusso da/per
le unità desiderate:
• cout : standard output. Si sono già visti molti esempi
• cerr : standard error. Si usa come cout
• cin : standard input (normalmente la tastiera)
include<iostream>
include<string>
int main(){
string nome;
cout << “Come ti chiami?” << endl;
cin >> nome; // Notare la direzione!!!
if(nome.empty()) cerr << “Stringa nulla!” << endl;
else cout << “Ciao “ << nome << “!” << endl;
return 0;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
195
Overloading degli operatori
di I/O
• Gli operatori << e >> possono essere ridefiniti per
consentire operazioni del tipo:
Vector2D v(1,2);
cout << “Il vettore v vale “ << v << endl;
• Si utilizza una funzione friend:
class Vector2D {
friend ostream& operator <<(ostream& os, const
Vector2D v);
[...]
}
ostream& operator <<(ostream& os, const Vector2D v){
os << “(“ << v.x() << “,” << v.y() << “)”;}
• Si ottiene:
Il vettore v vale (1,2)
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
196
Appendice: I/O con files
• E’ possibile definire altre unità di I/O
–
–
–
–
–
Si utilizza la libreria fstream (include iostream)
I files di input sono dichiarati ifstream
I files di output sono dichiarati ofstream
I files di input/output sono dichiarati fstream
Costruttore con argomento const char* (nome file)
#include <fstream>
#include <string>
int main(){
ifstream fin(“file1.dat”); // deve esistere!
if(!fin){ cerr << “file1.dat non esiste” << endl; return -1; }
ofstream fout(“file2.dat”); // se esiste viene sovrascritto
int i=0; string parola;
while (inf >> parola)
fout << “La “ << ++i << “-esima parola e\’ “ << parola << endl;
fin.close(); fout.close(); return 0;
}
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
197
Appendice: I/O in memoria
• E’ possibile definire unità di I/O in memoria (non
legate a files)
–
–
–
–
Si utilizza la libreria sstream (include iostream)
Le unità di input sono dichiarati istringstream
Le unità di output sono dichiarati ostringstream
Le unità di input/output sono dichiarati stringstream
– I costruttori non hanno argomento
– Il metodo str() applicato ad un oggetto di questo tipo
ritorna la stringa (string) contenuta nell’unità:
ostringstream messaggio;
messaggio << “Ciao!” << endl;
string s=messaggio.str();
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
198
Appendice: Manipolatori di
I/O
• Modificano il comportamento di una stream.
boolalpha: true e false rappresentati come stringhe
noboolalpha: true e false rappresentati come 1 e 0 (default)
showbase: interi stampati col prefisso che indica la base
noshowbase: interi stampati senza il prefisso (default)
showpoint: floating point stampati sempre col punto decimale
noshowpoint: stampa i floating point come interi se non frazionari (default)
showpos: stampa + per numeri positivi
noshowpos: non stampa + per i numeri positivi (default)
skipws: salta gli spazi bianchi in input (default)
noskipws: non salta gli spazi bianchi in input
uppercase: stampa 0X in esadecimale, E in scientifica
lowercase: stampa 0x oppure e (default)
dec: interi in base 10 (default)
hex: interi in base 16
oct: interi in base 8
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
199
Appendice: Manipolatori di
I/O (2)
left: aggiunge caratteri di riempimento alla destra del val.
right: aggiunge caratteri di riempimento alla sinistra
internal: aggiunge caratteri fra segno e valore
fixed: floating point in notazione decimale (default)
scientific: floating point in notazione scientifica
flush: svuota il buffer
ends: aggiunge il carattere nullo (\0) e svuota il buffer
endl: aggiunge un “newline” e svuota il buffer
ws: “mangia” gli spazi bianchi
• I seguenti manipolatori richiedono:
#include <iomanip>
setfill(ch): definisce il carattere di riempimento
setprecision(n): definisce la precisione per i floating point
setw(n): scrive o legge in n caratteri
setbase(b): interi in base b
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
200
Esempio di I/O con
manipolatori
#include <iomanip>
int main() {
cout << "inserisci un numero: ";
double num=0;
while(cin >> num) {
int pi = (int)(num);
cout << setfill('0') << setprecision(5);
cout << "Il numero inserito e\' " << num << endl;
cout << "La parte intera e\' " << pi << "(" << hex
<< setw(6) << pi << " esadecimale)" << dec << endl;
cout << "La parte frazionaria e\' " << num-pi << endl;
cout << "inserisci un numero: ";
}
inserisci un numero: 12345.678
return 0;
Il numero inserito e' 12346
}
La parte intera e' 12345(003039 esadecimale)
La parte frazionaria e' 0.678
inserisci un numero:
Non tutti i compilatori supportano tutti i manipolatori!!!
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
201
Per saperne di più
• sugli elementi di base del linguaggio C++
**** Lippman, Lajoye, The C++ Primer, 3rd Edition - Addison Wesley
*** Pohl, Object-Oriented Programming Using C++, 2nd Edition - Addison
Wesley
*** Stroustrup, The C++ Programming Language, 3rd Edition - Addison
Wesley
• su trucchi e tranelli in C++
**** Myers, Effective C++, Addison Wesley
**** Myers, More Effective C++, Addison Wesley
*** Coplien, Advanced C++, Addison Wesley
• su STL
**** Glass, Schuchert, The STL <PRIMER>, Prentice Hall
*** Ammeraal, Wiley, STL for C++ Programmers ** Musser, Saini, STL Tutorial and Reference Guide, Addison Wesley
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
202
Per saperne di più (2)
• su OO A&D
*** Booch, Object-Oriented Analysis and Design with Applications,
Benjamin/Cummings
*** Booch, Object Solutions, Addison Wesley
• su UML
**** Fowler, Scott, UML Distilled, Addison Wesley
*** Booch, Rumbaugh, Jacobson, The Unified Modeling Language
User Guide, Addison Wesley
• sui Design Patterns
***
Gamma, Helm, Johnson, Vlissides, Design Patterns, Addison
Introduzione al C++ e alla programmazione ad oggetti
19-23 febbraio 2001
Wesley
203
Scarica

ppt - INFN Bologna