elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di...

147
Elementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele Rimoldi - Dipartimento di Fisica Nucleare e Teorica Università di Pavia, I

Transcript of elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di...

Page 1: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

Elementi di C++ con UML, HTML, Java e Python

Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA

Adele Rimoldi - Dipartimento di Fisica Nucleare e Teorica Università di Pavia, I

Page 2: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

2

Introduzione ........................................................................................................................ 12

Riepilogo del linguaggio C ......................................................................................................... 13

Struttura di un programma in C ............................................................................................ 13

Il Preprocessore .................................................................................................................. 14

Il main program ................................................................................................................... 15

Commenti ........................................................................................................................... 16

Input/Output ........................................................................................................................ 16

I/O: lettura e scrittura ........................................................................................................... 16

I/O: principali funzioni I/O da tastiera .................................................................................... 16

I/O: scanf() .......................................................................................................................... 17

I/O: lettura e scrittura da file ................................................................................................. 18

Tipi predefiniti in C ............................................................................................................... 18

Identificatori ........................................................................................................................ 19

Dichiarazione ...................................................................................................................... 20

typedef .............................................................................................................................. 20

Enumeratori ........................................................................................................................ 21

Operatori ............................................................................................................................ 22

Espressioni di assegnazione ................................................................................................ 22

Statements ......................................................................................................................... 23

Statement composti ............................................................................................................ 23

if ......................................................................................................................................... 23

while e do-while .................................................................................................................. 24

break e continue ................................................................................................................. 24

switch ................................................................................................................................. 25

L’operatore ? ...................................................................................................................... 25

Array .................................................................................................................................. 25

Puntatori ............................................................................................................................. 27

Page 3: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

3

& ........................................................................................................................................ 27

* ......................................................................................................................................... 27

Puntatore nullo .................................................................................................................... 28

Puntatori e array .................................................................................................................. 28

Puntatori: allocazione dinamica ............................................................................................ 29

Regole di conversione e cast ............................................................................................... 30

Funzioni .............................................................................................................................. 30

Prototipi delle funzioni .......................................................................................................... 31

Call-by-Value ...................................................................................................................... 31

Call-by-Reference ............................................................................................................... 32

Funzioni esterne ................................................................................................................. 33

struct .................................................................................................................................. 33

Accesso ai membri delle strutture ......................................................................................... 35

Passaggio dei membri di una struct a una funzione ............................................................... 35

Passaggio di una intera struttura ad una funzione ................................................................. 36

Puntatori a strutture ............................................................................................................. 36

Dichiarazione di un puntatore ad una struttura ...................................................................... 36

Uso dei puntatori a struttura ................................................................................................. 36

L’operatore -> ..................................................................................................................... 36

C++ come C “migliorato” ............................................................................................................ 38

main program ..................................................................................................................... 38

Parametri del programma .................................................................................................... 39

Organizzazione dei files ....................................................................................................... 40

Stringhe .............................................................................................................................. 40

Size e capacity .................................................................................................................... 41

Accesso agli elementi di una stringa ..................................................................................... 41

iostream ............................................................................................................................. 42

Manipolatori ........................................................................................................................ 43

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 3

Page 4: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

4

fstream ............................................................................................................................... 44

stringstream ........................................................................................................................ 44

commenti ............................................................................................................................ 45

const .................................................................................................................................. 45

Riferimenti .......................................................................................................................... 46

Riferiementi e Puntatori ....................................................................................................... 46

Scope ................................................................................................................................. 46

namespace ......................................................................................................................... 47

new e delete ....................................................................................................................... 48

Regole di conversione e cast ............................................................................................... 48

Casting in ANSI C++ ........................................................................................................... 49

Funzioni .............................................................................................................................. 49

Funzioni inline ..................................................................................................................... 50

Argomenti di default ............................................................................................................ 50

Call by reference ................................................................................................................. 50

Overloading ........................................................................................................................ 51

Function signature ............................................................................................................... 51

C++ vs. C: le differenze ....................................................................................................... 51

Classi ........................................................................................................................................ 53

Linguaggio C e struct ........................................................................................................... 53

Problema: il tipo complesso ................................................................................................. 53

Metodi ................................................................................................................................ 54

Metodi const ....................................................................................................................... 55

Modificatori ......................................................................................................................... 55

L’ esempio: il tipo complesso ............................................................................................... 56

Classi ................................................................................................................................ 57

struct e class: riepilogo ........................................................................................................ 58

L’ esempio: il tipo complesso ............................................................................................... 58

CORSO DI INFORMATICA PER LA FISICA4

Page 5: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

5

Costruttori e distruttori .......................................................................................................... 59

L’ esempio: il tipo complesso ............................................................................................... 59

Inizializzazione .................................................................................................................... 60

Costruttore di default ........................................................................................................... 60

Costruttore di copia ............................................................................................................. 61

Costruttori ad un parametro ................................................................................................. 62

Distruttore ........................................................................................................................... 62

L’ esempio: il tipo complesso ............................................................................................... 63

Operatori ............................................................................................................................ 63

Regole per la ridefinizione degli operatori ............................................................................. 64

Un esempio: l’operatore << .................................................................................................. 64

L’esempio: il tipo complesso ................................................................................................ 65

this ..................................................................................................................................... 65

L’operatore di assegnazione (=) ........................................................................................... 66

Overloading di operatori ...................................................................................................... 66

Che cos’è una classe? ........................................................................................................ 67

Un esempio: come costruirla ed usarla ................................................................................. 67

Incapsulamento .................................................................................................................. 69

friend .................................................................................................................................. 70

static ................................................................................................................................... 70

Un contatore ....................................................................................................................... 71

Singleton ............................................................................................................................ 72

Templates ................................................................................................................................. 74

Template di template ........................................................................................................... 74

Funzioni template e parametri .............................................................................................. 75

Membri statici ..................................................................................................................... 76

Un esempio:lo stack di interi ................................................................................................ 76

typename ........................................................................................................................... 78

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 5

Page 6: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

6

Un altro esempio: la classe Queue ....................................................................................... 79

Potenza dei templates ......................................................................................................... 81

STL (Standard Template Library) ............................................................................................... 82

Template (ripasso) .............................................................................................................. 82

Container ............................................................................................................................ 82

Container sequenziali .......................................................................................................... 83

Operazioni comuni a tutti i container ..................................................................................... 83

Sequenze ........................................................................................................................... 83

vector ................................................................................................................................. 84

list ...................................................................................................................................... 85

deque ................................................................................................................................. 86

Stringhe .............................................................................................................................. 86

Accesso agli elementi di una stringa ..................................................................................... 87

Stringhe e vectors ............................................................................................................... 88

Funzioni numeriche globali .................................................................................................. 88

Contenitori associativi .......................................................................................................... 89

map .................................................................................................................................... 89

multimap ............................................................................................................................. 90

Contenitori speciali .............................................................................................................. 90

queue ................................................................................................................................. 91

Iteratori ............................................................................................................................... 91

Iterator adapters .................................................................................................................. 92

Funzioni base ..................................................................................................................... 93

Algoritmi ............................................................................................................................. 94

Algoritmi di manipolazione ................................................................................................... 94

Nonmodifying algorithms ..................................................................................................... 96

Algoritmi di modificazione .................................................................................................... 96

Algoritmi di removing e mutating .......................................................................................... 96

CORSO DI INFORMATICA PER LA FISICA6

Page 7: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

7

Polimorfismo ed ereditarietà ...................................................................................................... 98

Classi base e classi derivate ................................................................................................ 98

“Is a” ................................................................................................................................... 99

Ereditarietà (Inheritance) ..................................................................................................... 99

Classi base ......................................................................................................................... 99

Metodi virtuali .................................................................................................................... 100

Metodi virtuali e classi astratte ............................................................................................ 101

Ereditarietà ed interfaccia .................................................................................................. 102

Costruttori ed ereditarietà ................................................................................................... 102

Distruttori ed inheritance .................................................................................................... 103

Inheritance privata ............................................................................................................. 103

Un esempio:l’elenco telefonico ........................................................................................... 103

Ereditarietà multipla ........................................................................................................... 104

dynamic_cast .................................................................................................................... 105

Un altro esempio di polimorfismo ....................................................................................... 105

Un altro esempio: shape .................................................................................................... 106

Esempio di ereditarietà multipla .......................................................................................... 112

UML (Unified Modeling Language) ........................................................................................... 115

Processi ............................................................................................................................ 115

Scopo (Inception phase) ed elaborazione ........................................................................... 115

Rischi .............................................................................................................................. 115

Use cases ......................................................................................................................... 116

Scheletro di un modello concettuale ................................................................................... 116

Planning .......................................................................................................................... 116

Costruzione ...................................................................................................................... 116

Transizione ....................................................................................................................... 117

Strategie nello sviluppo di un progetto ................................................................................ 117

L’esempio: il sistema solare ............................................................................................... 117

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 7

Page 8: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

8

Confronto tra i modelli di sviluppo ....................................................................................... 118

Requisiti ............................................................................................................................ 118

Analisi ............................................................................................................................... 118

Disegno ............................................................................................................................ 119

Codifica ............................................................................................................................ 119

Test .................................................................................................................................. 119

Metodi di sviluppo del software .......................................................................................... 120

Diagrammi ........................................................................................................................ 120

UML per l’analisi e il disegno .............................................................................................. 121

Class diagrams ................................................................................................................ 121

Rappresentazione delle classi ............................................................................................ 122

Attributi e metodi ............................................................................................................... 122

Principali relazioni tra classi ............................................................................................... 122

Associazioni ...................................................................................................................... 123

Aggregazione(contenimento) ............................................................................................. 123

Composizione ................................................................................................................... 124

Dipendenza ...................................................................................................................... 124

Generalizzazione (ereditarietà) .......................................................................................... 125

Esempi di Class Diagram .................................................................................................. 125

Interaction Diagrams ......................................................................................................... 126

Collaboration Diagrams ..................................................................................................... 127

Altri diagrammi .................................................................................................................. 127

CRC (Classi, Responsabilità, Collaborazioni) ...................................................................... 128

CRC Workshop ................................................................................................................. 129

Design patterns ................................................................................................................. 129

Composite ........................................................................................................................ 130

Gruppo di Shapes ............................................................................................................. 131

Strategy ............................................................................................................................ 132

CORSO DI INFORMATICA PER LA FISICA8

Page 9: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

9

Observer ........................................................................................................................... 132

Open/Closed principle ....................................................................................................... 132

HTML ..................................................................................................................................... 134

DTML, XML HTML browsers ............................................................................................. 134

Utilizzatori e Programmatori ............................................................................................... 134

Le basi di HTML ................................................................................................................ 135

tags .................................................................................................................................. 135

attributes .......................................................................................................................... 135

values ............................................................................................................................... 135

Simboli speciali ................................................................................................................. 136

URL(Uniform Resource Locator) ........................................................................................ 136

Il design del proprio sito web .............................................................................................. 136

Creare una pagina web ..................................................................................................... 137

Formattazione del testo ..................................................................................................... 137

Creare immagini ................................................................................................................ 137

Formato ............................................................................................................................ 137

Colore ............................................................................................................................... 138

Trasparenza ..................................................................................................................... 138

Velocità ............................................................................................................................. 138

Animazione ....................................................................................................................... 138

Utilizzare le immagini ......................................................................................................... 138

Testo attorno alle immagini ................................................................................................ 139

Layout ............................................................................................................................. 139

Links ................................................................................................................................. 140

Liste ................................................................................................................................. 140

Tabelle ............................................................................................................................. 140

Frames ............................................................................................................................. 141

Forms ............................................................................................................................... 141

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 9

Page 10: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

10

Java ........................................................................................................................................ 142

Che cosa c’è di nuovo in Java? .......................................................................................... 142

Java ed Internet ................................................................................................................ 143

Linguaggi compilati ed interpretati ..................................................................................... 143

Bytecode .......................................................................................................................... 143

Applicazioni ed applets ...................................................................................................... 143

Un esempio di applicazione ............................................................................................... 144

Java vs. C++ ..................................................................................................................... 144

Creazione degli oggetti ...................................................................................................... 144

Ereditarietà ....................................................................................................................... 144

Interfacce .......................................................................................................................... 144

Un esempio ...................................................................................................................... 145

Uso delle interfacce ........................................................................................................... 145

Pacchetti ........................................................................................................................... 145

Un Applet .......................................................................................................................... 146

L’esecuzione dell’applet ..................................................................................................... 146

Un esempio di applet ......................................................................................................... 146

La programmazione multithread ......................................................................................... 147

La gestione delle eccezioni ................................................................................................ 147

Un ulteriore esempio ......................................................................................................... 148

Python .................................................................................................................................... 156

Usare l’interpreter di Python ............................................................................................... 157

Usare python come una calcolatrice ................................................................................... 157

altre caratteristiche generali del linguaggio .......................................................................... 157

stringhe ............................................................................................................................. 158

docstrings ......................................................................................................................... 159

Tipi numerici ..................................................................................................................... 159

moduli ............................................................................................................................... 159

CORSO DI INFORMATICA PER LA FISICA10

Page 11: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

11

importare moduli ............................................................................................................... 159

sequences ........................................................................................................................ 159

lists ................................................................................................................................... 159

tuples ................................................................................................................................ 159

strings ............................................................................................................................... 159

unpacking tuples ............................................................................................................... 159

indexing and slicing ........................................................................................................... 159

sequence operations ......................................................................................................... 159

binding – call by value ....................................................................................................... 159

Bibliografia .............................................................................................................................. 160

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 11

Page 12: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

12

Introduzione

Lo scopo di questo corso risiede nell’insegnare i concetti della programmazione Object Oriented attraverso l’introduzione del linguaggio C++. Esso è rivolto a studenti del primo anno del Corso di Laurea in Fisica triennale (Laurea Specialistica in Scienze Fisiche) che hanno già seguito il corso propedeutico di Informatica per la Fisica I nel primo semestre e che quindi posseggono conoscenze basilari del linguaggio C nonché familiarità con Unix. La generalità dell’approccio rende questo corso altresì adatto anche a studenti di altri indirizzi di Laurea affini che abbiano un corso similare nel loro piano di studi.

Nella progettazione di questo corso e nella stesura di questo testo si è quindi scelta la strada del riepilogo dei concetti già noti riguardo il linguaggio C per poi passare all’introduzione delle caratteristiche principali ed innovative del linguaggio C++ rispetto al C.

In realtà quasi tutti i manuali di C++ esistenti sono divisi in due parti, la prima che introduce il linguaggio C, la seconda che consiste in una sorta di estensione del linguaggio C per la programmazione Object Oriented, ovvero il C++. Alcuni manuali recenti propongono un approccio diretto alla programmazione in C++ e alla metodologia UML e risultano quindi maggiormente dedicati a studenti privi della conoscenze qui previste. In questo corso si omette qualunque riferimento al FORTRAN dato che non è oggetto di studio nel corso del primo semestre e che, anche se ancora largamente usato in molti campi della fisica, nel corso del tempo verrà sostituito da linguaggi più evoluti.

Perché si insegna la programmazione Object Oriented? In genere perché essa semplifica considerevolmente la gestione di medi e grandi pacchetti di software tipici di grandi strutture (banche, industrie, enti pubblici). Inoltre l'informatizzazione sta diventando un elemento fondamentale nella vita di un fisico, sia che la sua attività rimanga chiusa in ambito Universitario sia che spazi nell’Industria.

Questo Corso viene per la prima volta introdotto nel Corso di Laurea in Fisica quale corso fondamentale del primo anno e queste dispense nascono dal desiderio di fornire agli studenti un supporto di studio adeguato ai contenuti esposti durante le lezioni in aula.

Questo testo, nella sua prima stesura odierna, sarà quindi ricco di imprecisioni ed incompleto e non vuole avere nessuno scopo se non quello di annotare gli argomenti trattati. Il testo riporta il contenuto di ciascun argomento presentato a lezione e un seguente commento, talvolta ampliato o circostanziato.

Gli studenti che ritengono di avere interessi che vanno oltre quanto presentato qui sono rimandati, attraverso una ampia bibliografia, a testi ‘classici’ o meno noti che sembrano meglio spaziare sugli argomenti trattati durante le lezioni.

Esiste una versione del corso (in formato powerpoint) rintracciabile su web all’indirizzo:

http://www.pv.infn.it/~rimoldi/corsoinformatica.html

CORSO DI INFORMATICA PER LA FISICA12

Page 13: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

13

Riepilogo del linguaggio C

In questo capitolo vengono riepilogati i concetti fondamentali della programmazione in linguaggio C. Una versione powerpoint delle trasparenze relative al seguente capitolo del corso si trovano all’ indirizzo riportato nell’ introduzione e sono scaricabili direttamente via rete.

Struttura di un programma in C

Un programma in C è composto da:

file sorgente :. . contengono le istruzioni da compilare per creare gli eseguibili ed includono i così detti file header. Sono normalmente caratterizzati da un’estensione .c.c

//main.c#include <stdio.h>main(){ printf(“Ciao \n”); return 0;}

file “header” : contengono dichiarazioni di funzioni e variabili e definizioni di “macro”. Vengono inclusi in un file sorgente prima della compilazione per mezzo del pre-processore C ed hanno normalmente un’estensione .h..h.

max.h extern int max(int,int);

Nel linguaggio C lettere maiuscole e minuscole sono distinte. E’ inessenziale il punto di partenza per la scrittura del codice lungo una linea (diversamente da altri linguaggi, come ad esempio il FORTRAN e il COBOL). Naturalmente un certo ordine non può che aiutare nella lettura e viene fortemente consigliato.

A differenza di altri linguaggi ad alto livello il C non esegue verifiche di errore a run-time. Tali controlli devono essere quindi implementati dal programmatore (per esempio, la verifica del non superamento dei limiti degli array).

In C un argomento può essere di qualsiasi tipo che possa essere ragionevolmente convertito nel tipo del parametro (in C, la conversione di tipo viene eseguita automaticamente).

La peculiarità del linguaggio consiste nella possibilità di manipolazione diretta dei bit, byte, word e puntatori. Quindi è adatto a programmazione di software di sistema in cui questo genere di operazioni è molto comune.

Il C è un linguaggio strutturato: è possibile suddividere e nascondere dal resto del programma, tutte le informazioni e le istruzioni necessarie per eseguire una determinata operazione. Tali subroutine impiegano variabili locali (temporanee) che non influenzano direttamente il resto del programma. L'utilizzo di subroutine semplifica la condivisione di parti di codice da parte di più programmi.

Tutte le linee di programmazione devono essere concluse da un carattere di “;”.

Un blocco di codice è formato da un gruppo di istruzioni connesse logicamente, considerato come una unità singola e posto tra due parentesi graffe. La forma generale di un programma C è la seguente:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 13

Page 14: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

14

Dichiarazioni globalitipo restituito main(elenco parametri){

sequenza istruzioni}tipo restituito f1(elenco parametri){

sequenza istruzioni}tipo restituito f2(elenco parametri){

sequenza istruzioni}…tipo restituito fN(elenco parametri){

sequenza istruzioni}

Tutti i compilatori sono dotati di una libreria di funzioni standard che eseguono le operazioni più comuni. Molti programmi contengono quindi chiamate a tali funzioni

►► Il linguaggio C++ supporta l’intera libreria di funzioni definita dallo standard C, quindi nei programmi C++ sono disponibili tutte le funzioni standard C.

Quando una funzione che non fa parte del programma viene richiamata, il compilatore C prende nota del nome e in seguito il linker riunisce al codice scritto dal programmatore il codice oggetto che si trova nella libreria standard (linking).

Il Preprocessore

Il preprocessore è parte del processo di compilazione in C in grado di riconosce speciali istruzioni che possono essere inframmezzate all’interno di un programma. Come implica il suo nome, il preprocessore analizza questi statements speciali prima che l’analisi del programma vero e proprio abbia luogo. Esso fornisce al programmatore la possibilità di sviluppare programmi più facili da leggere, da modificare, da trasportare su computer o compilatori diversi. Infatti le direttive di pre-processamento permettono di selezionare il codice da compilare a seconda del tipo di sistema operativo, della versione del compilatore etc

In un file sorgente, qualsiasi istruzione che cominci con il simbolo # in colonna 1 viene interpretata dal preprocessore.

#include <stdio.h> /*inclusione di uno header di sistema*/#include “mydefs.h” /*inclusione di uno header “personale”*/#define MAX 100 /*definizione di una costante*/#define MAX(a,b) a<b?b:a; /*definizione di una macro*/

#if /*direttiva di compilazione condizionale*/ ...#else ...#endif

#ifdef /*utilizza definizioni precedenti*/ ...#else ...#endif

Lo statement:

CORSO DI INFORMATICA PER LA FISICA14

Page 15: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

15

#define TRUE 1

definisce il nome TRUE e lo rende equivalente a 1. Il nome TRUE può essere usato nel programma tutte le volte che la costante 1 può essere usata. Ovunque il nome appaia il suo valore definito di 1 sarà automaticamente sostituito nel programma dal preprocessore.

Invece le seguenti definizioni di preprocessore

#define AND &&#define OR ||

permettono di scrivere

if(y==0 OR y==value)…

La compilazione condizionale è un’altra delle caratteristiche del proprocessore. Essa è spesso utilizzata per avere lo stesso programma che funziona su diversi sistemi. E' anche usata per abilitare o disabilitare selettivamente statements del programma (per esempio per il debug).

#if MACHINE == 1 /* VAX-11 */…#elif MACHINE == 2 /* IBM PC */...#else...#endif

Altre istruzioni di preprocessore aiutano a personalizzare il codice eseguibile o per scopi particolari; se per esempio si vuole rendere indefinito un nome particolare (precedentemente definito) si può utilizzare la seguente istruzione:

#undef nome

Un seguente #ifdef nome o #ifdefined nome sarà valutato falso.

Il main program

Ogni programma in C, per essere eseguibile, deve contenere una funzione main(), punto di partenza dell'esecuzione. Il tipo ritornato da main()è un intero, come atteso dai sistemi operativi (return code dell’applicazione)

main(){ /* il più semplice programma in C */}

Le parentesi aperta e chiusa dopo un nome identificano una funzione. Il regione tra le parentesi graffe è il corpo della subroutine. In questo caso contiene semplicemente una linea di commento (il programma non fa assolutamente niente).

Commenti

In C esiste la possibilità di inserire linee di commento nel codice (buona pratica per documentare la funzionalità di un programma). I commenti sono caratterizzati da una coppia /* */. Tutto quanto è compreso fra questi caratteri non verrà considerato dal compilatore (viene rimosso dal preprocessore)

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 15

Page 16: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

16

int Ntries; /* questo e‘ un commento multiline:tutto viene trattato come un commentofino a quando il commento stesso non viene chiuso con uno */

Un commento inizia con i caratteri /* e termina non appena sono incontrati i caratteri */. Un commento può essere inserito ovunque in un programma.

►►Il linguaggio C++ supporta lo stesso tipo di commenti, ma ne aggiunge un altro tipo che vale per la lunghezza di una linea di codice senza necessità di delimitarne il fondo

// questo è un commento in C++

Input/Output

Le principali finzioni di I/O si possono eseguire da file o da tastiera. Benché si tratti concettualmente di situazioni diverse, tecnicamente non esiste una grande diversità tra le funzioni da tastiera o da file.

I/O: lettura e scrittura

Per leggere e scrivere dati formattati si usa scanf() (legge dati dalla tastiera) e printf() (scrive dati sullo schermo), che accettano qualsiasi tipo di dati interno del C compresi caratteri, stringhe e numeri. Queste funzioni sono contenute nella standard library del C che viene richiamata usando il comando di preprocessore “#include <stdio.h>” che include tutte le dichiarazioni e definizioni di macro contenute nella standard C library

#include <stdio.h>main(){ printf( “Hello, world !\n” ); /* \n e' il carattere di newline */}

I/O: principali funzioni I/O da tastiera

putchar()putchar() legge un carattere da tastiera (attende la pressione di “enter”)putchar()putchar() scrive un carattere sullo schermogets()gets() legge una stringa dalla tastieraputs()puts() scrive una stringa sullo schermo

La funzione getchar()permette di leggere dati dal terminale un carattere alla volta. Si può sviluppare facilmente una funzione read_line() per leggere una intera linea di testo da un terminale. Questa funzione chiamerà ripetutamente getchar() finché un carattere di newline viene riconosciuto. Una funzione analoga alla precedente, ma per scrivere dati sul terminale è putchar().

I prototipi delle funzioni getchar e putchar sono

int getchar(void);int putchar(int c):

Esempio:

putchar (c) ;putchar (‘\n’); /* muove il cursore all’inizio della riga successiva */

Il solo argomento richiesto e’ il carattere da essere inviato: 'c' che è definito di tipo char.

CORSO DI INFORMATICA PER LA FISICA16

Page 17: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

17

gets() e puts() leggono e scrivono rispettivamente una stringa dalla/sulla tastiera. Anch’esse fanno parte della standard library.

La funzione printf() scrive sullo standard output (stdout), in accordo con il formato specificato, gli argomenti elencati e restituisce il numero di caratteri scritti o un valore negativo in caso di errore.

int printf(format,arg1,arg2,argN);

Nell’esempio seguente è illustrato un semplice programma che, definiti gli interi v1 e v2 ne stampa il valore della somma (sum) sfruttando un'appropriata funzione printf()

#include <stdio.h>main(){ int v1, v2,sum; v1=50; v2=25; sum=v1+v2; printf( “Sum of %i and %i is %i\n”,v1,v2,sum);}

I campi e le convenzioni di formattazione sono indicate nel prospetto seguente:

%c legge un singolo carattere%d(i) un intero decimale%e(f)(g) un numero in virgola mobile%o un numero ottale%s una stringa%x un numero esadecimale%p un puntatore%n riceve un numero intero= al numero di caratteri letti%u legge un intero senza segno%[ ] attende l’immissione di un determinato gruppo di caratteri%% legge un segno percentuale

I/O: scanf()

Questa funzione della libreria standard del C viene utilizzata per leggere da console secondo il formato specificato dalla stringa format

int scanf(format,arg1,arg2,…);

Gli argomenti che seguono format devono essere tutti puntatori (definiti nei capitoli seguenti). La funzione restituisce il numero di dati a cui è stato assegnato un valore o l'identificatore EOF (End Of File) in caso di errore (cioè quando viene incontrata la fine del file prima che tutti gli elementi siano stati convertiti).

#include <stdio.h>main(){ int i,j;

scanf( “%o%x”,&i ,&j); /* Legge un numero ottale e uno esadecimale */printf(“%o,%x,i,j); /* Stampa i numeri precedenti leggi */return 0;

}

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 17

Page 18: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

18

I/O: lettura e scrittura da file

Molto spesso occorre leggere dati da un file o scriverli su un file. Entrambe queste operazioni possono essere eseguite facilmente in Unix utilizzando gli operatori di riindirizzamento. Se ad esempio volessimo scrivere tutti i risultati di un programma in un file di nome data potremmo redirigere l'output del programma nel file in questione

a.out > data

Il comando istruisce il sistema ad eseguire il programma a.out e a mandare nel file data, tutto l’output che normalmente viene visualizzato sul terminale. Naturalmente se si volesse redirigere anche l’input facendolo leggere da un file basterebbe usare la sintassi:

a.out < number > data

dove number è un file di input che contiene l’informazione che dovrebbe essere digitata sulla tastiera. Il re-indirizzamento dell’ I/O non è parte dello standard ANSI C, questo significa che si possono trovare sistemi operativi che non la supportano (anche se nella maggior parte dei casi questo non succede).

►►Il linguaggio C++ supporta l’intero sistema di I/O su file del C. Quindi le trasformazioni di codice da C a C++ non richiedono alcuna variazione per quanto riguarda le routine di I/O del programma.

Tipi predefiniti in C

In C sono definiti una serie di tipi numerici che permettono di rappresentare numeri interi, reali e caratteri. char (un solo byte) viene normalmente usato per rappresentare interi inferiori a 256. Stringhe e numeri complessi sono implementati come tipi derivati. Non esiste un tipo “logico” a significare “vero” o “falso”. Si utilizza generalmente una macro

#define TRUE 1#define FALSE 0

I tipi definiti nel C sono:

int intero in singola precisionelong intero in doppia precisionefloat reale in singola precisionedouble reale in doppia precisionelong double reale in precisione estesaunsigned int intero senza segnounsigned double reale senza segno in doppia precisionechar carattere singolo

Esempi di costanti:

123 intero decimale0x123 intero esadecimale 123l intero long123u intero unsigned‘A’ carattere3.14f float 3.1415L long double300E-2 notazione esponenziale“Nome” stringa costante

Costanti carattere:

CORSO DI INFORMATICA PER LA FISICA18

Page 19: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

19

‘\a’ alert‘\\’ backslash‘\b’ backspace‘\r’ carriage return‘\”’ double quote‘\f’ form feed‘\t’ tab‘\n’ newline‘\0’ carattere nullo‘\’’ single quote‘\v’ vertical tab‘\101’ 101 ottale, ‘A’‘\x041’ esadecimale, ‘A’

Stringhe costanti:

“” stringa nulla (‘\0’)“nome” ‘n’ ‘o’ ‘m’ ‘e’ ‘\0’“una \”stringa\”” stampa: una “stringa”“una stringa \ un \ alla fine della lineasu piu‘ linee” per continuare la stringa

Il numero di bit riservati ad ogni tipo dipende dal microprocessore e dal compilatore impiegati. Come si vede anche dalla tabella un carattere è ad esempio contenuto in un byte nella maggior parte dei casi. Le dimensioni di un intero sono generalmente uguali alle dimensioni di una word nell’ambiente di esecuzione del programma. In genere un intero occupa 32 bit.

►►Il linguaggio C++ aggiunge ai tipi definiti bool e wchar che non hanno uguale in C

Identificatori

I nomi delle variabili, delle funzioni, delle etichette e degli altri oggetti definiti dall’utente sono chiamati genericamente identificatori. Un identificatore è composto da uno o più caratteri. Il primo carattere deve essere una lettera o un underscore (carattere di sottolineatura). I caratteri successivi possono essere lettere, numeri o underscore. Gli identificatori che iniziano con un doppio underscore o con un underscore e una lettera maiuscola sono riservati ad usi di sistema. Non esiste un limite in lunghezza, anche se alcuni sistemi si limitano a considerare i primi 31 caratteri

►►Il linguaggio C++ supporta qualsiasi lunghezza per un identificatore, fino a 1024 caratteri

int Ntries; double _attempts;double 2A; /* errore! */

Dichiarazione

Le dichiarazioni associano un significato ad un identificatore. In C ogni variabile deve essere dichiarata per poter essere usata. La forma generale di una dichiarazione è:

tipo elenco_variabili;

tipo deve essere un tipo di dati valido in C, mentre elenco variabili può essere formato da uno o più nomi di identificatori separati da virgole. Diversamente da altri linguaggi (es: Fortran) in C il nome della variabile non ha nulla a che fare con il suo tipo.

int i; /* la variabile i */double max(double r1,double r2); /* la funzione max */

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 19

Page 20: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

20

Una dichiarazione è spesso anche una definizione. Per variabili semplici questo consiste nell’associare un valore alla variabile al momento della dichiarazione

double pi=3.1415926; /* definizione */double max(double r1, double r2) { /* dichiarazione*/ return (r1>r2) ? r1: r2; /*definizione di max*/ }

Le variabili possono essere definite in tre luoghi diversi:• all’ interno delle funzioni (variabili locali)• nella definizione dei parametri delle funzioni• all’esterno delle funzioni

Le variabili locali possono essere usate solo dalle istruzioni che si trovano all’interno del blocco in cui sono dichiarate. Esse quindi NON sono note all’esterno del proprio blocco di codice che inizia e chiude con una coppia di parentesi graffe. La vita delle variabili locali è legata all’esecuzione del blocco di codice in cui sono dichiarate.

Normalmente si dichiarano le variabili locali all’inizio del blocco di codice, cioè subito dopo la parentesi graffa di apertura della funzione e prima di ogni altra istruzione. Si possono tuttavia dichiarare variabili locali in qualunque altro punto del blocco di codice, per esempio dentro un if.

Le variabili globali sono dichiarate al di fuori di qualsiasi funzione e sono note all’intero programma; possono quindi essere usate ovunque. Esse conservano inoltre il proprio valore per l’intera esecuzione del programma.

double r; /* r è globale, può essere usata da */ /* tutte le funzioni definite in questo file */main(){ int i=4; /* dichiarazione e definizione */ double h; r=3; h=i*r;}

typedef

L’istruzione typedef viene utilizzata per creare un alias per tipi esistenti, cioè non si crea un nuovo tipo di dati ma si definisce un nuovo nome ad un tipo di dati preesistente. Ciò può essere utile per rendere più trasportabili i programmi dipendenti dal sistema operativo.

La forma generale è la seguente:

typedef tipo nuovonome;

typedef int INTEGER; /* per i nostalgici del fortran */typedef int BOOLEAN /* un tipo logico */typedef void (*ptr_f)(); /* ptr_f e` un puntatore ad una subroutine */

questo nuovo nome si aggiunge a quello preesistente senza sostituirlo.

La typedef NON può essere usata per implementare nuovi tipi (ma solo per definire un alias)

typedef mela frutto; /* compila solo se mela e` gia` stata definita*/

►► Il linguaggio C++ supporta lo stesso tipo di definizione

CORSO DI INFORMATICA PER LA FISICA20

Page 21: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

21

Enumeratori

L'enumerazione (enum) è il caso più semplice di un tipo definito dall’utente (è assimilabile ad un tipo intero). E' formata da un gruppo di costanti intere dotate di un nome che specificano tutti i valori consentiti per una variabile di tale tipo. La forma generale delle enumerazioni è la seguente:

enum nome_tipo_enumerativo {elenco enumerazioni} elenco_variabili;

Esempi:

enum Color { red, green=10, blue};

Color screenColor = blue;Color windorColor = red;

int n = blue; /* valido */Color c = 1; /* errore */

enum Seme { cuori, picche, quadri, fiori}; /* NB: cuori è il nome di un intero, non di una stringa. */

Il nome del tipo enumerazione può essere utilizzato per dichiarare variabili di tale tipo. In C la seguente riga dichiara money come una variabile di tipo coin

enum coin money;

Il fattore chiave per capire una enumerazione è che ad ognuno dei simboli corrisponde un valore intero. Questi valori possono essere utilizzati in qualunque punto si potrebbe utilizzare un intero. Ad ogni simbolo viene assegnato un valore maggiore di una unità rispetto al simbolo precedente. Il valore del primo simbolo dell’enumerazione è 0. L'esempio seguente visualizza i valori 0 e 2

printf(“%d %d”, cuori, quadri);

I valori di uno o più simboli possono essere esplicitati tramite un inizializzatore: in uno degli esempi precedenti green è posto a 10.

►►Il linguaggio C++ semplifica invece la definizione per cui la stessa variabile può essere dichiarata con la seguente forma abbreviata: coin money;

Operatori

Esistono quattro classi principali di operatori in C

►►Il linguaggio C++ si comporta in ugual modo per quanto riguarda gli operatori.

Espressioni aritmetiche -i +w piu` e meno unaria*b a/b i%2 moltiplicazione,divisione, moduloa+b a-b addizione e sottrazione binariea=3; assegnazione

auto-incremento e decremento espressione equivalente k = ++j; j=j+1; k=j; k = j++; k=j; j=j+1; k = --j; j=j-1; k=j; k = j--; k=j; j=j-1;

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 21

Page 22: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

22

Gli operatori di incremento e di decremento si comportano diversamente a seconda che l’operatore preceda o segua l’operando. Se l’operatore precede l’operando l’incremento o il decremento è effettuato prima di fornire il valore dell’operando all’espressione. Nel caso contrario l'incremento (decremento) è effettuato dopo l'assegnazione.

x=10;y= ++x; /* y assume il valore 11 */

x=10;y= x++; /* y assume il valore 10 */

Tabella operatori relazionali

< minore di .LT.> maggiore di .GT.<= minore o uguale .LE.>= maggiore o uguale .GE.== uguale .EQ.!= diverso .NE.! Negazione unaria .NOT.&& and logico .AND.|| or logico .OR.

Tabella operatori bit-wise

~i Complemento bit a biti&j AND bit a biti|j OR bit a biti^j XOR bit a biti<<n shift a sinistra di n pos.i>>n shift a destra di n pos.

Espressioni di assegnazione

Le espressioni di assegnazione sono valutate da destra a sinistra

a = j++; /* j viene assegnato ad a ed in seguito incrementato */

Le assegnazioni multiple sono permessea = b = c = d = 100;

Alcuni operatori di assegnazione combinano assegnazione ed altri operatori.

a *= b; /* equivale ad a = a*b; */a -= b; /* equivale ad a = a-b; */

Assegnazioni possono essere fatte all’interno di espressioni aritmetiche

a = b + ( c = 3 ); /* equivale a c=3; a=b+c; */

Statements

Le tabelle seguenti indicano una sintesi di statement comuni a partire dal più semplice (quello vuoto costituito solo dal carattere finale di linea (;) agli altri più articolati.

CORSO DI INFORMATICA PER LA FISICA22

Page 23: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

23

vuoto ;espressione j=j+k;composto { . . . . } Usato in funzioni, if.. costituisce un blocco goto goto label; Da non usarsi if if (p==0) if con un solo branch

cerr<<“error”;if-else if (x==y) if con due branch

printf(“the same\n”); else

printf(“different\n”);for for (j=0;j<n;j++) usato per definire un loop

a[j]=0;while while (i != j) 0 o più iterazioni

i++;do-while do

y=y-1; 1 o piu` iterazioni while (y>0);

break break; esce dal blocco continue continue; va alla prossima iterazioneswitch switch (s) {

case 1: Si deve usare break per ++i; evitare di cadere nei case 2: casi successivi --i; Si deve aggiungere un caso di default: default alla fine della lista

++j; };

dichiarazione int i=7; globale o in un funzione label error:

cerr<<“Error!”; usato con gotoreturn return x*x*x; ritorno da una funzione

Statement composti

Uno statement composto in C è 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. Ovunque si possa usare uno statement singolo si può definire un blocco.

if

Attenzione alla differenza tra “=” e “==”; il primo è un assegnazione

if (i=1) /* questo e` sempre vero!!! */{. . . .}

Nel dubbio, usare sempre un blocco…

if (i != 0) /* possibile divisione per 0 */ a++; /* mancano delle {}? */a/=i;

Prestare attenzione ai corretti accoppiamenti tra if e else

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 23

Page 24: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

24

if (i == 0) /* possibile divisione per 0 */ if (a<0) {

printf(“a e` negativo!\n”); }else b=a/i; /* Il compilatore associa questo else all'if piu' interno, e non al primo come voluto dal programmatore */

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 valore della condizione, lo statement verrà eseguito zero o più volte

La sintassi di un do-while è invece:

dostatement;

while (condizione);

Lo statement verrà quindi eseguito almeno una volta

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];scanf(“%i”,&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 do-while. break è anche usato negli switch

switch

Lo switch è uno statement condizionale che generalizza lo if-else

switch (condizione)(statement);

è generalmente composito e consiste di diversi case e, opzionalmente, di un default

CORSO DI INFORMATICA PER LA FISICA24

Page 25: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

25

switch (n) {case 0:

printf(“ n e` nullo\n”); break;case 1: case 3: case 5: case 7: case 9:

printf(“ n e` dispari\n”); break;case 2: case 4: case 6: case 8: case 10:

printf(“ n e` pari\n”); break;default:

printf“ n non e` compreso tra 0 e 10\n”);}

L’operatore ?

L’operatore ? e‘ l’unico esempio di operatore ternario in C.

expr1 ? expr2 : expr3;

Equivale a:

if(expr1) expr2;else expr3;

Viene cioè valutata l’espressione 1; se è vera viene valutata l’espressione 2 che diverrà il valore dell’espressione. Se invece l’espressione 1 è falsa viene valutata l’espressione 3 ed il suo valore diviene il valore dell’espressione. Nell'esempio seguente, la funzione max ritorna a come massimo se a>b, altrimenti b.

double max(double a, double b){

return max = (a>b) ? a : b;}

Array

Un array è un elenco di informazioni dello stesso tipo conservate in locazioni di memoria contigue (secondo un ordine preciso). E' formato da una serie di variabili dello stesso tipo cui si fa riferimento utilizzando un nome comune. Per accedere ad un determinato elemento si utilizza un indice. L’indirizzo più basso corrisponde al primo elemento, quello più alto all’ultimo. Gli array non sono necessariamente monodimensionali. Il tipo più comune è la stringa che termina con il carattere nullo ('/0'). In C sono supportati gli array di dimensione fissa. La forma generale di una dichiarazione di un array monodimensionale è la seguente:

tipo nome_var[dim];

Come ogni variabile un array deve essere dichiarato esplicitamente in modo che il compilatore possa allocare lo spazio di memoria richiesto. Qui ‘tipo’ dichiara il tipo base dell’array, cioè di ogni elemento; ‘dim’ indica il numero degli elementi che l'array deve contenere. Per dichiarare un array di 100 elementi di tipo double chiamato balance occorre scrivere :

double balance[100];

Per accedere ad un elemento si associa un indice al nome dell’array:

balance[3]=121.121;

In C tutti gli array iniziano dall’indice 0. Quindi quando si scrive

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 25

Page 26: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

26

char p[10]; /* Array di 10 elementi da p[0] a p[9] */

In C non esiste nessuna verifica di superamento dei limiti degli array (da 0 a n-1). Se non si pone abbastanza attenzione, si può finire per scrivere in un’altra variabile o nel codice del programma stesso; solo nei casi più fortunati, ciò provoca un crash del programma (cosa che permette di scoprire e individuare il problema) .

Esempio:

int main() { int x[10]; int i,j; double m[5][5]; for ( i = 0; i < 10, i++ ) /* Riempimento array monodimensionale */ x[i] = 0;

for ( i = 0; i < 5; i++ ) /* Riempimento matrice 5x5 */ for ( 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} };

La moltiplicazione fra matrici è indicata nell’esempio sottostante:

main() { int DIM=3; int i,j,k; float sum=0; float m[DIM][DIM], m1[DIM][DIM], m2[DIM][DIM]; // Assumiamo che m1 ed m2 vengano riempiti qui... // Moltiplicazione: for (i=0; i<DIM; i++) { for (j=0; j<DIM; j++) { for (k=0; k<DIM; k++) sum += m1[i][k] * m2[k][j]; m[i][j] = sum; } }}

PuntatoriUn puntatore è l’indirizzo di memoria di un oggetto. Una variabile puntatore è una variabile dichiarata in modo specifico per contenere un puntatore ad un oggetto di un determinato tipo. In C i puntatori possono

• essere un metodo pratico e rapido per far riferimento agli elementi di un array

• consentono alle funzioni C di modificare i parametri di chiamata

• consentono la creazione di liste concatenate e di altre strutture di dati dinamiche

I due operatori usati per manipolare i puntatori sono ‘&’ e ‘ *’.

CORSO DI INFORMATICA PER LA FISICA26

Page 27: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

27

&è un operatore unario (cioè ha un solo operando) che restituisce l’indirizzo di memoria del proprio operando. L'esempio seguente inserisce nella variabile m l’indirizzo di memoria in cui si trova la variabile count.

m= &count;

Questo indirizzo corrisponde alla posizione fisica della variabile nella memoria. Quindi l’operatore & può essere letto come “indirizzo di “. Se ad esempio la variabile count si trova all’indirizzo di memoria 0x200 e contiene il valore 100, &m restituisce 0x200.

*questo operatore accede al volare “puntato” dalla variabile puntatore. Per esempio l’esempio seguente inserisce il valore di count in q.

q= *m;

inserisce il valore di count in q (q riceve il valore che si trova all’indirizzo di m). Quindi l’operatore & può essere letto come “all’indirizzo”.

Le variabili che devono contenere indirizzi di memoria (i puntatori) devono essere dichiarate inserendo un * davanti al nome della variabile. Ad esempio per dichiarare ch come puntatore ad un carattere si usa:

char *ch;

In questo caso ch non è un carattere ma un puntatore ad un carattere. Il tipo di dati puntati dal puntatore (in questo caso char) è detto tipo base del puntatore. Ma anche un puntatore è una variabile e contiene l’indirizzo del proprio tipo base. Un puntatore può puntare solo a dati corrispondenti al proprio tipo base.

Il codice seguente:

#include <stdio.h>int main(){ int j = 12; int *ptr = &j; printf(“%i\n“, *ptr); j = 24; printf(“%i\n”, *ptr); printf(“%p\n”, ptr); return 0;}

produce sul terminale:

12240x7b03a928 /* indirizzo di memoria */

Puntatore nullo

Il puntatore NULL è utilizzato per indicare la non inizializzazione di puntatore. Il codice seguente produce un crash del programma (segmentation violation)

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 27

Page 28: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

28

include <stdio.h>int main(){ int j = 12; int *ptr = NULL; /* Puntatore nullo */

printf(“%i\n”,*ptr); /* crash! Punta a una regione di memoria invalida*/ return 0;}

Puntatori e array

In C gli array sono trattati come puntatori

main(){ float x[5]; int j; for (j = 0; j < 5; j++) x[j] = 0;

float *ptr = x; *ptr = 1.5; /* x[0] = 1.5 */ *(ptr+1) = 2.5; /* x[1] = 2.5 */ *(ptr+3) = 3.5; /* x[3] = 3.5 */}

Con riferimento all'esempio seguente, scrivere x+1 significa puntare all’elemento x[1] che contiene 2.5; mentre scrivere x+3 significa indicare il valore 3.5.

x[0] x[1] x[2] x[3] x[4]

1.5 2.5 0.0 3.5 0.0

X+1 x+3

CORSO DI INFORMATICA PER LA FISICA28

Page 29: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

29

Puntatori: allocazione dinamica

L’allocazione dinamica è il modo con cui un programma può ottenere memoria durante l’esecuzione. Lo spazio di memoria delle variabili globali viene assegnato in fase di compilazione e le variabili locali utilizzano invece lo stack. Ma durante l’esecuzione del programma non è più possibile aggiungere variabili locali o globali, anche se molti tipi di programma richiedono la possibilità di allocare memoria run-time. Esistono infatti casi nei quali la memoria di un programma non può essere determinata prima della sua esecuzione: ad esempio un word processor o un database dovranno poter utilizzare tutta la RAM disponibile nel sistema (che varia da computer a computer).

►► Il linguaggio C++ conserva il modo di allocare memoria del C e ne aggiunge un altro proprio più esteso.

La memoria allocata dinamicamente nel C è ottenuta dallo heap, che è la regione di memoria libera tra cui si trova il programma (e la sua area di memoria permanente) e lo stack. Anche se le dimensioni dello heap non sono note si può pensare che esso contenga una grande area disponibile.

La funzione per allocare memoria è malloc()

void *malloc(size_t numero_di_byte);

La funzione restituisce un puntatore di tipo void, size_t è definito nello stdlib.h come un intero unsigned e numero_di_byte è il numero di bytes da allocare alla memoria. Se la memoria non è in grado di soddisfare le richieste di allocazione essa ritorna un puntatore nullo. Esempio:

#include <stdio.h>#include <stdlib.h> /* Definisce malloc() */int main(){ int *ptr=(int *)malloc(sizeof(int)); /* Allocazione di memoria */ *ptr = 12; printf(“%i\n”,*ptr);

free(ptr); /* De-allocazione */ return 0;}

La funzione free() viene usata per liberare memoria allocata e non più utilizzata. Il suo mancato utilizzo porta all'accumulo di locazioni di memoria inutilizzate (memory leak).

NB: Utilizzare puntatori prima del malloc() o dopo il free() causa il crash del programma.

L’esempio seguente mostra l’uso dei puntatori in riferimento a più locazioni di memoria:

#include <stdio.h>#include <stdlib.h> /* Definisce malloc() */int main(){ int *ptr = (int *)malloc(3*sizeof(int)); /* Alloca spazio per 3 interi */ ptr[0] = 10; ptr[1] = 11; ptr[2] = 12;

free(ptr); return 0;}

ptr punta alla locazione di memoria che contiene il numero 10 a cui sono contigue quelle contenenti l’11 e il 12.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 29

Page 30: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

30

Regole di conversione e cast

In C esistono conversioni esplicite ed implicite di tipo.

Le conversioni implicite (e.g. int →float) avvengono nelle espressioni aritmetiche, nel passare i parametri ad una funzione o nel ritornare un valore da una funzione. Il meccanismo di conversione è molto conveniente ma anche potenzialmente pericoloso (errori a run time)

Conversioni implicite• Char e short 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

Le conversioni esplicite, spesso necessarie, sono lasciate all’utente

int *ptr= (int *) malloc(10); /*malloc ritorna un puntatore di tipo void*/

Funzioni

In C le funzioni sono caratterizzate da un nome, dal tipo della variabile ritornata e da una lista di parametri (opzionali)

double max( double a, double b) { return (a>b) ? a : b;}

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. Nell’esempio citato il tipo ritornato dalla funzione è “double”, i parametri della funzione sono a e b, il corpo della funzione sta entro le due parentesi graffe e il valore di ritorno è indicato nell’espressione di return.

double cube(double x) /* Funzione con parametro (passato “by value”) */ { return x*x*x; } void pr_square(int i) /* Funzione che non ritorna alcun valore */ {printf(“%i”,i*i);}

void hello () /* Funzione senza parametri: void hello(void) */ { printf(“Hello”); }

int scanf(const char, …) /* Funzione a numero variabile di argomenti */

Prototipi delle funzioni

Prima di essere usata, una funzione deve essere dichiarata (nel file che la usa)

#include <stdio.h>double max(double, double); /* Prototipo della funzione */int main(){ double m = max(1, 3); printf(“Il massimo e` %i\n“,m); return 0;}

Il prototipo della funzione è normalmente ospitato in max.h.

CORSO DI INFORMATICA PER LA FISICA30

Page 31: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

31

double max(double, double);

mentre la definizione è parte di un file .cc

double max (double a, double b){

return (a>b) ? a : b;}

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.

Call-by-Value

Gli argomenti di una funzione vengono normalmente passati “by value”: cioè ne viene creata una copia locale alla funzione. Per tal motivo una funzione non può modificare gli argomenti passati by value.

#include <stdio.h>int sqr(int x);int main (void){ int t=10; printf(“%d %d \n”, sqr(t),t); return 0;}

int sqr(int x){ x=x*x; return(x);}

Qui il valore dell’argomento di sqr(), 10, viene copiato nel parametro x. Quando viene eseguito l’assegnamento x=x*x solo la variabile locale x viene modificata. La variabile t usata per richiamare sqrt() continuerà a contenere il valore 10. L’output sarà 100 10. Alla funzione viene passata solo una copia del valore dell’argomento. Ciò che avviene all’interno della funzione non ha alcun effetto sulla variabile utilizzata nella chiamata.

L'esempio seguente mostra un tentativo di implementazione di una funzione (swap) che scambia il valore di due variabili

#include <stdio.h>void swap(int a, int b){ int temp; temp=a; a=b; b=temp;}main(){ int i=10,j=20; swap(i,j); /* i e j conservano i loro valori iniziali */} /* Cioè la funzione swap non fa ciò che ci si aspetta */

Cioè la chiamata “by-value” impedisce l'implementazione di una funzione swap. Per far ciò occorre poter passare dei parametri “by-reference”

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 31

Page 32: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

32

Call-by-Reference

L’uso di puntatori permette ad una funzione di modificare il valore dei suoi argomenti. Inoltre, per ragioni di efficienza, oggetti di grandi dimensioni (in termini di memoria) vengono normalmente passati “by reference”. Gli arrays sono sempre passati “by reference” e possono quindi sempre essere modificati.

In C/C++ è possibile una chiamata per indirizzo passando quindi alla funzione un puntatore ad un argomento al posto dell’argomento stesso. Poiché alla funzione viene passato l’indirizzo dell’argomento il codice che si trova all’interno della funzione può modificare il valore dell’argomento che si trova all’esterno della funzione stessa.

La funzione swap(), che scambia i valori delle due variabili intere, può essere così implementata

#include <stdio.h>void swap(int *x,int *y){ int temp; temp=*x; /* salva il valore all’ indirizzo x */ *x=*y; /* copia y in x */ *y=temp; /* copia x in y */}

int main(void){ int i=10, j=20; swap(&i,&j); /* passa gli indirizzi di i e j */ printf(“%d %d \n”,i,j);}

swap scambia i valori delle due variabili puntate da x e da y, perché le vengono passati gli indirizzi delle variabili e non i loro valori. All’interno della funzione è possibile accedere al contenuto delle variabili utilizzando le operazioni sui puntatori. Questo è il motivo per cui è possibile scambiare il contenuto delle variabili utilizzate per chiamare la funzione. Nell’esempio alla variabile i viene assegnato il valore 10 e a j il valore 20. Quindi viene chiamata swap con gli indirizzi di i e j (con l’operatore unario &)., cioè a swap vengono passati gli indirizzi di i e j e non i rispettivi valori. Quindi la stampa sarà “20 10” (nell’esempio precedente relativo alla chiamata “by value” l'esito sarà invece “10 20”).

Funzioni esterne

In C è possibile utilizzare librerie compilate in FORTRAN e quindi chiamare funzioni FORTRAN

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, ……) /* CRASH! Il FORTRAN passa solo “by-reference” */int id=100;hbook1_(id, title, ……) /* OK! */

CORSO DI INFORMATICA PER LA FISICA32

Page 33: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

33

struct

Il linguaggio C offre una (limitata) possibilità di definire nuovi “tipi” (tipi derivati) per mezzo del concetto di struct. Una struttura è un raggruppamento di variabili sotto un unico nome, chiamato tipo di dati aggregato o conglomerato. L’utilizzo di struct consente l’implementazione di strutture dati abbastanza complesse ed uno stile di programmazione più “generico”

persona.hstruct persona { char nome[20]; char cognome[20]; int eta; char professione[20]; struct persona *coniuge; /*uso una struct di tipo persona*/ struct persona *figli[5];};

persona è l’identificatore del tipo; all’interno delle parentesi graffe c’è la struttura del tipo e il tutto si chiude sul “;” finale. Il nome identifica la struttura e diventa quindi lo specificatore di tipo.

main.c#include “persona.h”#include <stdio.h>main() { struct persona john={ {“John”},{“Doe”},40,{“Medico”} }; struct persona mary={ {“Mary”},{“Doe”},37,{“Giornalista”} }; john.coniuge=&mary; mary.coniuge=&john; printf(“La moglie di John e’ %s\n”,john.coniuge->nome);}

In C, data una struttura addr, per dichiarare una variabile di tale tipo occorre utilizzare la seguente sintassi:

struct addr addr_info;

viene dichiarata una variabile di tipo struct addr e chiamata addr_info.

►►Il linguaggio C++ supporta una definizione abbreviata: addr addr_info;

In C il solo nome della struttura non identifica un tipo: il nome di una struttura è un tag.

struct addr{ char name[30]; char street[40]; char city[20]; char state[3]; unsigned long int zip;} addr_info,b_info,c_info;

Qui si definisce un tipo di struttura chiamata addr e si dichiarano le variabili addr_info, b_info,c_info.

►►In C++ il nome della struttura è già un nome di tipo completo e quindi può essere utilizzato per definire variabili, anche se la dichiarazione del C può essere utilizzata anche per un programma C++.

Una volta dichiarata una variabile del tipo della struttura il compilatore alloca automaticamente una quantità di memoria sufficiente per contenere tutti i membri della struttura.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 33

Page 34: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

34

Accesso ai membri delle strutture

Per accedere ai membri si utilizza l’operatore “.” (l’ operatore punto). Ad esempio:

addr_info.zip=12345;

assegna il valore 12345 al campo zip della variabile addr_info. Per accedere ai singoli membri di una struttura si utilizza quindi il nome della variabile (del tipo della struttura) seguito da un punto e dal nome del membro. Per stampare il nome del membro sullo schermo si userà la seguente linea:

printf(“%d”, addr_info.zip);

L’array di caratteri addr_info.name può essere utilizzato nel modo seguente:

gets(addr_info.name);

Qui si passa un puntatore al carattere iniziale di name. Dato che name è un’array di caratteri si può accedere direttamente ai singoli caratteri di addr_info.name indicizzando name.

Passaggio dei membri di una struct a una funzione

La funzione riceve il valore del membro. Esempio data la struttura:

struct fred{ char x; int y; float z; char s [50];} mike;

ecco alcuni esempi di passaggio a una funzione dei membri di una struttura:

func(mike.x); /*passa il valore del carattere di x */func(mike.y); /*passa il valore dell’ intero di y */func(mike.z); /*passa il valore del float di z */func(mike.s); /*passa l’indirizzo della stringa s */func(mike.s[2])); /*passa il valore del carattere s[2] */

Se invece si desidera passare l’indirizzo basta inserire l’operatore & prima del nome della struttura

func(&mike.x); /*passa l’indirizzo del carattere di x */func(&mike.x); /*passa l’indirizzo dell’intero di y */func(&mike.x); /*passa l’indirizzo del float di z */func(mike.x); /*passa l’indirizzo della stringa s */func(&mike.x); /*passa l’indirizzo del carattere s[2] */

Passaggio di una intera struttura ad una funzione

Se una struttura è usata come argomento di una funzione essa viene passata utilizzando il metodo standard della chiamata per valore. Quindi ogni modifica che la funzione apporta al contenuto della struttura non modifica la struttura utilizzata come argomento.

Puntatori a strutture

In C è possibile utilizzare un puntatore ad una struttura come si usa un puntatore normale.

CORSO DI INFORMATICA PER LA FISICA34

Page 35: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

35

Dichiarazione di un puntatore ad una struttura

La dichiarazione di un puntatore ad una struttura è del tipo seguente:

struct addr *addr_pointer;

►► In C++ il nome della struttura è pleonastico, quindi viene normalmente omesso.

Uso dei puntatori a struttura

E’ possibile il passaggio di una struttura ad una funzione tramite una chiamata per indirizzo. Con riferimento all’esempio precedente (main.c), scrivere:

john.coniuge =&mary;

significa inserire nel puntatore john.coniuge l’indirizzo della struttura mary.

L’operatore ->

Per accedere ai membri di una struttura utilizzando un puntatore a tale struttura si usa l’operatore -> (operatore freccia). Esso viene utilizzato al posto dell’operatore punto (.) quando si accede ad un membro di una struttura tramite un puntatore alla struttura stessa. Nell’esempio iniziale:

struct persona john={ {“John”},{“Doe”},40,{“Medico”} };struct persona mary={ {“Mary”},{“Doe”},37,{“Giornalista”} };john.coniuge=&mary;mary.coniuge=&john;printf(“La moglie di John e’ %s\n”,john.coniuge->nome);

In generale i tipi derivati non si comportano come i tipi predefiniti.

struct complesso { double reale; double immaginario; };main() { int i=3,j=4; int k = i+j;

struct complesso x=(3.5,6.) , y=(1.3,4.8); struct complesso r = x*y; double modulo= sqrt(x.reale*x.reale+

x.immaginario*x.immaginario);}

Le caratteristiche “derivate” del tipo “complesso” sono implementate nel programma che lo utilizza. Nell’esempio precedente è da notare che l’aritmetica dei tipi derivati non viene riconosciuta. Le caratteristiche “derivate” del tipo “complesso” devono essere implementate nel programma che lo utilizza.

Nel linguaggio C struct fornisce uno strumento per l’implementazione di strutture dati complesse (liste, alberi, vettori) per la manipolazione e lo stoccaggio dei dati e la possibilità (embrionale) di definire nuovi tipi (tipi derivati). I tipi derivati in C non si comportano come i tipi predefiniti e mancano di funzionalità. In particolare non e’ definita un’algebra dei tipi derivati (operatori). La manipolazione di una struct (accesso ai dati, struttura dei dati) e’ lasciata al programma che la utilizza.

►► Il C++ riparte dal concetto di struct per l’introduzione di una nuova entità, la classe (class), con funzionalità e capacità ben più estese.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA 35

Page 36: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

36

C++ come C “migliorato”

L’evoluzione del linguaggio C è il linguaggio C++: una prova di ciò sta persino nel fatto che il C++ alla sua nascita fu chiamato “C con classi”. Perché un nuovo linguaggio? Essenzialmente per superare i limiti del C nella trattazione di programmi estesi e complessi (~100000 linee). La terza standardizzazione del C++ (fine degli anni 90) lo ha portato alla versione attuale. Ulteriore miglioramento essenziale si è avuto dopo l'introduzione della STL (Standard Template Library, di cui si parlerà più avanti estesamente) che è costituita da una serie di routine generiche per la manipolazione dei dati, che offre soluzioni brillanti ed evolute per la gestione di numerosi problemi.

In generale è stato lo sviluppo del concetto di programmazione ad oggetti (OO da Object Oriented) che ha portato alla nascita del C++. A partire dai linguaggi strutturati (tipici degli anni 70) come il C e il Pascal, la richiesta di programmi sempre più complessi ha portato alla coscienza della incontrollabilità degli stessi al di sopra di una certa soglia di dimensioni. Creare la programmazione a oggetti ha significato capovolgere le tecniche di programmazione precedenti.

Nei linguaggi strutturati (come il C), in programma è definito da collezioni di funzioni che operano sui dati. Invece nella programmazione OO, i programmi sono organizzati attorno a i dati, e sono proprio questi ultimi a controllare l’accesso al codice. In un linguaggio ad oggetti si definiscono i dati e le routine che sono autorizzate ad agire su tali dati: quindi sono i dati a stabilire quali operazioni possono essere eseguite.

I linguaggi che consentono di applicare i principi della programmazione ad oggetti posseggono tre fattori in comune (l’incapsulamento, il polimorfismo e l’ereditarietà) che verranno trattati in dettaglio in seguito. Ma di questo si tratterà più avanti. Per ora, dopo aver introdotto il C come sottoinsieme del C++, passiamo ad un’analisi delle differenze o delle migliorie del linguaggio C++ rispetto al C: le principali risiedono nel modo di eseguire operazioni di I/O, nel modo di inclusione dei file header, etc

Le trasparenze relative al seguente capitolo del corso sono state scritte in powerpoint e si trovano all’ indirizzo riportato nell’introduzione con click da: dal C al C++.

main program

Il più semplice programma in C++ha la seguente struttura:

#include <iostream> // Commento stile C++ using namespace std; /* si puo’ utilizzare anche il commento in stile C*/ int main() // Si può usare al posto di main(void){ int i; cout << ”Stringa di output.\n”; // l'operatore inseritore “<<” manda cout << ”Immettere un numero:\n”;// la stringa sull'output stream cout cin >> i; // “>>” e' l'operatore estrattore cout << i << ” al quadrato = “ << i*i << ”\n”; return 0;}

Come in C, ogni programma per essere eseguibile, deve contenere una funzione main() punto di partenza dell’esecuzione.

Lo header <iostream> è incluso come direttiva al preprocessore per consentire di eseguire operazioni di I/O (come stdio.h in C).

La linea

using namespace std;

Page 37: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

37

indica al compilatore di utilizzare un particolare namespace (una regione di dichiarazione nel programma in cui possono essere inseriti vari elementi). Il namespace std contiene la libreria standard C++. Per accedere agli elementi della libraria standard occorre far precedere al nome il namespace di definizione, es: std::cout. La direttiva using, importa in amespace std nel corpo della funzione main, e quindi l'oggetto cout può essere chiamato senza la necessità di utilizzare l'operatore di scope “::”.

Parametri del programma

E' possibile fornire parametri ad un programma via command line. Il metodo è lo stesso utilizzato in C (dichiarare main con due parametri di tipo int e char** )

#include <iostream>using namespace std;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, cioè il primo parametro è il nome del programma). Il vettore di stringhe argv contiene i parametri, cioè è un puntatore ad un array di puntatori a caratteri. Tutti gli argomenti della riga di comando sono quindi stringhe e i numeri dovranno essere convertiti nel formato interno corretto. Il programma in questione produrrà:

prompt> mytest questo e un testargc e‘ : 5il nome dell’eseguibile e‘/user/xxx/mytestArgomento #1 = questo Argomento #2 = eArgomento #3 = unArgomento #4 = test

Organizzazione dei files

Come in C, le dichiarazioni delle interfacce e le specifiche sono separate dall’implementazione. Sono ospitate negli header files (.h o .hh), che vengono inclusi nei file sorgente utilizzando direttive del precompilatore.

#include <iostream> // NB Il suffisso “.h” non è richisto

Gli header non contengono codice eseguibile (con l’eccezione delle definizioni delle funzioni inline) e non devono essere inclusi più di una volta, per evitare problemi con il linker

#ifndef MyHeader_H#define MyHeader_H// dichiarazioni...#endif

I file sorgente (con estensione .c,.cxx,.cpp,.cc) vengono compilati e contengono l’implementazione di funzioni e metodi, codice eseguibile ed includono gli header files utilizzando le direttive del preprocessore.

Le funzioni dichiarate inline sono implementate dal compilatore nel punto stesso in cui sono chiamate. Normalmente ospitate negli header file o in file separati (con estensione .icc).

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

37

Page 38: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

38

Stringhe

Lo ANSI/C++ introduce un nuovo tipo di stringhe che rimpiazzano le “vecchie” stringhe C (chiamate stringhe di tipo char* o const char*). Le stringhe della libreria standard sono viste come tipi e quindi si possono copiare, assegnare, paragonare senza preoccuparsi della memoria allocata. Le operazioni concesse con le stringhe sono riassunte nella seguente tabella:

=, assignswap+=, append(),push_back()insert()erase()clear()resize()replace()+==,!=,<,<=,>,>=,compare()size(), length()max_size()empty()capacity()reserve()[],at()>>,getline()<<copy()c_str()data()substr()begin(), end()rbegin(), rend()find functions

Assegna un nuovo valoreSwap dei valori tra due stringheAppende caratteriInserisce caratteriCancella caratteriRimuove i caratteri (la svuota)Cambia il # di caratteri (cancella o appende)Sostituisce caratteriConcatena stringheParagona stringheRitorna il numero dei caratteriRitorna il massimo num di caratteriRitorna se la stringa e’ vuotaRitorna il numero max di caratteri allocabiliRitorna “vero” se la stringa è vuotaRitorna il numero di caratteri allocatiRiserva memoria per un certo num. di caratteriAccede ad un carattereLegge il valore da uno streamScrive il valore su uno streamCopia o scrive i valori in una c_stringRitorna il valore come c_stringRitorna il valore come array di caratteriRitorna una certa sotto-stringaProvide normal iterator supportProvide reverse iterator supportCerca per una sottostringa o carattere

Anche se da questa lista sembrerebbe che tutte le operazioni siano possibili con le stringhe, rimangono per esempio impossibili da eseguire le seguenti operazioni:

● espressioni regolari● text processing, ad esempio un paragone tra stringhe del tipo “case insensitive”.

Size e capacity

Per usare correttamente le stringhe occorre conoscerne il comportamento in modo corretto. Le funzioni size() e length() sono equivalenti: ritornano il numero di caratteri di una stringa. Il metodo empty()rappresenta un modo per verificare se il numero di caratteri è = 0 ed è più veloce dei precedenti due metodi. max_size() ritorna il massimo numero di caratteri che una stringa può contenere. reserve() riserva in memoria un numero di caratteri uguale a n:

std::string s; // crea una stringa vuotas.reserve(80); // riserva memoria per 80 caratteri

CORSO DI INFORMATICA PER LA FISICA 38

Page 39: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

39

Accesso agli elementi di una stringa

Una stringa consente di avere accesso read-write agli elementi (caratteri) che la compongono. Il singolo carattere può essere acceduto in due modi diversi:

• tramite l’operatore [ ], che non controlla se l’indice passato come argomento è valido• tramite il metodo at(), che effettua tale verifica. In caso di superamento dei limiti della

stringa, il sistema lancia un eccezione del tipo out_of_range (la gestione delle eccezioni non viene trattata in questa dispensa

Entrambi ritornano il carattere alla posizione indicata dall’indice passato. Il primo carattere ha indice 0, mentre l’ultimo ha indice length()-1 . Nell’esempio seguente si può controllare l’esito dell’uso dei due diversi approcci:

const std::string cs(“nico”); // cs contiene ‘n’ ‘i’ ‘c’ ‘o’ std::string s(“abcde”); // s contiene ‘a’ ‘b’ ‘c’ ‘d’ ’e’ s[2] //vale ‘c’s.at(2) //vale ‘c’s[100] //ERRORE può portare a un crashs.at(100) //ERRORE, lanciata un eccezione out_of_ranges[s.length()] //ERRORE può portare a un crashcs[cs.length()-1] //indica ‘\0’s.at(s.length()) //ERRORE, lanciata un eccezione out_of_rangechar &r=s[2]; //referenza al terzo caratterechar *p=s[3]; //puntatore al quartor= ‘X’; // s contiene ‘a’ ‘b’ ‘X’ ‘d’ ‘e’

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.

In C per utilizzare le funzioni I/O si include il file stdio.h

#include <stdio.h>

In C++ si include invece iostream

#include <iostream> // NB: direttiva al preprocessoreint main(){ std::cout << “Hello, world !” << std::endl; // end-of-line return 0;}

E' possibile utilizzare di seguito più operazioni di output “<<”; endl fa parte del namespace std.

La seguente linea produce sullo schermo i caratteri A B e C separati da spazi di tabulazione.

std::cout << ”A\tB\tC”;

La riga seguente scrive Hello World! sullo schermo e termina la linea corrente.

std::cout << “Hello World!” << std::endl;

L’operatore “<<” ha due operandi. Ogni operando ha un tipo. Un tipo denota una struttura dati e i significati delle operazioni che hanno senso su di essi. L’operando di sinistra è del tipo std::ostream. Invece std::endl è un manipolatore, in questo caso l’azione è quella di terminare la linea corrente di output.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

39

Page 40: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

40

Manipolatori

Per cambiare i parametri di formattazione di uno stream si usano particolari funzioni, alcune delle quali sono riassunte nella tabella seguente:

manipolatore scopo input/output

boolalpha //attiva il flag boolalpha input/outputdec //attiva il modo decimale input/output endl //output del carattere di fine riga outputends //output di un carattere nullo outputfixed //attiva il flag fixed outputflush //svuotamento di uno stream outputhex //attiva il modo esadecimale input/outputleft //allineamento a sinistra outputsetw //imposta l’ampiezza di campo outputsetfill(int ch) //setta il carattere di riempimento output

Per accedere ai manipolatori che fanno uso di parametri (come setw) si deve includere nel programma lo header <iomanip>. Esempio:

#include <iostream>#include <iomanip>int main(){ std::cout << std::hex << 162 << std::endl; std::cout << std::setfill(‘?’) << std::setw(10) << 2343.0 << std::endl; return 0;}

produce il seguente output:

a2??????2343

Il vantaggio nell’uso dei manipolatori risiede nel fatto che spesso il codice si fa più compatto. Il manipolatore setioflags() consente di impostare direttamente i vari flag di formattazione relativi ad uno stream.

Uno dei più interessanti manipolatori è boolalpha che consente di introdurre i valori logici come true e false invece che come valori numerici, come nel caso in cui non è settato (cioè il default) . Il valore 0 è quindi sempre usato per false e il valore 1 per true. Il manipolatore boolalpha forza la rappresentazione testuale (setta il flag ios::boolalpha, il manipolatore noboolalpha forza la rappresentazione numerica (elimina il flag ios::boolalpha)

fstream

Per leggere/scrivere da/su file si utilizzano le fstream. Utilizzate senza parametri, le funzioni fstream(), ifstream(), ofstream() creano uno stream senza associarlo ad alcun file. L'associazione può essere fatto in un secondo momento attraverso il metodo open(). Passando invece il nome del file come parametro, si crea lo stream e lo si associa direttamente al file.

CORSO DI INFORMATICA PER LA FISICA 40

Page 41: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

41

#include <fstream>#include <string>#include <iostream>int main(){ // Lettura di due stringhe dal file persone.txt std::ifstream infile; infile.open(“persone.txt”); if ( !infile ) { std::cerr << “ errore nell’aprire il file!” << std::endl; return -1; } std::string nome, cognome; int eta; infile >> nome >> cognome >> eta; // Scrittura delle due stringhe su un secondo file std::ofstream outfile(“persone.out”) ; outfile << eta << “ – “ << nome << “ – “ << cognome << std::endl, outfile.close(); return 0; }

Se il file di input è persone.txt, del tipo seguente:

John Smith 34Joe Doe 28

Il file di output sarà (persone.out):

34 – John - Smith

stringstream

Per leggere/scrivere da/in una stringa si usano le stringstream. L’uso più interessante riguarda il fatto di poter formattare del testo di output in una stringa per poi mandarlo ad un canale di output anche con ritardo. Un altro uso interessante è quello legato alla possibilità di leggere riga per riga e poi processare ogni linea usando stringstreams.

• Per leggere da stringhe si usa istringstream

• Per leggere da o per scrivere su stringhe si usa ostringstream

• Per leggere/scrivere una stringa si usa stringstream

• Per leggere/scrivere caratteri di una stringa si usa stringbuf

Una specializzazione di questa parte sarà ritrattata nella parte dedicata alla Standard Template Library. Un esempio ne illustra l’uso:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

41

Page 42: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

42

#include <sstream>#include <string>#include <iostream>using namespace std;int main(){ stringstream s(“Questa è la stringa iniziale”); string str =s.str(); // da stringstream a stringa std::cout<< str << std::endl; // stampa della stringa s << “Numeri: “ << 10 << “ “ << 123.2; // output su stringstream int i; double d; s >> str >> i >> d; // ri-lettura da stringstream std::cout << str << “ “ << i << “ “ << d << std::endl; return 0; }

L’output di questo programma è:

Questa è la stringa inizialeNumeri: 10 123.2

commenti

Esistono due tipi di commento in C++, inline e multiline.

const int Ntries; // questo e` un commento inline// il resto della linea e’ trattato come un commentoconst 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).

const

La keyword const viene utilizzata per dichiarare un oggetto costante. Alcuni esempi:

const int N=100; // N non puo` essere cambiatodouble w[N]; // N usato come per dimensionare un vettoreconst int vect[3]= {10,20,30}; // 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. In generale è da evitare.

Riferimenti

Il C++ fornisce un nuovo sistema (oltre al puntatore) per accedere all’indirizzo di una variabile, il riferimento (reference)

CORSO DI INFORMATICA PER LA FISICA 42

Page 43: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

43

int i=10,j=3; int& a = i; // a è inizializzato all’indirizzo di i // a e’ un indirizzo, int& e’ l’indirizzo di un intero // a può essere utilizzato in luogo di istd::cout << “ i = “ << a << std::endl; a=j; // errore! a non è una variabile!

I riferimenti vengono utilizzati come alias alla variabile a cui sono associati. Al momento della dichiarazione, un riferimento deve essere associato alla variabile a cui “riferirà”. Al contrario dei puntatori, i riferimenti non possono essere riassegnati ad altre variabili. a e’ un indirizzo che può essere utilizzato esattamente come si utilizzerebbe una variabile.

Lo scopo della referenza è proprio quello di riunire le caratteristiche dei puntatori (che, essendo indirizzi, sono parole a 32 bit che danno accesso in maniera complicata all’informazione contenuta in un oggetto) con quelle degli oggetti stessi che hanno accesso immediato alle loro caratteristiche, ma che sono in generale troppo grossi per venire passati, per esempio, come argomenti di una funzione.

vector<double> homework;vector<double>& hw = homework; //hw è un sinonimo per homework

Dire che un nome e’ a referenza ad un oggetto significa che il nome è un altro nome per lo stesso oggetto.

Riferimenti e Puntatori

Il puntatore porta sempre l’indicazione del tipo di informazione a cui punta. Il compilatore quindi conosce il tipo di informazione puntata e ne controlla le modalità di impiego. Esiste anche il puntatore void (senza tipo) ma prima di utilizzarlo occorre definirne il tipo attraverso una operazione di casting.

se p e’ una variabile di tipo puntatorep=&x assegna come valore al puntatore p l’indirizzo della variabile x*p denota la variabile puntata da p, cioè il contenuto di x

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; // lo scope di n è la funzione for (int i=0;i<100;i++) // lo scope di i è il corpo di for { double r; // lo scope di i è il corpo di for ... } cout << “n “ << n << endl; // OK cout << “i “ << i << endl; // errore! cout << “r “ << r << endl; // errore! …}

Attenzione! La stessa variabile può essere ri-dichiarata (con visibilità diversa). Questo è da evitare (se possibile) per non rendere il programma oscuro e a rischio di errore.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

43

Page 44: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

44

int i=7; // file (global) scopeint func(){ int i=50; // 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` da evitare ... } std::cout << “i “ << i << “ “ << ::i << std::endl;

... // ::i accede alla “i” con global scope}

namespace

Un namespace è una regione di dichiarazioni per un programma. Lo scopo di un namespace è quello di localizzare i nomi degli identificatori per evitare conflitti: evitare che funzioni diverse (definite in librerie diverse) con lo stesso nome possano interferire (name clash). Gli elementi dichiarati in un namespace sono distinti da quelli dichiarati in un altro namespace. Le funzioni e le variabili dichiarate al di fuori di ogni namespace appartengono al global scope e sono visibili in qualsiasi punto del programma.

namespace mynames{ int i; // la mia dichiarazione di i float max(float, float); // 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}

Per utilizzare variabili e funzioni appartenenti ad un namespace si una l'operatore di scope “::” o la direttiva “using” che importa nello scope corrente elementi definiti in altri namespace:

float r = mynames::max (2.1f, 5.3f);

using namespace mynames; // Importa tutti gli elementi definiti in mynamesfloat r = max (2.1f, 5.3f);

using mynames::max; // Importa solo la funzione maxfloat r = max (2.1f, 5.3f);

new e delete

Gli operatori new and delete vengono utilizzati per allocazione/deallocazione dinamica della memoria.

int *i=new int; // alloca un intero, returna il puntatorechar *c=new char[100]; // alloca un array (stringa) di 100 caratteriint *i=new int(99); // alloca un intero e lo inizializza a 99char *c=new char(‘c’); // alloca un carattere inizializzato a cint *j=new int[n][4]; // alloca un array di puntatori ad intero

CORSO DI INFORMATICA PER LA FISICA 44

Page 45: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

45

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. L'operatore new riserva la quantità necessaria di memoria richiesta e ritorna l’indirizzo di quest’area. L’operatore delete è usato per restituire l'area di memoria precedentemente allocata tramite new. Al fine di evitare dannosi sprechi di memoria (memory leak) ogni oggetto allocato con new e non più utilizzato deve essere distrutto con delete. L’argomento di delete è tipicamente un puntatore inizializzato precedentemente con new:

delete ptr; distrugge un puntatore ad un oggettodelete p[i]; distrugge l’oggetto p[i]delete [] p; distrugge ogni oggetto di tipo p

La dimensione dello heap non è infinita e quindi l’allocazione può fallire; nel qual caso new restituisce un puntatore nullo o manda un’eccezione. Nel caso di allocazione di una quantità significativa di memoria, occorre 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.

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). Valgono le seguenti regole di conversione:

• 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

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:

static_cast <T*> (p);

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 può essere inizializzato a 0 senza bisogno di un cast esplicito. In C++ occorre usare 0 e non NULL per i puntatori.

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.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

45

Page 46: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

46

x=(float) i; // cast in C++ - notazione Cx=float(i); // cast in C++, notazione funzionalex=static_cast<float>(i); // ANSI C++ - raccomandatoi=reinterpret_cast<int>(&x) // ANSI C++, pericolosofunc(const_cast<int>(c_var)) // dove c_var e` dichiarata const // Usato quando e' necessario eliminare l'attributo const // Eg: per chiamare che accetta valori non const

Esiste anche un dynamic_cast, utilizzato per riconoscere il tipo di un oggetto a run-time (RTTI).

Funzioni

La forma generale di una funzione è la seguente:

tipo_restituito nome_funzione (elenco parametri)

Il tipo_restituito specifica il tipo di dati restituito dalla funzione. Una funzione può restituire un qualsiasi tipo di dati tranne un array. L’elenco_parametri è un elenco di nomi di variabili (preceduti dai rispettivi tipi), separati da virgole, che ricevono i valori degli argomenti quando la funzione viene chiamata. Una funzione può anche non aver parametri, in questo caso il campo dei parametri rimane (anche se vuoto) e le parentesi sono necessarie. Nella dichiarazione delle variabili si può dichiarare più variabili dello stesso tipo utilizzando un elenco di nomi di variabili separati da virgole, ma nella dichiarazione dei parametri di una funzione occorre dichiarare esplicitamente il tipo di ogni parametro insieme al nome.

Funzioni inline

La keyword inline suggerisce al compilatore che ogni chiamata alla funzione deve essere convertita in codice eseguibile nel punto stesso della chiamata. Le funzioni inline vengono usate per ragioni di efficienza e devono essere semplici. Il compilatore può decidere autonomamente (per esempio se la funzione è troppo lunga) di ignorare la direttiva inline.

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:

int pow (int a, int k=2){ if (k==2) return a*a; else return a*pow(a, k-1);}

// main.ccint pow(int , int);int main(){ int r=3; int a1=pow(3,3); // a1=27 int a2=pow(3); // a2=9 return 0;}

Solo ai parametri più a destra nella sequenza di chiamata può essere dato un default. Nell’esempio precedente l’argomento di default è int k=2;

CORSO DI INFORMATICA PER LA FISICA 46

Page 47: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

47

Call by reference

L’uso di riferimenti permette ad una funzione di modificare il valore dei suoi argomenti senza usare dei puntatori

void swap(int& a, int& b){ int temp; temp=a; a=b; b=temp;}

int main() { int i=10,j=20; swap(i,j); // la funzione lavora sugli indirizzi di i e j return 0;}

I riferimenti sono normalmente utilizzati per passare l’indirizzo di una variabile ad una funzione. Se la funzione non deve potere modificare un argomento passato per riferimento, si deve dichiarare l’argomento stesso const.

Overloading

Funzioni diverse possono avere lo stesso nome. La funzione che viene chiamata è scelta dal compilatore in base al numero e tipo degli argomenti (non in base al tipo ritornato).

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;}

Function signature

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 conversioneprint(15,9); // errore! Ambiguità fra (2) e (3)print(15,9.); // OK, chiama (2)print(); // OK, chiama (1) con il default

C++ vs. C: le differenze

Lo standard C++ è una estensione dello standard C, quindi ogni programma C è anche un programma C++. Esistono però delle differenze tra i due linguaggi. Le più importanti sono le seguenti:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

47

Page 48: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

48

• In C++ le variabili locali possono essere dichiarate in qualsiasi punto di un blocco. In C devono essere dichiarate all’inizio di un blocco prima di ogni dichiarazione “attiva”.

• In C una funzione dichiarata int f(); non dice nulla sui parametri della funzione. Se in C non viene specificato nulla significa che non viene stabilito nulla rispetto ai parametri della funzione. In C++ una dichiarazione simile significa che la funzione non ha parametri, quindi in C++ scrivere int f(); o int f(void); è la stessa cosa

• In C++ tutte le funzioni devono avere un prototipo, diversamente dal C in cui ciò è opzionale

• In C una costante carattere viene automaticamente trasformata in un intero. In C++ no.

• In C non è un errore dichiarare più volte una variabile globale, in C++ si.

• In ANSI C un identificatore può avere al massimo 31 caratteri significativi, in C++ questa restrizione non esiste

• In C quando viene richiesto uno specificatore di tipo nelle estensioni di dichiarazione viene utilizzato per default il tipo int, in C++ no.

CORSO DI INFORMATICA PER LA FISICA 48

Page 49: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

49

Classi

Il concetto di classe in C++ è l’ estensione di quello di struct in C ed è l’elemento centrale della programmazione ad oggetti. In generale si può dire che:

• Un programma è una rappresentazione (più o meno fedele) di una situazione reale

• Una situazione reale non è fatta di int e di char ma di oggetti (tracce, finestre grafiche, satelliti, volumi) che interagiscono fra di loro a seconda delle loro caratteristiche e peculiarità.

• Per riprodurre una situazione reale, un buon linguaggio di programmazione deve permettere la descrizione di qualsiasi oggetto (tipi derivati), delle sue caratteristiche (rappresentazione interna) e delle sue interazioni con qualsiasi altro oggetto coinvolto nella simulazione (interfaccia verso l’esterno).

Le trasparenze del corso relative all’argomento di questo capitolo (in formato powerpoint) si trovano all’indirizzo della pagina web indicata nell’introduzione e sono disponibili tramite click su: classi.

Linguaggio C e struct

Nel C, tipi derivati e oggetti sono implementati per mezzo di strutture: struct. Viene effettuata una rappresentazione interna poi esportata pubblicamente al programma utente, che deve implementare una rappresentazione alternativa se necessario.

Ad esempio il tipo complesso esporta una rappresentazione cartesiana (reale-immaginario); se è richiesta una rappresentazione polare (rho-phi), questa deve essere implementata dal programma utente. L'unica interfaccia verso l’esterno è la rappresentazione interna.

Inoltre anche la moltiplicazione di due numeri complessi (che vorremmo fosse parte dell'interfaccia) non è fornita dall'interfaccia, ma è lasciata al programma utente.

Supponiamo di voler implementare il tipo complesso.

Problema: il tipo complesso

Vogliamo generalizzare la definizione di complesso data in C in maniera che:

• qualsiasi rappresentazione (cartesiana, polare) sia disponibile all’utente, indipendentemente da quale effettivamente sia la rappresentazione interna

• il tipo complesso si comporti come qualsiasi altro tipo predefinito (inizializzazione, definizione delle operazioni algebriche, interazione con altri tipi)

• funzionalità addizionali (ad esempio il modulo) possano essere associate al tipo e non al programma utente

In C++ una struct può contenere, oltre che variabili (data members), anche funzioni (metodi) che normalmente operano sui data members ed estendono la funzionalità del tipo.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

49

Page 50: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

50

//complesso.hstruct complesso { double reale; double immaginario; double Modulo() { return reale*reale+immaginario*immaginario; }};

L’accesso ai metodi avviene con la stessa modalità usata per l’accesso ai data members. Modulo() diventa così una caratteristica del tipo complesso e ne estende la definizione.

//main.cc#include “complesso.h”#include <iostream>int main() { complesso a; a.reale=3.2; // inizializzazione parte reale a.immaginario=5.6; // inizializzazione parte imm. std::cout<<“Modulo di a “<< a.Modulo() <<std::endl;}

La definizione di Modulo appartiene ora al tipo complesso e non più a main() (ne a nessun altro codice utente). La funzione Modulo() appartiene al tipo complesso e non può esserne separata. Per sottolineare questo possesso, il compilatore associa il nome del metodo al tipo per mezzo dell’operatore di scope ( :: )

double complesso::Modulo()

La definizione di Modulo()avviene in un qualsiasi file source (prassi normale).

//complesso.hstruct complesso { double reale; double immaginario; double Modulo();};

//complesso.cc#include “complesso.h”double complesso::Modulo() { return reale*reale+ immaginario*immaginario;}

Metodi

L’uso di metodi permette di accedere alla rappresentazione interna di un oggetto e di implementarne rappresentazioni alternative

struct complesso { double reale; double immaginario; double Modulo(); double Reale() {return reale;} // accesso parte reale double Immaginario() {return immaginario;} // accesso parte immaginaria // Rappresentazione polare double Rho() {return Modulo();} // accesso al modulo double Phi() {return atan(immaginario/reale);} // accesso all'angolo};

CORSO DI INFORMATICA PER LA FISICA 50

Page 51: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

51

Metodi const

Metodi che non modificano lo stato (il valore dei data members) di un oggetto dovrebbero essere definiti const (non obbligatorio ma consigliabile). L’uso di qualificatori come const ha una duplice valenza:

• documentazione: l’uso di un metodo dichiarato const non modificherà l’oggetto su cui il metodo stesso opera (interfaccia “read-only” )

• evoluzione del codice: per “contratto” modifiche al codice dovranno rispettare il carattere read-only dell’interfaccia (a meno di modificare l’interfaccia stessa).

Modificatori

La tecnica dell’overloading permette di avere funzioni con lo stesso nome, ma diverso comportamento sullo stato dell’oggetto su cui operano: cioè è possibile unificare le interfacce Read-only e Read/Write:

//complesso.hstruct complesso { double reale; double immaginario; double Modulo();

// accesso (Read-only) double Reale() const {return reale;} double Immaginario() const {return immaginario;} double Rho() const {return Modulo;} double Phi() const {return atan(immaginario/reale);}

// modifiche (accesso Read-Write) void Reale(double r) {reale=r;} void Immaginario(double r) {immaginario=r;} void Rho(double r); void Phi(double r);};

//complesso.cc#include “complesso.h”

double complesso::Modulo() // Non modifica la rappresentazione interna{ return reale*reale+immaginario*immaginario; }

void complesso::Rho(double r) // Modifica la rappresentazione interna { reale=r*cos( Phi() ); immaginario=r*sin( Phi() );}

L’uso di accessori e modificatori permette di operare direttamente sulla rappresentazione interna di un oggetto. Il tipo “complesso” si comporta ora come se sia la rappresentazione cartesiana che quella polare fossero state implementate. La rappresentazione interna (cartesiana) é tuttavia ancora accessibile direttamente: se volessimo cambiare la rappresentazione interna (a polare per esempio) qualsiasi codice che acceda direttamente alla rappresentazione cartesiana non funzionerebbe più.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

51

Page 52: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

52

#include “complesso.h”#include <iostream>int main() { complesso a; a.Reale(3.2); // inizializzazione parte reale a.Immaginario(5.6); // inizializzazione parte imm. complesso b; b.Rho(6.); // inizializzazione modulo b.Phi(1.23); // inizializzazione angolo using namespace std; cout << “Phi di a “ << a.Phi() << endl; cout << “Reale di b “ << b.Reale() << endl; cout << “Reale di b “ << b.reale << endl;}

Classi

La classe (class) in C++ è una generalizzazione del concetto di struct, a cui aggiunge la possibilità di controllo dell’accesso alla struttura interna del tipo.

class identificatore {public:

// parte “pubblica” dell’interfaccia. Qualsiasi // altro pezzo di codice puo’ accedere liberamente // ai data members ed ai metodi dichiarati in questa// sezione

private:// soltanto i metodi che appartengono alla classe// stessa (indipendentemente se pubblici o privati)// possono accedere a questa sezione

};

Una struct è una classe i cui dati e metodi sono pubblici. In generale una classe NON è una struct. La rappresentazione interna diventa “privata”, la rappresentazione “visibile” è ora soltanto quella fornita dall’interfaccia “pubblica”. Riferendosi all'esempio precedente, il codice utente non ha più modo di sapere se la rappresentazione interna sia cartesiana o polare. La rappresentazione interna può ora essere modificata o cambiata completamente senza che il codice utente debba essere toccato.

complesso.hclass complesso {private:

double reale;double immaginario;

public:double Modulo();// accesso (Read-only)double Reale() const {return reale;}double Immaginario() const {return immaginario;}double Rho() const {return Modulo;}double Phi() const {return atan(immaginario/reale);}// modifiche (accesso Read-Write)void Reale(double r) {reale=r;}void Immaginario(double r) {immaginario=r;}void Rho(double r);void Phi(double r);

};

CORSO DI INFORMATICA PER LA FISICA 52

Page 53: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

53

//main.cc#include “complesso.h”#include <iostream>int main() { complesso a; a.Reale(3.2); // inizializzazione parte reale a.Immaginario(5.6); // inizializzazione parte imm. complesso b; b.Rho(6.); // inizializzazione modulo b.Phi(1.23); // inizializzazione angolo std::cout << “Phi di a “ << a.Phi() << std::endl; std::cout << “Reale di b “ << b.Reale() << std::endl;// la linea seguente e’ ora ILLEGALE! std::cout << “Reale di b “ << b.reale << std::endl;}

struct e class: riepilogo

In C++ il concetto di struct viene generalizzato, da semplice raggruppamento di variabili utile per costruire una struttura dati a strumento per definire nuovi tipi. La possibilità di aggiungere ad una struct metodi che operano sulla rappresentazione interna permette di dotare la struct stessa di un comportamento proprio e di ampliarne la funzionalità.

La classe è un’ulteriore generalizzazione della struct. L’aggiunta di un sistema di controllo dell’accesso ai dati in una classe consente di nasconderne l’implementazione: il codice utente dipende così soltanto dall’interfaccia pubblica della classe che ne specifica la funzionalità.

L’ esempio: il tipo complesso

La definizione di una classe “complesso” permette l’introduzione di un tipo derivato in un linguaggio di programmazione che non lo supporta a priori. La rappresentazione interna del tipo è nascosta al codice utente. L’interfaccia “pubblica” specifica il comportamento del tipo (per esempio la possibilità di accedere alla sua parte “reale”).

Vogliamo ora risolvere il problema dell’inizializzazione di un oggetto (quali valori vengono assegnati alla rappresentazione interna quando un oggetto viene creato) ed aggiungere un’algebra al nostro tipo “complesso”.

//main.cc#include “complesso.h”#include <iostream>int main() {

complesso a;a.Reale(3.2); // inizializzazione parte realea.Immaginario(5.6); // inizializzazione parte immaginariacomplesso b;b.Reale(6.); // inizializzazione parte b.Immaginario(1.23); // inizializzazione angolocomplesso c=a+b; // Impossibile “+” non definito su complessicomplesso d=c*a; // Impossibile “*” non definito su complessi

}

In questo codice la parte di inizializzazione funziona (anche se risulta poco maneggevole), mentre le operazioni algebriche non sono definite perché il compilatore non conosce nulla dell’algebra complessa. Ciò che si vorrebbe è quindi un codice che si presenta così:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

53

Page 54: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

54

//main.cc#include “complesso.h”#include <iostream>int main() { complesso a(3,2); // inizializzazione diretta complesso b(6.,1.23); // inizializzazione diretta complesso c=a+b; complesso d=c*a;}

Costruttori e distruttori

Un costruttore è un metodo il cui nome è quello della classe a cui appartiene. Un costruttore non ritorna un tipo. Lo scopo di un costruttore è quello di costruire e inizializzare oggetti del tipo della classe. Questo implica l’inizializzazione degli attributi e, se necessario, allocazione di memoria dallo heap.

La lista degli argomenti assegnati ad un costruttore è liberamente scelta da chi implementa la classe. Una classe può avere più di un costruttore (overloading).

Alcuni costruttori sono necessari perché il compilatore possa fare il suo lavoro: se non vengono definiti il compilatore li genererà automaticamente.

L’ esempio: il tipo complesso

class complesso {private:

double reale;double immaginario;

public: complesso(); //default constructor complesso(double r); //costr. con inizializz. parte reale complesso(double r, double i); //costr. con inizializzione double Modulo();

// accesso (Read-only) double Reale() const {return reale;} double Immaginario() const {return immaginario;} double Rho() const {return Modulo;} double Phi() const {return atan(immaginario/reale);}

// modifiche (accesso Read-Write) void Reale(double r) {reale=r;} void Immaginario(double r) {immaginario=r;} void Rho(double r); void Phi(double r);};

Nel codice precedente appare il costruttore di default

complesso();

il costruttore in cui è inizializzata la sola parte reale

complesso(double r);

e quello in cui sono inizializzate entrambe:

complesso(double r, double i);

CORSO DI INFORMATICA PER LA FISICA 54

Page 55: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

55

#include “complesso.h”complesso::complesso() // default. Non ha tipo{ reale = 1; // mettiamo per default, l’unità immaginario = 0;}

complesso::complesso(double r) // non ha tipo{ reale=r; // inizializza solo parte reale immaginario=0;}

complesso::complesso(double r,double i) //non ha tipo{ reale=r; immaginario=i;}

• I costruttori ubbidiscono alle stesse regole di overloading dei metodi normali

• Il costruttore “appropriato” viene invocato ogni volta che un oggetto viene creato

#include “complesso.h”#include <iostream>int main() { complesso a; // default, a è 1 complesso b(6.,1.23); // costruttore a due parametri complesso c(3); // costruttore a un parametro complesso d(“hello!”); // errore di compilazione!!}

Quando uno degli attributi è esso stesso una classe, il costruttore appropriato viene scelto sulla base dei parametri forniti nell’inizializzazione.

Inizializzazione

Una sintassi alternativa permette di attribuire valori ai membri di una classe per mezzo di una lista di inizializzatori, che precede il corpo della funzione

//complesso.cc#include “complesso.h”complesso::complesso() : reale(1), immaginario(0){ // vuoto}complesso::complesso(double r): reale(r),immaginario(0) {}complesso::complesso(double r,double i): reale(r),immaginario(i){}

E` obbligatorio inizializzare così gli attributi (non statici) che siano o riferimenti o const.

Costruttore di default

Un costruttore senza una lista di argomenti viene chiamato costruttore di default.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

55

Page 56: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

56

//complesso.cc#include “complesso.h”complesso::complesso() : reale(1), immaginario(0){ // vuoto}

La funzionalità del compilatore dipende in modo cruciale dall’esistenza di un costruttore di default per ogni classe definita, per cui, in assenza di un costruttore di default, il compilatore ne genererà uno automaticamente (il più banale). Se si desidera avere un costruttore di default non banale, questo deve essere esplicitamente dichiarato e definito (nel caso di “complesso”, il costruttore di default generato inizializzerebbe reale ed immaginario a 0 ).

Costruttore di copia

La forma più generale di un costruttore di copia è la seguente:

classname (const nome-classe& O) {//corpo del costruttore}

O è un riferimento all’oggetto che si trova sul lato destro dell’inizializzazione. Un costruttore di copia (copy constructor) permette di copiare oggetti in oggetti. Un costruttore di copia viene utilizzato ogni qualvolta che si passi un oggetto “by value” ad una funzione o un metodo (una copia locale dell’oggetto viene creata) nonché in diversi altri casi.

Un costruttore di copia per classe è necessario al compilatore che ne genererà uno (il più banale) nel caso che esso non sia stato esplicitamente dichiarato.

La copia di oggetti in oggetti rappresenta un problema complesso nel caso di allocazione dinamica di memoria (“deep copy”, “shallow copy”) ed è quindi buona regola esplicitare sempre un costruttore di copia (a meno di casi assolutamente banali).

//complesso.h...complesso(const complesso& c);...

//complesso.cc#include “complesso.h”complesso::complesso(const complesso& c):

reale(c.reale), immaginario(c.immaginario){}

//main.cc#include “complesso.h”#include <iostream>void main() { complesso a; // default, a è 1 complesso b(6.,1.23) ; // costruttore a due parametri complesso c(b) ; // costruttore di copia!}

Se invece:

myclass x=y;

CORSO DI INFORMATICA PER LA FISICA 56

Page 57: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

57

L’operazione sarebbe stata quella di eseguire una copia bit a bit; x sarebbe stato una copia esatta di y, cioè y avrebbe usato la stessa memoria eventualmente allocata per x, non una propria area distinta. Se ad esempio myclass avesse contenuto un distruttore che libera memoria la distruzione di x e y sarebbe risultata in una doppia cancellazione di memoria.

Questo richiamo ricorda che in C++ ci sono due situazioni per cui a un oggetto viene assegnato il valore di un altro oggetto:

• L’assegnamento

• L’inizializzazione che si può verificare in tre modi diversi:

Quando un oggetto inizializza esplicitamente un altro oggetto, come nelle dichiarazioni

Quando viene eseguita una copia di un oggetto che deve essere passato ad una funzione

Quando viene creato un oggetto temporaneo (normalmente come valore restituito da una funzione)

Il costruttore di copie viene usato solo nelle inizializzazioni.

L’ inizializzazione viene utilizzata da ciascuna delle seguenti istruzioni:

myclass x=y; // y inizializza esplicitamente xfunc(y) ; // y passata come parametroy=funx(); // y riceve da func() un oggetto temporaneo

Costruttori ad un parametro

Un costruttore ad un solo parametro viene considerato dal compilatore come regola di conversione implicita. Un costruttore di questo tipo è utilizzato infatti per convertire il parametro (o il suo tipo) il un oggetto. Questo può portare ad errori o effetti indesiderati nel caso di espressioni complicate. Nel caso NON si desideri che un costruttore funga da operazione di conversione, lo si deve dichiarare explicit.

complesso.hclass complesso {...public:

explicit complesso(double r);...};

Distruttore

Così come è possibile intervenire sul modo in cui un oggetto viene creato (tramite la definizione di uno o più costruttori), è anche possibile agire su un oggetto appena prima che questo venga eliminato (sia perché si è invocato esplicitamente delete sia perché esso è giunto alla fine della sua vita naturale). Un distruttore è un metodo che porta lo stesso nome della classe a cui è associato preceduto da una ~.

//complesso.hclass complesso {...public:

~complesso(); // distruttore...};

• Il distruttore viene automaticamente invocato ogni qualvolta che un oggetto sta per venire distrutto. Se non è esplicitato, il compilatore ne genererà uno automaticamente.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

57

Page 58: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

58

• Il distruttore non ha tipo.

• Il distruttore NON ubbidisce alle normali regole di overloading.

• Esiste soltanto un distruttore per classe.

• Il distruttore NON accetta argomenti: la lista dei parametri deve rimanere vuota.

L’ esempio: il tipo complesso

//complesso.cc#include “complesso.h”complesso::~complesso(){ std::cout << “un altro complesso se ne va!” << std::endl;}

main.cc#include “complesso.h”#include <iostream>int main() { complesso a; complesso b= new complesso(6.,1.23) ; std::cout << “ b viene distrutto qui!” << std::endl; delete b; // distruttore di b invocato for (int i=0; i<10; i++) { complesso c(3.); std::cout << “ c è creato e distrutto “ << std::endl; } //!! distruttore di c invocato (10 volte) std::cout << “ fine del programma, a viene distrutto” << std::endl;}

Per molte classi il distruttore è triviale e può essere tralasciato. Il compilatore genererà automaticamente un distruttore altrettanto triviale. Se la classe ha invece una funzionalità complessa (per es. allocazione dinamica di memoria), il distruttore ha il compito cruciale di riportare la situazione allo stato originale quando un oggetto viene distrutto (per es. invocando delete per restituire memoria allo heap ) .

Un distruttore è caratterizzato dalla ~ e dal fatto di non avere argomenti e dal fatto di non ritornare un tipo. Qualsiasi altra combinazione verrà interpretata come “normale” metodo di una classe (e mai utilizzata).

Dal punto di vista del computer, un programma è un insieme di operazioni predefinite su certe aree di memoria. Il compilatore prestabilisce come le aree di memoria corrispondenti ai tipi predefiniti debbano essere configurate e come interagiscano. Costruttori e distruttori sono operazioni che un programmatore può definire per stabilire la configurazione dei tipi derivati. Resta ancora da stabilire come questi tipi interagiscano fra di loro. Per questo, il C++ permette di ridefinire tutte le principali operazioni fra tipi derivati.

Operatori

In C++, la somma fra due interi è predefinita (operazioni binarie su due aree di memoria).

int a=3,b=4;int c=a+b;

Una semplice addizione può essere vista come un operatore (una funzione) che, prendendo come argomenti due interi (a e b) restituisce un intero (che viene poi associato a c).

CORSO DI INFORMATICA PER LA FISICA 58

Page 59: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

59

int a=3,b=4;int c=operator+(a,b);

Oppure come metodo della classe intero che, preso un argomento intero, lo associa all’oggetto su cui opera per restituire un intero.

int a=3,b=4;int c=a.operator+(b);

Qualsiasi operatore che sia definito per i tipi fondamentali (+ - * /, operatori di assegnazione, operatori di shift a sinistra e a destra etc.) può essere ridefinito per i tipi derivati in termini di funzioni globali o metodi appartenenti alle classi stesse. La cardinalità (operatori unari o binari) e l’associatività (la “precedenza” di un operatore rispetto ad un altro) non possono essere modificate. Non si possono definire operatori che non siano già stati definiti per i tipi fondamentali (non si può definire un nuovo operatore ** come in Fortran per significare l’elevamento a potenza).

Regole per la ridefinizione degli operatori

Tutti gli operatori previsti dal C++ possono essere ridefiniti tranne:

• Operatore di risoluzione di visibilità

• Operatore punto per la selezione di un membro di una struttura

• Operatore di selezione di un membro a mezzo di puntatore

Un esempio: l’operatore <<

L’operatore di shift a sinistra (<<) viene utilizzato per le operazioni di output su una stream.

int i,k;std::cout << i << k;

Utilizzando una notazione “espansa”, l’operatore << può essere visto come una funzione globale che opera su una ostream e su un intero per restituire una ostream

int i,k;operator<<(operator<<(std::cout,i),k);

L’operatore << deve ritornare una ostream perché si possano concatenare due o più operazioni di output.

L’esempio: il tipo complesso

Nello stesso modo, possiamo definire un operatore << che operi sul tipo complesso e che ci permetta di stampare un complesso nella stessa maniera in cui stampiamo un intero.

ostream& operator<<(ostream& out, const complesso& c){ out << “ “ << c.Reale()<< “+i*” << c.Immaginario(); return out;}

• L’operatore prende come input una ostream ed un complesso (che non viene modificato e quindi dichiarato const )

• L’operatore ritorna una ostream

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

59

Page 60: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

60

• L’operatore “modifica” il suo argomento e lo ritorna per una successiva operazione

complesso a(3,2),b(1,4);std::cout << a << “ “ << b <<std::endl; // Stampa: “3+i*2 1+i*4”

Sappiamo ora come definire un operator+, un operator*, un operator/ per il tipo complesso:

complesso operator+(const complesso& a, const complesso& b) { complesso c( a.Reale()+b.Reale(), a.Immaginario()+b.Immaginario() ); return c;}

complesso operator*(const complesso& a, const complesso& b) { complesso c; c.Rho( a.Rho() * b.Rho() ); c.Phi( a.Phi() + b.Phi() ); return c;}

complesso operator/(const complesso& a, const complesso& b) { complesso c; c.Rho( a.Rho() / b.Rho() ); c.Phi( a.Phi() - b.Phi() ); return c;}

this

Per ogni oggetto creato, un puntatore predefinito chiamato this permette di riferirsi all’oggetto stesso.

// complesso.cc#include “complesso.h”double complesso::Modulo() // sintassi alternativa per Modulo(){ return this->reale*this->reale+ this->immaginario*this->immaginario;}

this viene normalmente utilizzato da quei metodi che devono ritornare un puntatore all’oggetto su cui operano.

L’operatore di assegnazione (=)

Gli operatori unari (assegnazione, + e – unari, ++, +=, etc.) devono essere definiti come metodi della classe su cui operano.

//complesso.hclass complesso {...public: complesso& operator=(const complesso& c); ...};

CORSO DI INFORMATICA PER LA FISICA 60

Page 61: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

61

//complesso.cc#include “complesso.h”complesso& complesso::operator=(const complesso& c){ reale=c.reale; immaginario=c.immaginario; return *this;}

complesso a(3,2);complesso b;b=a;std::cout << a << “ “ << b << std::endl;

Overloading di operatori

Come qualsiasi altro metodo o funzione, definizioni di operatori diverse per tipi di argomenti possono coesistere. Somma di un complesso e di uno scalare.

complesso operator+(const complesso& a, const double d){ complesso temp(d); return a+temp; // somma fra complessi}// proprietà commutativacomplesso operator+(const double d,const complesso& a){ return a+d; // operator+ definito sopra}

complesso a(3,2);double r=5.3; complesso b = a+r;complesso c = r+a;

Ma allora in sintesi:

Che cos’è una classe?

La dichiarazione di una classe è la dichiarazione di un nuovo tipo che racchiude sia il codice che i dati. Il nuovo tipo sarà utilizzato per definire oggetti di tale classe. Una classe è un’astrazione logica mentre un oggetto ha esistenza fisica: un oggetto è una istanza di una classe. La dichiarazione di una classe è sintatticamente uguale a quella di una struttura. Il concetto di classe si basa sui seguenti cardini :

• 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” dell’oggetto

Un esempio: come costruirla ed usarla

Attraverso questo esempio (la costruzione e la manipolazione della classe del vettore bidimensionale) si vogliono ripercorrere le definizioni e le osservazioni precedenti per quanto riguarda il concetto di classe e la sua trattazione.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

61

Page 62: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

62

// Vector2d.hclass Vector2D{public: // funzioni o metodi Vector2D(double x, double y); double x(); // double y(); // double r(); // double phi(); // private: //dati o attributi double x_; // double y_; }; // punto e virgola!

Gli attributi privati

double x; double y_;

non sono accessibili al di fuori della classe. Solo i metodi pubblici sono visibili:

double x(); double y(); double r(); double phi();

La definizione della classe termina con un “;” e l’implementazione dei metodi avviene in Vector2D.cc

//Vector2D.cc#include “Vector.h”Vector2D::Vector2D(double x, double y) : x_(x), y_(y) {} double Vector2D::x() { return x_; }

double Vector2D::r(){ return sqrt(x_*x_ + y_*y_); }

Come usare la classe Vector2D:

#include <iostream.h>#include “Vector2D.h”int main() { Vector2D v(1, 1); //invoca il constructor cout << “ v = (“ << v.x() << “,” << v.y() << “)” << endl; cout << “ r = “ << v.r(); cout << “ phi = “ << v.phi() << endl; return 0;}

L’output è il seguente:

v = (1, 1)r = 1.4141 phi = 0.7854

Oppure attraverso un puntatore :

CORSO DI INFORMATICA PER LA FISICA 62

Page 63: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

63

//main.cc#include <iostream.h>#include “Vector2D.h”int main(){ Vector2D *v = new Vector2D(1, 1); //allocazione sullo heap cout << “ v = (“ << v->x() << “,” << v->y() << “)” << endl; cout << “ r = “ << v->r(); cout << “ phi = “ << v->phi() << endl; delete v; //attenzione! return 0;}

e l’output relativo:

v = (1, 1)r = 1.4141 phi = 0.7854

new alloca memoria sullo heap. Quando v non viene più usato, occorre cancellare l’area prenotata con delete. Esiste una protezione dell’accesso ai dati; il codice seguente, che cerca di accedere a dati privati fallisce in fase di compilazione. Solo i metodi hanno libero accesso ai dati privati (e protected) della classe.

#include <iostream>#include “Vector2D.h”int main() { Vector2D v(1, 1); cout << “ V = (“ << v.x_ << “,” // << v.y_ << “,” << endl; // non compila ! cout << “ r = “ << v.r(); cout << “ phi = “ << v.phi() << endl;}

Selettori e modificatori sono metodi che agiscono in modo diverso sui data members di una classe. I selettori non modificano lo stato di una classe e sono caratterizzati dalla parola chiave const. I modificatori invece sono in grado di modificarne i contenuti.

class Vector2D{public: Vector2D(double x, double y); double x() const; //selettore double y() const; //selettore double r() const; //selettore double phi() const; //selettore void scale(double s); //modificatoreprivate: double x_, y_;};

Incapsulamento

E' la possibilità di nascondere gli attributi di un oggetto ad altri oggetti. L’accesso all’oggetto è possibile solo attraverso i suoi metodi. In questo modo si impedisce una errata manipolazione di un dato da parte di un programma garantendo quindi l’integrità e correttezza dei dati in ogni momento. Si nasconde quindi all’utilizzatore della classe il dettaglio implementativo dello stato dell’oggetto.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

63

Page 64: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

64

La programmazione ad oggetti attraverso l’incapsulamento consente di

• ridurre la dipendenza del codice di alto livello dalla rappresentazione dei dati

• riutilizzare del codice di alto livello (codice di analisi), mentre il codice di basso livello dipende dai dettagli della struttura dei dati

• sviluppare moduli indipendenti uno dall’altro

• avere codice utente che dipende dalle interfacce e non dall’implementazione

• nascondere i dettagli di implementazione

• supportare tipi di dati astratti

friend

La keyword friend può essere usata per fornire ad una funzione (o una classe) libero accesso ai dati privati di un’altra classe oppure per definire metodi che operano su più oggetti di una stessa classe o di classi distinte.

Quando una classe è friend di un’altra classe, essa e tutte le sue funzioni membro hanno accesso ai membri privati definiti all’interno dell’altra classe.

class A { . . . friend int aFunc(); friend void C::f(int); friend class B};

class B { // Tutti i suoi metodi hanno accesso a tutti i membri privati di A};

class C { void C::f(int); // Il metodo ha accesso a tutti i membri privati di A};

int aFunc(); // Ha ha accesso a tutti i membri privati di A

friend (nonostante il nome) è nemico dell’incapsulamento e quindi dell’Object Orientation. Un uso eccessivo di friend è quasi sempre sintomo di un cattivo design.

static

Se la dichiarazione di una variabile membro è preceduta dalla keyword static, si chiede al compilatore di creare una sola copia di tale variabile e di utilizzare tale copia per tutti gli oggetti della classe: quindi esisterà una sola copia di dati membri static. Tutti gli oggetti di una classe utilizzano quindi la stessa variabile e non allocano spazio per essa; tale spazio deve essere allocato dal programmatore come variabile globale. Una variabile static esiste prima che venga creato un qualsiasi oggetto della sua classe.

In sintesi:

• attributi dichiarati static in una classe sono condivisi da tutti gli oggetti di quella classe.

• metodi dichiarati static non possono accedere ad attributi non statici della classe .

• attributi statici possono essere usati e modificati soltanto da metodi statici.

Un esempio:

CORSO DI INFORMATICA PER LA FISICA 64

Page 65: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

65

#include <iostream.h>class shared { static int a; int b;public: void set(int i,int j) {a=i; b=j;} void show();};

int shared::a; //definisce avoid shared::show(){ cout << “Variabile statica a: ”<<a; cout << “\nVariabile non statica b: ”<<b; cout << “\n”; }int MyClass::counter=0; // Allocazione e inizializzazione della variabile // membro static della classe MyClassint main() { shared x,y; x.set(1,1); //assegna 1 alla variabile a x.show(); y.set(2,2); //ora le assegna 2 y.show(); x.show(); return 0;}

Nell’esempio precedente a è stata modificata sia per x che per y, perché a è condivisa da entrambi gli oggetti. Quindi l’output del programma sarà il seguente:

Variabile statica a: 1Variabile non statica b: 1Variabile statica a: 2Variabile non statica b: 2Variabile statica a: 2Variabile non statica b: 1

Nonostante l’utilizzo di static sembri imporre condizioni troppo restrittive, esso risulta utile nell’implementazione di:

• contatori

• singleton (vedi oltre)

Un contatore

Per esempio se si vuole contare il numero di oggetti di una determinata classe correntemente instanziati, per il conteggio si usa una variabile membro statica che viene incrementata (decrementata) da ciascun costruttore (distruttore). Una funzione membro statica stampa il valore corrente del contatore.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

65

Page 66: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

66

//MyClass.hClass 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; }};

#include <iostream.h>#include “MyClass.h”int MyClass::counter=0;int main() { MyClass a,b,c; MyClass *p=new MyClass; cout << “ How many? “ << MyClass::HowMany() << endl; delete p; cout<< “ and now? “ << a.HowMany() <<endl; return 0;}

Un membro statico deve essere inizializzato una e una sola volta nel codice eseguibile

int MyClass::counter=0;

Un metodo statico può essere invocato nei due modi seguenti:

MyClass::HowMany(); // 1a.HowMany(); // Dove a è un istanza di MyClass

Singleton

Un singleton è una classe di cui, ad ogni momento nel corso del programma, non esistere più di una copia (istanza). Utile per l'implementazione di classi “manager”

class aSingleton {private: static aSingleton *ptr; // Membro statico aSingleton () {} // Costruttore privato: ne vieta utilizzo // al di fuori della classepublic: static aSingleton *GetPointer(){ // Ritorna l'unica istanza della classe if (ptr==0) // Se non esiste lo crea ptr=new aSingleton; return ptr; }};

#include “aSingleton.h”aSingleton *aSingleton::ptr=0;

int main(){ aSingleton *mySing= aSingleton::GetPointer(); . . . return 0;}

CORSO DI INFORMATICA PER LA FISICA 66

Page 67: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

67

Templates

Con un template, sinonimo di modello, è possibile creare funzioni e classi generiche: il tipo dei dati su cui esse operano è specificato come parametro. L’utilizzo della funzione o della classe avviene con vari tipi di dati senza dover ricodificare esplicitamente.

Ad esempio un algoritmo che ordina un’array di int è lo stesso che per un’array di float, attraverso l'uso dei template non è necessario codificarne due diversi. I template sono quindi funzioni o classi scritte per uno o più tipi non specificati. Quando si usano i template si passano i tipi, implicitamente o esplicitamente.

La possibilità di utilizzare lo stesso codice per tipi differenti (con il tipo della variabile diventa un parametro) è una caratteristica dei linguaggi OO ed è chiamato: polimorfismo parametrico.

template<class T> T max( T p1, T p2 ) { if ( p1 < p2 ) return p2; else return p1;}

//main.ccint main() { Vector v1,v2; cout << max<int>(10,20) << endl; // Affinché funzioni la scrittura cout << max<float>(2.6,1.0) << endl;// sull'output stream, il tipo T deve cout << max<Vector>(v1,v2) << endl; // aver definito l'operatore “<<”}

Sintassi dei template:

template < function identifier > function definitiontemplate < 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 dove il template viene utilizzato.

template <typename T=int> // 'int' è qui indicaro come valore di defaultclass array_n {...private: T items[n]; // array di n elementi di tipo T}; array_n<complex, 1000> w; // w array di complessi

Template di template

L’argomento di un template può essere esso stesso un template.

template <class T1, template <class T2> class T3 >

questo permette la creazione e l’utilizzo di meta-template (template instanziati con template) molto sofisticati. La Standard Template Library fa uso di questa possibilità.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

67

Page 68: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

68

Funzioni template e parametri

Esempio dell'uso dei template

template <class T> //OK per ogni compilatorevoid swap(T& x, T& y){ T temp; temp=x; x=y; y=temp;}

template <class T, int n=10> // Secondo standard ANSI/C++, parametri T aFunc(){ // numerici possono essere inclusi nella T temp[n]; // definizione del template, ma alcuni . . . // ma alcuni compilatori non supportano } // tale funzionalità

int main() { int i=10, j=20; float x=10.1, y=23.1; char a=‘x’, b=‘z’;

swap(i,j); swap(x,y); swap(a,b); cout << “i e j scambiati: “ << i << “ “ << j <<endl; cout << “x e y scambiati: “ << x << “ “ << y <<endl; cout << “a e b scambiati: “ << a << “ “ << b <<endl; return 0;}

La funzione swap viene qui richiamata con tre diversi tipi di dati: int, double e char. Siccome essa è una funzione generica (cioè la definizione di una funzione preceduta dalla dicitura template), il compilatore crea automaticamente tre definizioni di swap: una di esse scambia valori interi, un’altra scambia valori reali, una terza valori char.

Con l’istruzione template si può fornire anche più di un tipo di dati generico, basta utilizzare un elenco separato da virgole. Il programma seguente, ad esempio, utilizza due tipi generici per creare una funzione template:

#include <iostream>using namespace std;

template <class type1,class type2> // Template a 2 parametrivoid myfunc (type1 x, type2 y) { cout << x << ' ' << y << endl; }

int main(){ myfunc(10, “Programmare in C++ “); myfunc(.23,19L); return 0;}

I tipi type1 e type2 vengono sostituiti dal compilatore rispettivamente con i tipi int e char* e double e long nel momento in cui il compilatore genera le specifiche istanze di myfunc() all’interno di main(). Quando si crea una funzione template si chiede al compilatore di generare tutte le versioni di tale funzione necessarie per gestire tutte le situazioni nelle quali il programma deve impiegare tale funzione.

CORSO DI INFORMATICA PER LA FISICA 68

Page 69: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

69

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.

Un esempio: lo stack di interi

Si vuol ora creare una classe generica per lo stack. Iniziamo dallo stack di interi. La schematizzazione della classe è la seguente:

La classe “Contenuto” contiene come data member un puntatore next all’elemento successivo e la variabile intera val che ne descrive il valore, mentre la classe “Stack” contiene il puntatore top di tipo “Contenuto”.

class Contenuto {...private: Contenuto* next; int val; };

class Stack {...private: Contenuto* top;};

Se quindi si vuole implementare la classe stack per gli interi e la classe contenuto un codice possibile alla sua implementazione è il seguente:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

69

Page 70: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

70

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; };

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;};

#include <iostream>#include “Stack.h”int main() { Stack s; s.push ( 10 ); s.push ( 20 ); std::cout << s.pop() << “ - “ << s.pop << std::endl; return 0;};

con il seguente output:

10 - 20

L’ implementazione della classe relativa allo stack “templato” diventa:

CORSO DI INFORMATICA PER LA FISICA 70

Page 71: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

71

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;};

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; };

con il relativo user code:

#include <iostream>#include “Stack.h“int main() { Stack<int> s; s.push ( 10 ); s.push ( 20 ); Stack<double> s1; Stack<Shape *> s2; std::cout << s.pop() << “ “ << s.pop << std::endl; return 0;}

Quando viene dichiarata una istanza specifica di stack il compilatore genera automaticamente tutte le funzioni e le variabili necessarie per gestire i dati effettivamente impiegati. Nell’esempio vengono usati un tipo di stack per double e per un tipo Shape *.

typename

È una parola chiave riservata in modo specifico ai template. Può essere utilizzata per sostituire la parola class nella dichiarazione di un template. Oppure, come nell’esempio seguente, per indicare il tipo generico:

template <class T>class MyClass { typename T::SubType *ptr; //ptr è un puntatore al tipo T::SubType …};

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

71

Page 72: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

72

template <class T>class MyClass { T::SubType *ptr; // Senza “typename”, SubType è interpretato // come membro statico della classe T e quindi // la riga sarebbe una moltiplicazione tra // SubType e ptr !! };

Con typename, si informa il compilatore che un nome utilizzato nella dichiarazione di un template fa riferimento ad un tipo e non al nome di un oggetto. Ogni identificatore di un template è considerato essere un valore, a meno che sia qualificato da typename.

Un altro esempio: la classe Queue

Si vuol definire una classe che supporti il meccanismo di una coda. Struttura di dati che si vuol costruire riguarda una collezione di oggetti aggiunti al fondo e rimossi in alto (FIFO). Le operazioni da introdurre sono quindi:

• Aggiungere un elemento al fondo

• Rimuovere un elemento all’inizio

• Determinare se la coda è vuota

• Determinare se la coda è piena

Esse vengono espletate da opportuni metodi:

void add(item);item remove();bool is_empty();bool is_full();

La definizione della classe sarà:

class Queue{public: Queue(); ~Queue(); Type& remove(); void add(const Type& ); bool is_empty(); bool is_full();private:// …};

Quale tipo per Type? int? In questo caso se è assegnato un valore di tipo diverso, esso, se possibile, viene automaticamente convertito in int, altrimenti si ha un errore di compilazione.

Queue qObj; string str(“adele”); qObj.add(3.141549); //ok item aggiunto come == 3 qObj.add (str); //errore di conversione da str a int

Il C++ assicura che solo oggetti di tipo int o trasformabili in int possano essere aggiunti alla Queue. E per tipi diversi come ci si comporta? Si può ad esempio copiare la classe e adattarla per lavorare con int, double,complessi, string creando classi diverse:

IntQueue DoubleQueue ComplexQueue StringQueue

La generalizzazione ovvia avviene attraverso i templates.

CORSO DI INFORMATICA PER LA FISICA 72

Page 73: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

73

template <class Type>Class Queue { public: Queue (); ~Queue(); Type& remove(); void add (const Type &); bool is_empty(); bool is_full(); private: //…};

Queue<int> qi;Queue<complex<double>> qc;Queue<string> qs;

Un altro esempio (che contiene un errore)

template <class Type>Class QueueItem { public: //… private: typedef double Type; // Errore ! Typedef non può avere lo stesso nome // del parametro templato Type. Type item; QueueItem *next;};

Il nome di un parametro templato può essere riusato nelle definizioni o dichiarazioni di una classe templata.

template <class T> class QueueItem; //dichiarazione di QueueItem template <class Type> class Queue{ public: Queue():front (0),back(0){}; ~Queue(); Type & remove(); void add (const Type &); bool is_empty() const {return front ==0;} private: QueueItem<Type> *front; QueueItem<Type> *back;};

Queue<int> qi;Queue<string> qs;Queue qs; //errore, manca il parametro

Potenza dei templates

Uno degli obiettivi più difficili della programmazione è creare codice riutilizzabile. La classe stack nella sua prima versione era utilizzabile solo per maneggiare interi. Anche se l’algoritmo poteva essere utilizzato per ogni tipo di dati, l’indicazione del tipo di dati ne limitava l’applicazione. Se si trasforma, come nell’esempio precedente, la classe stack in una classe generica diventa possibile creare uno stack per qualsiasi tipo di dati.

La Standard Template Library è costruita sui template.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

73

Page 74: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

74

CORSO DI INFORMATICA PER LA FISICA 74

Page 75: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

75

STL (Standard Template Library)

La STL (Standard Template Library) è una raccolta di funzioni generiche (algoritmi) e di classi di uso comune.

La libreria di algoritmi contiene l’implementazione di numerose funzioni di carattere generale: copia, scambio, ordinamento di oggetti e così via. Tra le classi più utilizzate della libreria di classi standard vi sono quelle che vanno sotto il generico nome di containers: si tratta di classi in grado di rappresentare oggetti generici costituiti, in generale, da collezioni di oggetti più semplici. Stringhe, vettori, iteratori, contenitori associativi (come mappe o multimappe) ne sono gli esempi più noti. La STL è progettata in modo che operazioni simili su diversi contenitori abbiano la stessa interfaccia e la stessa semantica. La STL è una libreria generica: tutti i suoi componenti sono parametrizzati mediante l’utilizzo dei template. Ne è consigliato un uso intensivo della STL dato che essa, pur possedendo una sintassi complessa, fornisce soluzioni semplici alla maggior parte dei problemi di programmazione. Il concetto base è la separazione tra dati e operazioni :

• I dati sono maneggiati da classi container

• Operazioni definite da algoritmi configurabili

• Gli iteratori sono una sorta di collante tra algoritmi e dati

Qui viene presentata una panoramica della libreria, partendo dalla sua organizzazione, dagli elementi di base e continuando con una panoramica sulle tecniche di programmazione con alcuni esempi. Le trasparenze presentate a lezione, scritte in formato powerpoint, sono raggiungibili all’indirizzo web indicato nell’introduzione alla voce: Standard Template Library.

Template (ripasso)

Tutte le parti (o quasi) della STL sono scritte con i template trattati nel capitolo precedente. Le funzioni o le classi sono scritte per uno o più tipi non specificati, che vengono passati implicitamente o esplicitamente al momento dell'utilizzo. Un esempio:

template <class T>inline const T& max(const T& a, const T& b){ return a < b ? b : a; //if a<b usa b altrimenti a}

T quindi è un tipo di dati arbitrario: il tipo è specificato da chi chiama la funzione.

Container

I container sono oggetti che contengono altri oggetti. La STL offre container di vario tipo. I seguenti containers sono detti sequenziali:

• vector definisce un array dinamico

• deque crea una coda a doppio concatenamento

• list fornisce una lista lineare

perché in STL una sequenza è una lista lineare. Oltre a quasti vengono definiti dei container associativi che consentono di ricercare in modo efficiente un valore sulla base di una chiave: set/multiset e map/multimap. Una mappa memorizza coppie chiave/valore e consente di trovare un valore sulla base della sua chiave.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

75

Page 76: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

76

Container sequenziali

vector deque list string array sono tutti container sequenziali che vengono di seguito trattati singolarmente con esempi.

Operazioni comuni a tutti i container

Le operazioni comuni a tutti i container sono elencate nella tabella sottostante con un breve commento che ne esplicita la funzionalità:

ContType cContType c1(c2)ContType c(beg,end)c.˜ContTypec.size()c.empty()c.max_size()c1==c2c1 !=c2Idem con gli operatori < >c1.swap(c2) e swap(c1,c2)c.begin() end()rbegin()rend()c.insert(pos,elem)c.clear() c.erase(beg,end)c.get_allocator()

Crea un container vuotoCopia un container dello stesso tipoCopia gli elementi di un container da beg a endCancella gli elementi e libera memoriaNumero di elementi contenutiRitorna true se Il container è vuotoMax numero di elementi inseribiliRitorna true se c1 è uguale a c2Ritorna true se c1 è diverso da c2

Swap tra c1 e c2Ritorna un iteratore al primo/ultimo elementoInserisce una copia di elem alla posizione pos Svuota il containerRimuove gli elementi da beg a endRitorna il modello in memoria del container

Sequenze

Vector e list sono le sequenze più usate. Le principali differenze tra i due sono elencate qui in sintesi:

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. •Utilizzo di iteratore ad accesso casuale

list•Tempo costante di inserimento e cancellazione di elementi in ogni punto della lista.•Utilizzo di iteratore bidirezionale.

vector

Un vettore manipola i propri elementi in un array dinamico; si può accedere ad ogni elemento direttamente con l’indice corrispondente, operazione chiamata random access.

Appendere o rimuovere elementi alla fine di un vettore è molto veloce. Inserire elementi all’inizio o in mezzo è invece molto lento, dato che gli elementi che seguono devono essere mossi per far posto al nuovo elemento. Quindi il tempo di inserimento e di cancellazione di elementi all’inizio e alla fine del vettore è costante, mentre il tempo varia linearmente con il numero di elementi per inserimento e cancellazione di elementi all’interno del vettore. Poiché vector è un iteratore ad accesso casuale (le locazioni di memoria sono contigue), l’accesso agli elementi è veloce.

CORSO DI INFORMATICA PER LA FISICA 76

Page 77: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

77

#include <iostream>#include <vector>using namespace std;int main() { vector<int> coll; for (int i=1; i<=6; ++i) { coll.push_back(i); } for (int i=0; i<coll.size(); ++i){ cout << coll[i] << ‘ ‘; } cout << endl; return 0;}

In questa porzione di codice è stato definito un vettore di interi di nome coll ed è stato utilizzato per introdurre come elementi degli interi e per stamparli poi su standard output.

1 2 3 4 5 6

E' possibile preallocare elementi, cioè richiedere al vettore di riservare della memoria addizionale, al fine di evitare ripetute allocazioni di memoria (che sono “time consuming”).

v.reserve(n)

L’istruzione precedente riserva spazio per n elementi, ma non li inizializza. Questa operazione non cambia la dimensione del container; ma pre-alloca spazio di memoria contiguo per una sua crescita (tramite insert o push_back).

D'altra parte il vettore è ridimensionabile

v.resize(n)

se n è inferiore alla size corrente il vettore viene troncato dei suoi elementi eccedenti; se n è superiore allora al vettore avvengono assegnati nuovi elementi dello stesso tipo in modo da raggiungere la size indicata.

Nella tabella riassuntiva seguente sono invece ricordate alcune operazioni possibili su vettori ed è indicata una caratterizzazione del tipo di oggetto ritornato:

c.at(idx) // l’elemento con indice idxc[idx] // l’elemento con indice idx (no range checking)c.front() // il primo elemento (no check di esistenza)c.back() // l’ultimo elemento (no check di esistenza)c.begin() // l'iteratore al primo elemc.end() // l'iteratore all’ultimo elemc.rbegin() // reverse iterator al primo elemementoc.rend() // reverse iterator per la pos dopo l’ultimo elementocapacity() // il max num di elementi senza riallocazionec.size() // il numero di elementic.empty() // se il contenitore è vuotoc.max_size() // il max numero di elementi possibile

Con i vettori si possono inserire o eliminare elementi; ecco le operazioni più comuni:• c.insert(pos,ele): inserisce alla posizione dell’iteratore pos una copia di ele e

ritorna la posizione del nuovo elemento• c.insert(pos,n,ele): inserisce n copie di ele alla posizione di pos

• c.insert(pos,beg,end)

• c.push_back(elem)

• c.pop_back()

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

77

Page 78: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

78

• c.erase(pos)

• c.erase(begin,end)

• c.resize(num): cambia il numero di elementi a num; se la dimensione cambia aumentando si costruiscono nuovi elementi facendo uso del default constructor

• c.resize(num,ele): cambia il numero di elementi a num; se la dimensione cambia aumentando si costruiscono nuovi elementi tutti uguali a ele

• c.clear()

list

E' una sequenza di elementi a doppio link. Ogni elemento ha la sua posizione di memoria e contiene una referenza al suo predecessore e al suo successore. Il random access non è consentito, quindi per accedere al decimo elemento di una list occorre navigare attraverso i nove precedenti. L’accesso lineare all’i-esimo elemento è funzione lineare del tempo. L’immissione o l’ esclusione di un elemento è veloce in qualunque posizione della lista (contrariamente a deque e a vector). In breve: la ricerca di elementi è lenta, ma veloce è l’inserimento e l’estrazione.

//stl/list.cpp#include <iostream>#include <list>using namespace std;int main() { list<char> coll; for (cha c=‘a’; c<=‘z’; ++c) // Inserisce caratteri nella lista coll.push_back(c);

while (!coll.empty()) { // Finchè ci sono elementi nella lista cout << coll.front() << ‘ ‘; // legge il primo elemento coll.pop_front(); // lo rimuove } cout << endl; return 0;}

Ciò che si ottiene è la sequenza seguente:

a b c d e f g h i j k l m n o p q r s t u v x y z

deque

Abbreviazione per “double endend queue”. Siamo quindi in presenza di un array dinamico che può essere espanso in entrambe le direzioni. L’inserzione di elementi in cima e in fondo è rapida. E' invece lenta in mezzo (movimento di elementi).

//stl/deque.cpp#include <iostream>#include <deque>using namespace std;int main() { deque<float> coll; for (int i=1; i<=6; ++i) coll.push_front(i*1.1); for (int i=0; i<coll.size(); ++i) cout << coll[i] << ‘ ‘; cout << endl; return 0;}

CORSO DI INFORMATICA PER LA FISICA 78

Page 79: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

79

Il risultato di questa operazione sarà il seguente:

6.6 5.5 4.4 3.3 2.2 1.1

Stringhe

Sono trattate come collezioni di caratteri. Finora con le stringhe si sono effettuate poche operazioni:

• creazione

• lettura

• concatenazione

• scrittura

• ispezione della loro size

In ognuno di questi usi le stringhe erano viste come una singola entità. Spesso questo tipo di uso astratto è esattamente ciò che si vuole: si vuole ignorare il contenuto interno di una stringa. Ma talvolta si vorrebbe guardare agli specifici caratteri entro una stringa.

Si può considerare una stinga un particolare container: esso contiene solo caratteri e supporta quasi tutte le operazioni dei containers. Una delle operazioni è ad esempio l’indexing, come per i vettori, per cui si può pensare di trattare una stringa come un vettore. Ad esempio si può pensare di suddividere una stringa in due parti separate da un carattere di blank (space, blank, tab, end-of-line). Oppure si vuol leggere una linea ed analizzarne il contenuto. Ad esempio:

s.substr(i,j) // crea una nuova stringa contenente copia dei caratteri // in s compresi nell’intervallo [i, i+j]

getline(is, s) // legge una linea di input da is e la salva in s

s+= s2 // sostituisce il valore di s con s + s2 // cioè appende ad s il contenuto di s2

size(); length()// Sono equivalenti: ritornano il numero di caratteri

empty() // Verifica se la stringa è vuota

max_size() // massimo numero di caratteri che la stringa può contenere

std::string s; // crea una stringa vuotas.reserve(80); // riserva memoria per 80 caratteri

Accesso agli elementi di una stringa

L’operazione è effettuata tramite l’operatore [ ] o il metodo at(). Entrambi ritornano il carattere alla posizione indicata dall’indice passato, ma il primo non esegue il controllo sulla validità dell'indice. Il primo carattere ha indice 0 mentre l’ultimo ha indice length()-1

const std::string cs (“nico”); // cs contiene ‘n’ ‘i’ ‘c’ ‘o’std::string s(“abcde”); // s contiene ‘a’ ‘b’ ‘c’ ‘d’ ’e’s[2] // ritorna ‘c’s.at(2) // ritorna ‘c’s[100] // Errore. Può causare un crashs.at(100) // Manda eccezione out_of_ranges[s.length()] // Errore. Può causare un crashs.at(s.length()) // Manda eccezione out_of_rangechar & r=s[2]; // Referenza al terzo caratterechar* p=s[3]; // Puntatore al quarto caratterer= ‘X’; // s conterrà: ‘a’ ‘b’ ‘X’ ‘d’ ‘e’

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

79

Page 80: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

80

Stringhe e vectors

Stringhe e vectors si comportano in modo similare, dato che sono entrambi container implementati come array dinamici. Quindi una stringa può essere pensata come un particolare tipo di vettore che ha i caratteri come elementi, anche se con talune differenze:

• Il goal primario di un vettore è quello di trattare gli elementi del contenitore e non il contenitore come un tutto. Allora le implementazioni di vettori sono ottimizzate per operare su elementi dentro il contenitore.

• Una stringa invece deve manipolare il contenitore (la stringa stessa) come un tutto. Le stringhe sono quindi ottimizzate per ridurre i costi di assegnazione e di passaggio dell’intero container.

Funzioni numeriche globali

Gli header files <cmath> e <cstdlib> forniscono le funzioni numeriche globali che sono ereditate dal C. Le funzioni dello header file <cmath> sono riassunte nella seguente tabella:

pow()exp()sqrt()log()log10()sin()cos()tan()sinh()cosh()tah()asin()acos()atan()atan2()fabs()fmod()

PotenzaFunzione esponenzialeRadice quadrataLogaritmo naturaleLogaritmo in base 10SenoCosenoTangenteSeno iperbolicoCoseno iperbolicoTangente iperbolicaArcosenoArcocosenoArcotangenteArcotangente di un quozienteValore assoluto di un valore floating pointResto della divisione di un floating point

Contenitori associativi

Gli elementi sono ordinati automaticamente in base a un criterio d'ordine: una funzione (per default l'operator “<”) che paragona i valori o le chiavi. I contenitori associativi sono alberi binari: ogni elemento (ogni nodo) ha un padre e due figli. Esistono diversi tipi di contenitori associativi:

● set: collezione in cui gli elementi sono ordinati in funzione del loro valore. Ogni elemento può apparire una volta sola

● multiset: come il set, ma con la duplicazione consentita

● map: contiene elementi che sono coppie chiave/valore. La chiave è la base per il criterio di ordinamento; chiavi duplicate non sono ammesse.

● multimap: come una mappa ma con duplicazioni concesse

Un set allora è una mappa in cui il valore coincide con la chiave.

Un esempio di set/multiset:

CORSO DI INFORMATICA PER LA FISICA 80

Page 81: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

81

//stl/set1.cpp#include <iostream>#include <set>int main(){ typedef std::set<int> IntSet; IntSet coll; coll.insert(3); //inserendo gli elementi in ordine sparso coll.insert(2); coll.insert(1); coll.insert(5); coll.insert(4); coll.insert(6); coll.insert(1);

IntSet::const_iterator pos; for (pos=coll.begin(); pos != coll.end(); ++pos){

std::cout << *pos << “ “; } std::cout << std::endl; return 0; }

Anche se gli elementi sono inseriti in ordine sparso l'output è:

1 2 3 4 5 6

map

Un esempio di map:

#include <map>#include <algorithm>#include <iostream>#include <string>using namespace std;

int main() { map<string,int> amap; // Mappa tra string e interi amap["Primo”]=1; amap[“Secondo”]=2; amap["Terzo"]=3; cout << "Size : " << amap.size() << endl;

map<string,int>::iterator it; for ( it=amap.begin(); it!=amap.end(); it++) // Stampa la mappa cout << "map : " << it->first << " " << it->second << endl;

cout << amap.find("Terzo")->second << endl; return 0;}

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

81

Page 82: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

82

Size : 3 map : Primo 1 map : Secondo 2 map : Terzo 3 3

multimap

Un esempio di multimap:

#include <map>#include <iostream>#include <string>using namespace std;int main() { typedef multimap<int,string> mmap; mmap coll;

//insert some elements in arbitrary order coll.insert(make_pair(5,”tagged”)); coll.insert(make_pair(2,”a”)); coll.insert(make_pair(1,”this”)); coll.insert(make_pair(4,”of”)); coll.insert(make_pair(6,”strings”)); coll.insert(make_pair(1,”is”)); coll.insert(make_pair(3,”multimap”));

mmap::iterator pos; // dump for ( pos=coll.begin(); pos!=coll.end(); ++pos){ cout << pos->second << ‘ ‘ ; } cout <<endl; return 0;}

Viene prodotto il seguente output:

This is a multimap of tagged strings.

Contenitori speciali

Due tipi di contenitori speciali sono previsti: i container adapters, a cui appartengono stack queue e priority queue, e un contenitore speciale chiamato bitset.

stack

Implementa uno stack, altrimenti noto come LIFO. Con push() si pongono inserire elementi, mentre con pop() si eliminano, in ordine inverso a quello di inserzione; top() ritorna l’elemento successivo senza rimuoverlo. Per verificare se la classe stack contiene elementi si possono usare le funzioni membro size() ed empty(). Per usare uno stack occorre introdurre lo header <stack> . Un esempio:

CORSO DI INFORMATICA PER LA FISICA 82

Page 83: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

83

//cont/stack1.cpp#include <iostream>#include <stack>using namespace std;

int main() { stack<int> st; //push tre elementi nello stack st.push(1); st.push(2); st.push(3); cout << st.top() << “ ”; st.pop(); //pop e stampa di due elementi cout << st.top() << “ ”; st.top()=77; //modifica il top element st.push(4); //push due nuovi elementi st.push(5); st.pop(); //pop e stampa i rimanenti while(!st.empty()){

cout << st.top() << “ ”;st.pop();

} cout << endl; return 0;}

L’output del programma è il seguente:

3 2 4 77 1

queue

La classe queue implementa una coda (di tipo FIFO). Le funzioni membro push() e pop() sono utilizzate per inserire o per rimuovere elementi (in ordine uguale a quello di inserimento) . Il metodo back() ritorna invece l’ultimo elemento nella coda. In realtà si tratta di un buffer in cui l’elemento successivo è sempre l’elemento che ha la più alta priorità nella queue. Se esiste più di un elemento con la uguale priorità, non è definito un ordine. L’operatore usato è sempre <. Implementazioni proprie dell’operatore sono sempre possibili.

Iteratori

Gli iteratori sono dei puntatori agli elementi di un contenitore e ci permettono di muoverci all’interno di esso; sono dei puntatori intelligenti: fanno scorrere il contenuto di un container come un puntatore fa scorrere una array

• 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

Dopo un’operazione il puntatore è lasciato al prossimo elemento della collezione. Ogni classe container fornisce il suo tipo di iteratore che conosce la struttura interna del proprio container ed agisce su essa.

Operazioni fondamentali che definiscono il comportamento di un iteratore sono le seguenti:

Operator *: Ritorna l’elemento della posizione attuale

Operator ++: Lascia che l’operatore proceda di un elemento

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

83

Page 84: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

84

Operator== e operator!=: Ritorna sei due operatori sono nella stessa posizione

Operator=: assegna un iteratore (assegna la posizione dell’elemento a cui riferisce)

Un’altra distinzione per operatori è quella che riunisce gli iteratori bidirezionali e quelli random access:

● Bidirezionali: possono operare in due direzioni. In avanti con l’operatore incremento e all’indietro con l’operatore decremento. list, set, multiset,map,multimap hanno iteratori di questo tipo.

● Random access: essi hanno tutte le proprietà dei bidirezionali, ma in più hanno la possibilità di accedere direttamente a tutti gli elementi (random access). Si possono aggiungere o sottrarre offset, processare differenze, paragonare operatori usando gli operatori relazionali < e >. vector deque e string hanno iteratori di questo tipo.

Nell’esempio che segue si vede come nel primo caso l’operatore “!=“ può essere sempre utilizzato, con ogni tipo di container, mentre nel secondo caso l’operatore < funziona solo con quelli a random access.

for (pos=coll.begin(); pos != coll.end(); ++pos){…

} //ok con ogni container

// Invece:for (pos=coll.begin(); pos < coll.end(); ++pos){

…} //non funziona con tutti i container, ma solo con quelli a random access

Iterator adapters

Gli iteratori sono pure astrazioni. In realtà quando qualcosa si comporta come un iteratore è ritenuto esso stesso un iteratore e quindi gode delle proprietà degli iteratori. Tre sono le principali categorie di iteratori:

• insert iterators: chiamati anche inserters. Essi sono usati per consentire agli algoritmi di lavorare in insert mode e non in overwrite mode. Alcune funzionalità:

back_inserter(container) // appende nello stesso ordine con push_backfront_inserter(container) // inserisce in fronte in ordine inverso // usando push_frontinserter(container,pos) // inserisce nello stesso ordine // alla posizione pos usando insert

• stream iterators: Iteratori di questo tipo leggono da e scrivono su una stream, cioè su oggetti che rappresentino canali di I/O. Essi forniscono una astrazione che permette all’input da tastiera di comportarsi come una collezione da cui si può leggere. Si può inoltre redirezionare l’output di un algoritmo direttamente a un file o sullo schermo

vector<string> coll;//legge da standard input fino a eof (o errore), destinazione:collcopy (istream_iterator<string>(cin), // Legge da standard input

istream_iterator<string>(), back_inserter(coll)); // Destinazione

sort (coll.begin(),coll.end());

//stampa tutti gli elementi senza duplicazioni//sorgente: coll//destinazione: standard output con newline tra gli elunique_copy(coll.begin(),coll.end(),ostream_iterator<string>(cout,”\n”));}

CORSO DI INFORMATICA PER LA FISICA 84

Page 85: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

85

• reverse iterators: Operano in reverse mode, sostituiscono una chiamata di un operatore incrementale con una a un operatore di decremento e viceversa. Tutti i container possono creare operatori di reverse tramite le loro funzioni membro rbegin() e rend().I vantaggi offerti:

Tutti gli algoritmi sono capaci di operare in direzione opposta senza codice speciale. Uno step all’elemento successivo tramite l’operatore ++ è ridefinito come uno step all’elemento precedente con l’operatore - -.

#include <iostream>#include <vector>#include <algorithm>#include <iterator>using namespace std;

int main(){ vector<int> coll; for (int i=1; i<=9; ++i) //inserisce elementi da 1 a 9

coll.push_back(i);

//stampa tutti gli elementi in ordine inverso copy (coll.rbegin(), coll.rend(), ostream_iterator<int>(cout,” ”)); cout <<endl; return 0;}

*coll.rbegin() ritorna il valore dell’ultimo elemento. *coll.rend() è invece indefinito come pure *coll.end(), dato che entrambi si riferiscono ad una posizione che non è un valido elemento per la collezione.

Funzioni base

begin()

Ritorna un iteratore che rappresenta l’inizio degli elementi di un container.

end()

Ritorna un iteratore che rappresenta la fine degli elementi di un container. La posizione end è la posizione dietro l’ultimo elemento, l'iteratore chiamato past-the-end operator. begin e end definiscono un half-open range. Non ci sono problemi se la dimensione è 0: begin() e end() coincidono.

Algoritmi

Sono funzioni globali che, attraverso l'uso di iteratori, operano su container anche di tipo diverso. Gli algoritmi vengono usati per manipolare il contenuto dei container: inizializzazione, ordinamento, ricerca, trasformazione del contenuto (anche su intervalli di elementi).

Sono incluse le operazioni di ordinamento, come : sort, merge, min, max... e di ricerca come: find, count, equal.. e di trasformazione, come: transform, replace, fill, rotate, shuffle... oltreché generiche operazioni numeriche come: accumulate, adjacent difference...

Un esempio di uso di algoritmi:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

85

Page 86: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

86

#include <algorithm>#include <iostream>#include <vector>using namespace std;int main{ vector<int> coll; vector<int>::iterator pos; coll.push_back(2); coll.push_back(5); coll.push_back(4); coll.push_back(1); coll.push_back(6); coll.push_back(3); pos = min_element(coll.begin(), coll.end()); // pos. minimo elemento cout << “min ” << *pos << endl; // stampa il minimo elemento

sort(coll.begin(), coll.end()); // sorting in ordine ascendente for(pos=coll.begin(); pos != coll.end(); pos++) cout << *pos << " "; cout << std::endl;

pos=find(coll.begin(), coll.end(), 3); // cerca il primo el. =3 reverse(pos, coll.end()); // rovescia l’ordine dal terzo // elemento fino all’ultimo for(pos=coll.begin(); pos != coll.end(); pos++) cout << *pos << " "; cout << std::endl; return 0;}

min 11 2 3 4 5 61 2 6 5 4 3

Algoritmi di manipolazione

Nell’esempio seguente sono rimossi gli elementi con valore 3

CORSO DI INFORMATICA PER LA FISICA 86

Page 87: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

87

#include <algorithm>#include <iostream>#include <list>#include <iterator>using namespace std;int main{ list<int> coll; for (int i=1; i<=6; ++i) { // inserisce elementi da 1 a 6 e da 6 a 1 coll.push_front(i);

coll.push_back(i); } cout << “pre: “; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout,” “)); cout << endl;

remove(coll.begin(),coll.end(),3); // Rimuove elem. con valore 3 cout << “post:”; copy (coll.begin(),coll.end(),ostream_iterator<int>(cout,” “)); cout << endl; return 0;}

Gli elementi hanno cambiato il loro ordine come se i vecchi fossero stati rimossi. Ogni elemento di valore 3 è sovrascritto dai seguenti. Alla fine i vecchi elementi che non sono stati sovrascritti rimangono inalterati e la scrittura su standard output è la seguente:

pre: 6 5 4 3 2 1 1 2 3 4 5 6post:6 5 4 2 1 1 2 4 5 6 5 6

Una miglioria al codice precedente è fornita dall’esempio seguente:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

87

Page 88: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

88

#include <algorithm>#include <iostream>#include <list>#include <iterator>

using namespace std;int main(){ list<int> coll; for (int i=1; i<=6; ++i) { //inserisce elementi da 1 a 6 e da 6 a 1

coll.push_front(i); coll.push_back(i); }

cout << “pre : “; copy (coll.begin(),coll.end(),ostream_iterator<int>(cout,” “)); cout << endl;

list<int>::iterator end = remove (coll.begin(),coll.end(),3);

cout << “num. of removed elements: “ << distance(end,coll.end()) <<endl;

coll.erase(end,coll.end()); cout << “done: ”; copy (coll.begin(),coll.end(),ostream_iterator<int>(cout,” “)); cout << endl; return 0;}

come si vede dalla stampa finale, l’effetto della modifica fa effettivamente cancellare gli elementi uguali a 3

pre: 6 5 4 3 2 1 1 2 3 4 5 6num. Of removed elements: 2done: 6 5 4 2 1 1 2 4 5 6

Nonmodifying algorithms

Non cambiano l’ordine né tantomeno il valore degli elementi che processano. Essi possono essere chiamati da tutti gli standard containers.

Algoritmi di modificazione

Essi possono modificare il valore degli elementi direttamente o mentre essi vengono copiati da un range ad un altro. La sorgente non cambia, la destinazione si. I principali sono:

for_each(): Accetta una operazione che modifica l’argomento. L’argomento è passato per reference.

void square (int & elem){ elem= elem*elem;}for_each(coll.begin(), coll.end(), square);

transform(): Può essere usato per assegnare il risultato all’elemento originale.

int square (int elem){return elem*elem;

}transform(coll.begin(), coll.end(), coll.begin(), square);

CORSO DI INFORMATICA PER LA FISICA 88

Page 89: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

89

Algoritmi di removing e mutating

Rimuovono, copiano o cambiano elementi:

remove()remove_if()remove_copy()unique()reverse()rotate()rotate_copy()next_permutation()random_shuffle()partition()

Rimuove elementi di un dato valoreRimuove elementi secondo un criterioCopia gli elementi che non soddisfano un criterioRimuove duplicati adiacentiRovescia l’ordine degli elementiRuota l’ordine degli elementiCopia gli elementi mentre ruota l’ordinePermuta l’ordine degli elementiPrende gli elementi in ordine casualeCambia l’ordine degli elementi in modo che quelli che soddisfano un criterio siano davanti

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

89

Page 90: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

90

Polimorfismo ed ereditarietà

Il polimorfismo è un concetto cardine dei linguaggi di programmazione ad oggetti. Si potrebbe sintetizzare il concetto dicendo che oggetti simili sono trattati nello stesso modo indipendentemente dal loro tipo; in generale si usa la frase: “un’interfaccia, più metodi”. In altre parole il polimorfismo consente ad una interfaccia di controllare l’accesso ad una classe generale di azioni. La specifica azione selezionata è determinata dalla natura della situazione. Oggetti simili possono essere trattati come se fossero dello stesso tipo senza implementare trattamenti specifici per distinguere le tipologie. Un esempio tratto dal mondo reale è quello del termostato: un termostato (interfaccia) è una apparecchiatura che consente un controllo della temperatura indipendentemente dal tipo di combustibile (metodo) utilizzato per l’impianto.

Le trasparenze in formato powerpoint relative a questo capitolo si trovano all’indirizzo web indicato nell’introduzione e sono raggiungibili alla voce: Polimorfismo.

Nella programmazione orientata agli oggetti l’introduzione del concetto di classe permette di definire, in qualsiasi programma, oggetti complessi e di modellare le interazioni fra di loro. La programmazione OO introduce relazioni fra tipi e sottotipi

Una Fiat Panda e’ un veicoloUn Elenco Telefonico e’ una lista di abbonati

Questa categorizzazione viene ottenuta per mezzo di un meccanismo chiamato ereditarietà (inheritance) : una nuova classe può essere ottenuta per eredità da una preesistente.

Una Fiat Panda ha tutte le caratteristiche di un veicolo

Classi base e classi derivate

L’introduzione di una relazione tipo/sottotipo comporta che molte caratteristiche siano condivise:

Un veicolo si muove, una Fiat Panda si muove

Un tipo derivato può riprodurre lo stesso comportamento pubblico del tipo base (oppure no)

L’ Elenco Telefonico e’ una lista , ma fornisce una serie di servizi diversi da quelli della lista

• Un tipo derivato che riproduce il comportamento pubblico di una classe base è considerato un sottotipo di quella classe (ereditarietà pubblica)

• Un tipo derivato che non riproduce il comportamento pubblico di una classe base non è un sottotipo di quella classe ma può riutilizzarne le caratteristiche (ereditarietà privata)

Tipi derivati dalla stessa classe base hanno caratteristiche individuali che li rendono incompatibili fra di loro :

Una bicicletta e’ un veicolo, una Panda e’ un veicolo, una Panda NON e’ una bicicletta

Classi base possono essere a loro volta tipi derivati:

Una Panda e’ un automezzo, un automezzo e’ un veicolo, una bicicletta NON e’ un automezzo

Nel caso di ereditarietà pubblica, un oggetto del tipo derivato può essere usato indifferentemente come oggetto del tipo base.

Una Panda si comporta come un automezzo (astrazione)Un automezzo non è necessariamente una Panda!!!

Page 91: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

91

“Is a”

Quando di un tipo si può dire “e’ un…” si stabilisce automaticamente una relazione di ereditarietà. Questo permette di:

• Definire precise gerarchie di classi

• Generalizzare il comportamento dei tipi (astrazione)

• Utilizzare tipi diversi in maniera generica (polimorfismo)

Ereditarietà (Inheritance)

In C++ una classe può essere derivata da una classe esistente usando la sintassi:

class newclass: (public|private) oldclass { dichiarazioni...};

public e private specificano il tipo di ereditarietà che vogliamo implementare

• pubblica: la classe derivata avrà lo stesso comportamento pubblico della classe base

• privata: la classe derivata eredita il comportamento pubblico della classe base, ma “esporta” il proprio comportamento.

Classi base

Non esistono prerequisiti che una classe deve soddisfare per essere una classe base. In linea di principio è possibile ereditare da qualsiasi classe.

Ogni dato o metodo pubblico della classe base viene “esportato” alla classe derivata. Dati o metodi privati della classe base non possono venire esportati e rimangono caratteristici della classe base.

Un ulteriore qualificatore (protected) viene introdotto per garantire accesso (da parte delle classi derivate) a dati e membri altrimenti “privati” della classe base.

class Base {public:

int i;void f();

private:float r;int g(int k);

protected:double z;void r();

};

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

91

VeicoloVeicolo

AutotrenoAutotreno AutomezzoAutomezzo

PandaPanda

BiciclettaBicicletta

Page 92: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

92

Gli attributi pubblici sono esportati alla classe derivata. Gli attributi privati non sono accessibili alla classe derivata, gli attributi protetti sono accessibili alla classe derivata ma non al mondo esterno.

class Derivata: public Base {public: void ff();private: double square() { return z*z; }};

Derivata eredita implicitamente da Base tutti gli attributi pubblici. I dati e metodi caratteristici di Derivata (void ff(); e double square()). La variabile z appartiene a Base ed è protetta, Derivata può accederci direttamente.

#include “Base.h”#include “Derivata.h”int main() { Base b; // oggetto della classe Base Derivata d; // oggetto di Derivata b.r(); // Errore! r() protetto d.f(); // OK, Derivata eredita f() d.r(); // Errore! r() protetto d.ff(); // OK, ff() appartiene a Derivata b.ff(); // Errore! ff() appartiene a Derivata ma non a Base! return 0;}

Metodi virtuali

Ogni metodo pubblico o protetto della classe base viene ereditato dalle classi derivate (e ne costituiscono parte dell’interfaccia). Se un metodo della classe base è dichiarato virtual, questo può essere ridefinito in ognuna delle classi derivate. L’interfaccia viene definita dalla classe base, il comportamento dalle classi derivate.

La Fiat Panda si comporta diversamente da una Ferrari, pur mantenendo le caratteristiche di veicolo

class Base { public: virtual void Print() { std::cout << “questa è la classe Base” << std::endl; }};

class A: public Base { public: void Print() { std::cout << “questa è la classe A” <<std::endl; }};

class B: public Base { public:

. . .// Print() non è ridefinito qui

};

CORSO DI INFORMATICA PER LA FISICA 92

Page 93: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

93

#include “Base.h”int main() { Base base; // oggetto della classe Base A a; // oggetto di tipo A B b; // oggetto di tipo B

base.Print(); // questa e’ la classe base a.Print(); // questa e’ la classe A b.Print(); // questa e’ la classe base return 0;}

Metodi virtuali e classi astratte

Un metodo virtuale in una classe base può venire dichiarato nullo (=0) e non essere definito. Questo trasferisce la responsabilità della definizione sulle classi derivate che devono allora definire quel metodo per potere essere usate. Una classe base con almeno un metodo virtuale nullo e’ chiamata classe astratta. Dal punto di vista del compilatore, una classe astratta non e’ un tipo completo e oggetti di questo tipo non possono essere creati. Una classe astratta definisce l’interfaccia per le sue classi derivate.

E’ sempre comunque possibile utilizzare puntatori a classi astratte per manipolare oggetti di tipo concreto in maniera polimorfica. Si può sempre guidare una Fiat Panda come se fosse un veicolo, una volta definito quale debba essere il comportamento del veicolo stesso (ed avendo la garanzia che la Fiat Panda si comporti come tale)

class Base { public: virtual void Print() = 0; // responsabilità deferita alle derivate};

class A: public Base { public: void Print() { std::cout << “questa è la classe A” << std::endl;}};

class B: public Base { public: void Print() // B deve ora definire Print() { std::cout << “questa è la classe B” << std::endl;}};

#include “Base.h”void main() { // Base base; // Questo e’ ILLEGALE Base *base; // questo e’ ammesso A a; // oggetto di tipo A B b; // oggetto di tipo B

// base->Print(); // ILLEGALE! base = &a ; // Polimorfismo run time base->Print(); base = &b ; // Polimorfismo run time base->Print(); return 0;}

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

93

Page 94: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

94

Ereditarietà ed interfaccia

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 (se si vuole che la classe derivata sia utilizzabile per creare oggetti)

Costruttori ed ereditarietà

I costruttori della classe base NON vengono ereditati! La classe derivata è a tutti gli effetti un nuovo tipo e deve implementare i suoi propri costruttori. D’altra parte, la classe derivata “contiene” la classe base che dovrà, in qualche modo, essere inizializzata. Mai costruttori della classe derivata NON possono inizializzare direttamente i dati della classe base. Ne consegue che, in qualche modo, i costruttori della classe derivata devono invocare un costruttore della classe base. Infatti il costruttore della classe derivata può (deve) invocare il costruttore della classe base nella propria lista di inizializzazione:

Derivata::Derivata(): Base(){

. . .}Derivata::Derivata(int i): Base(){

. . .}Derivata::Derivata(int i, double x): Base(x){

. . .}

Se il costruttore della classe base richiede degli argomenti, questi andranno ricavati dagli argomenti del costruttore derivato o forniti di default.

Distruttori ed inheritance

Anche se si sta definendo un nuovo tipo, il distruttore della classe base verrà “ereditato” dalla classe derivata. Se il distruttore della classe base non è dichiarato virtual, il distruttore della classe derivata NON verrà invocato quando uno dei suoi oggetti viene distrutto. Solo il distruttore della classe base verrà invocato in questo caso.

Ogni classe base che si rispetti deve dichiarare il proprio distruttore virtual (anche se vuoto). Se il distruttore di una classe non è dichiarato virtuale, probabilmente chi ha implementato quella classe non voleva che si potesse ereditare da essa… o forse se ne è dimenticato.

Inheritance privata

L’ereditarietà privata viene utilizzata per ereditare un’implementazione (quella della classe base) senza poi esportarne l’interfaccia publica. Viene adottata per ri-utilizzare codice esistente senza esporre i clienti (classi o programmi che utilizzeranno la classe derivata) ai dettagli dell’implementazione interna (la classe base). In genere poco usato.

CORSO DI INFORMATICA PER LA FISICA 94

Page 95: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

95

Un esempio: l’elenco telefonico

Un (semplice) elenco telefonico può essere implementato per mezzo di una multimap di abbonati. In questo esempio l’elenco è una multimap ma, per nascondere i dettagli di implementazione, si utilizzerà l’inheritance privata.

Per ogni applicazione “cliente”, il comportamento dell’elenco telefonico sarà limitato alla sua sola interfaccia pubblica, essendo quella della multimap “nascosta” dall’inheritance privata.

#include <string>#include <map>#include <vector>using namespace std;struct Abbonato { string cognome; string nome; string numero; string indirizzo;};

// Associa stringhe a oggetti “Abbonato”; std::less come relazione d'ordinetypedef multimap<string, Abbonato, std::less<string> > Elenco; // Ereditarietà privata dalla classe multimap class ElencoTelefonico: private Elenco { public: ElencoTelefonico(); void AggiungiAbbonato(const Abbonato& a); string Indirizzo(string nome, string cognome) const; string Numero(string nome, string cognome) const; vector<Abbonato>& Lista(string cognome) const;};

Lo stesso risultato può essere ottenuto per “composizione”, nascondendo una multimap nella classe ElencoTelefonico ed evitando cosi di utilizzare l’inheritance (senza complicare eccessivamente l’implementazione). La relazione “is a” si trasforma cosi in una relazione di composizione (“has a”).

#include <string>#include <map>#include <vector>using namespace std;struct Abbonato { string cognome; string nome; string numero; string indirizzo;};// Associa stringhe a oggetti “Abbonato”; std::less come relazione d'ordinetypedef multimap<string, Abbonato, std::less<string> > Elenco; class ElencoTelefonico { private: Elenco elencoTelefonico; public: ElencoTelefonico(); void AggiungiAbbonato(const Abbonato& a); string Indirizzo(string nome, cognome) const; string Numero(string nome, cognome) const; vector<Abbonato>& Lista( cognome) const;};

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

95

Page 96: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

96

Ereditarietà multipla

L’ereditarietà multipla permette di derivare una classe da due o più classi base.

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

L’ereditarietà multipla viene spesso utilizzata per combinare un’interfaccia ed una implementazione, ma può essere sintomo di un cattivo disegno. Essa può portare ad effetti indesiderati:

D eredita due volte da A, F addirittura tre volte. In casi particolarmente complicati potrebbe potenzialmente accadere che una classe erediti da se stessa.

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 Base {. . . . // base implementation};class Derived: public Base {. . . . void new_method() ; // non e’ definito in Base!};void func(Base *ptr) // ptr e’ un oggetto dell classe Base{ ptr->new_method(); // Errore!!! // Occorre ottenere un puntatore a Derived: Derived *p = dynamic_cast<Derived *> (ptr) if (p !=0) {

p->new_method(); }}

CORSO DI INFORMATICA PER LA FISICA 96

A A

B B C C

D D

E E

F F

Page 97: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

97

Un altro esempio di polimorfismo

Per capire meglio il polimorfismo si può utilizzare un altro esempio: il soldato in un gioco. 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 del gioco vuole tenere una lista di soldati e vuole poter dire ad ogni soldato di attaccare indipendentemente dal tipo ma basandosi solo sulla posizione.

list<Soldato> lista; // Lista di soldatiriempiLista(lista); // Funzione generica che riempie la listaPosizione unaPosizione=...; // Posizione generica nel giocolist<Soldato>::iterator iter;for(iter=lista.begin();iter!=lista.end();iter++) { // Loop sui soldati Soldato unSoldato=(*iter); if(unSoldato.posizione()==unaPosizione) // Se si trova in unaPosizione

unSoldato.attacca(); // allora attacca}

class Soldato { void attacca() { // cosa scrivo qui?!? Per quale tipo di // soldato implemento il metodo attacca()? }};

In C++ il polimorfismo run-time viene implementato tramite il concetto di ereditarietà.

• Una classe astratta definisce i messaggi.

• Una classe concreta: eredita da quella astratta e assegna i metodi ai messaggi.

class Soldato { // Classe base astratta virtual void attacca()=0;};

class Arcere : public Soldato { // Classe “concreta” virtual void attacca() { // lancia una freccia }};

class Fante : public Soldato { // Classe “concreta” virtual void attacca() { // usa la spada }};

Un altro esempio: shape

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

• disegna

• sposta

• ingrandisci

• etc...

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

97

Page 98: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

98

Il codice potrebbe essere:

// Circle.hClass Circle { public: Circle(Point2d center, double radius); // Dove Point2d è un classe che ~Circle(); // rappresenta un punto in 2D void moveAt(const Point2d & p); // Membri pubblici (interfaccia) void moveBy(const Point2d & p); void scale(double s); void rotate(double phi); void draw() const; void cancel() const; private: // Membri privati Point2d center_; double radius_; };

//circle.cc#include “Circle.h”void Circle::draw() const { const int numberOfPoints = 100; float x[numberOfPoints], y[numberOfPoints]; float phi = 0, deltaPhi = 2*M_PI/100; for ( int i = 0; i < numberOfPoints; ++i ) { x[i] = center_.x() + radius_ * cos( phi ); y[i] = center_.y() + radius_ * sin( phi ); phi += dphi; } polyline_draw(x, y, numberOfPoints, color_, FILL);}

void Circle::moveAt( const Point2d& p ) { cancel(); center_ = p; draw();}

void Circle::scale( double s ) { cancel(); radius_ *= s; draw(); }

Circle::Circle( Point2d c, double r ) : center_( c ), radius_( r ) { draw(); }

Circle::~Circle() { cancel(); }

ed il relativo main:

CORSO DI INFORMATICA PER LA FISICA 98

Page 99: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

99

//main.cc#include “Circle.h”int main() { Circle c( Point2d(10, 10), 5 ); c.draw(); c.moveAt(Point2d(20, 30)); return 0;}

Similmente l’ implementazione della classe quadrato potrebbe essere:

//Square.hclass Square {public: Square(const Point2d&, const Point2d&, Color color = TRASPARENT); ~Square(); void moveAt( const Point2d& p ); void moveBy( const Point2d& p ); void changeColor( Color color ); void scale( double s ); void rotate( double phi ); void draw() const; void cancel() const;private: Point2d center_; Vector2d centerToUpperCorner_; Color color_;};

//square.cc#include “Square.h”void Square::draw() const { float x[4], y[4]; Vector2d delta( centerToUpperCorner_ ); for ( int i = 0; i < 4; i++ ) { Point2d corner = center_ + delta; x[i] = corner.x(); y[i] = corner.y(); delta.rotate( M_PI_2 ); } polyline_draw(x, y, 4, color_, FILL);}

void Square::rotate( double phi ) { cancel(); centerToUpperCorner_.rotate( phi ); draw(); }

Square::Square(const Point2d& lowerCorner, const Point2d& upperCorner, Color color) : center_( median(lowerCorner, upperCorner) ), centerToUpperCorner_( upperCorner - center_ ), color_( color ) { draw(); }

void Square::scale( double s ) { cancel(); centerToUpperCorner_ *= s; draw(); }

Il codice applicativo (client):

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

99

Page 100: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

100

#include “Circle.h”#include “Square.h”int main() { Circle c1( Point2d(2.,3.), 4.23 ); Square r1( Point2d(2.,1.), Point2d(4.,3.) ); Circle * circles[ 10 ];

// Instanza 10 cerchi: li crea in memoria e li assegna a puntatori for ( int i = 0; i < 10; ++i ) circles[ i ] = new Circle( Point2d(i,i), 2. ); for ( int i = 0; i < 10; ++i ) // Disegra 10 cerchi circles[ i ]->draw(); return 0;}

Il problema è come gestire cerchi e quadrati insieme? Nella codifica di esempio, cerchi e quadrati hanno un interfaccia simile (uguale), ma i metodi appartengono a classi diverse.

La soluzione è la definizione di una classe base virtuale, che definisce un'interfaccia comune a tutte le “shape”: draw, pick, move, fillColor, etc

class Shape { // Interfaccia astratta da usare come classe basepublic: Shape() { } virtual ~Shape() { } virtual void moveAt(const Point2d& where) = 0; virtual void changeColor(Color newColor) = 0; virtual void scale(double s) = 0; virtual void rotate(double phi) = 0; virtual void draw() const = 0; virtual void cancel() const = 0;};

#include “Shape.h”class Square : public Shape { // Il resto tutto uguale a prima};

class Square : public Shape { // Il resto tutto uguale a prima};

CORSO DI INFORMATICA PER LA FISICA 100

Page 101: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

101

//main.cc#include “Circle.h”#include “Square.h”int main() { Shape * shapes[ 20 ]; // Vettore di shapes int index = 0; for ( int i = 0; i < 10; i++ ) { Shape * s; s = new Circle( Point2d(i, i), 2.) ); shapes[ index ++ ] = s; // Aggiungo un circle s = new Square( Point2d(i, i), Point2d(i+1, i+2)) ); shapes[ index ++ ] = s; // Aggiungo uno square } for ( int i = 0; i < 20; i++ ) // Disegno tutti gli shapes shapes[ i ]->draw(); // NB: viene chiamato il metodo Draw // delle classi derivate!! return 0;}

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_; double lx_, ly_;};

class Square : public Rectangle{public: Square(double x0, double y0, double l) : Rectangle(x0, y0, l, l) { }};

Avere due lunghezze (lx_ e ly_) è ridondante per Square. Che cosa succede se si invoca scaleX o scaleY?

Esempio di ereditarietà multipla

Una classe può ereditare da più classi:

class DrawableObj{public: virtual void draw() = 0;};

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

10

Page 102: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

102

class Shape {public: virtual void scale(double s) = 0; virtual void moveAt( Vector2d& ) = 0;};

class DrawableShape : public DrawableObj, public Shape{public: virtual void draw(); virtual void scale(double s); virtual void moveAt( Vector2d& ); };

CORSO DI INFORMATICA PER LA FISICA 102

Page 103: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

103

UML (Unified Modeling Language)

Questo acronimo (UML- Unified Modeling Language) indica il linguaggio di modellazione ad oggetti e la sua rappresentazione tramite diagrammi per la visualizzazione di problemi di software engineering. Esso aiuto a sviluppare e rappresentare un object oriented design.

Le trasparenze (in formato powerpoint) relative a questo capitolo sono raggiungibili all’indirizzo indicato nell’introduzione di questo testo sotto la dicitura UML.

Processi

Lo svolgimento di un processo visto come astrazione del concetto legato all’analisi sviluppo e modellizzazione di un problema passa attraverso fasi ben distinte che si possono categorizzare nel modo seguente:

I quattro momenti di sviluppo del processo si susseguono e possono essere ripetuti all’interno di una stessa fase. Un processo è quindi iterativo ed incrementale. Il software è sviluppato ed edito per gradi e a moduli. Ogni iterazione produce un software provato ed integrato che soddisfa un set di requirements del progetto. Esso contiene tutte le fasi di un ciclo sintetizzabili come:

• analisi

• design

• implementazione

• test

Alcuni progetti sono classificati come high-ceremony projects: essi richiedono lo svolgimento di meetings, la scrittura di documenti, una fase iniziale (incipit) molto lunga, la presenza di sponsors…

Altri progetti sono invece più immediati e vengono chiamati low-ceremony projects. Essi infatti richiedono la chiacchierata di un’ora ad inception phase perché possano essere iniziati.

Scopo (Inception phase) ed elaborazione

Durante l’inception phase si lavora al caso in esame capendone lo scopo, i costi, l’impatto. Se ne fa una analisi iniziale per capire le dimensioni del progetto. Essa può e deve richiedere poco tempo.

Durante la fase di elaborazione le domande da porsi riguardano essenzialmente:

• Che cosa costruire?

• Come?

• Con quale tecnologia?

• Valutare i rischi: quali sono i fattori che potrebbero far ‘deragliare’ il progetto?

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

10

Scopo (inception)

ElaborazioneCostruzione

con varie iterazioni

TransizioneBeta testingPerformance tuningUser training

Page 104: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

104

Rischi

Sui requirements:

• Quali sono i requirements per il sistema?

• Quali sono le priorità d’uso e di implementazione?

• Qual e’ il pericolo nel costruire un sistema errato?

Tecnologici:

Quanta esperienza pregressa è necessaria per usare tecniche OO?

Di personale:

Si ha wo/manpower sufficiente per affrontare il progetto?

Use cases

Interazione tipica che uno user ha con un sistema per raggiungere degli scopi. Quando si costruisce un processo attraverso gli use cases si fonda una base di comunicazione tra sponsor e sviluppatore nella stesura di un progetto.

Con un word processor use case tipici:

• Trasformare un testo in grassetto

• Creare un indice ad un documento

• etc..

Nella fase di elaborazione occorre scoprire tutti i possibili use cases attraverso colloqui con gli users. Non occorre che essi siano dettagliati, occorre conoscerli nella loro individualità e diversità per valutarne l’impatto.

Scheletro di un modello concettuale

È il fondamento di un modello. Non occorre arrivare alla determinazione dei minimi dettagli. Se introdotti portano a modelli senza sostanza. Un modello dettagliato prende troppo tenpo e soccombe per paralisi nell’analisi. Invece concentrarsi solo sulle caratteristiche importanti porta ad un modello migliore.

La prototipatura è necessaria. Se si adotta un linguaggio di programmazione in questa fase non è detto che poi sia lo stesso che verrà usato per la successiva implementazione (eg: smalltalk in fase di prototipatura, e poi c++ in fase di finalizzazione per l’implementazione globale).

Planning

Istituire una serie di iterazioni per la costruzione e assegnare use cases alle iterazioni. Un piano è terminato quando ogni use case è in una iterazione e possiede un momento di inizio. Occorre categorizzare gli use cases. Occorre anche categorizzare le priorità. Le domande chiave da porsi sono:

• Si può stare senza questa funzione per un breve periodo

• Si può sopravvivere senza questa funzione per un certo periodo

Occorre avere una chiara idea dei rischi legati alle priorità tenendo conto delle varie fasi. Occorre fare una stima dello sforzo per ogni use case. Le domande da porsi e le successive valutazioni sono le seguenti:

• So quanto tempo occorre

• Si può dare una stima in mesi-uomo

• Non ho idea

CORSO DI INFORMATICA PER LA FISICA 104

Page 105: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

105

Costruzione

Il sistema viene costruito in una serie di iterazioni. Ognuna è caratterizzata come un mini progetto con tutte le fasi caratterizzanti tipiche: dall’analisi al design, dalla codifica al test e integrazione.

Al termine di questa fase occorre fornire un demo finale per lo user insieme a tests per confermare che gli use cases sono stati correttamente costruiti. Questi tests si possono dividere in due diverse categorie: quelli scritti da sviluppatori chiamati unit tests e quelli scritti da testatori (diversi dai precedenti) che si chiamano system tests.

Transizione

Al termine del processo di costruzione attraverso iterazioni si passa alla finalizzazione. L’ottimizzazione è ancora assente. L’ottimizzazione di un progetto riduce chiarezza ed estensibilità del sistema per migliorarne la performance. E’ quindi una fase successiva che viene preceduta dalla fase di bug fixes.

Strategie nello sviluppo di un progetto

Nello sviluppo di un progetto si possono delineare diverse fasi :

• Requisiti: che cosa l’utente vuole

• Analisi: la visione dell’informatico dei requisiti

• Disegno: l’aspetto del sistema software

• Produzione: codifica

• Test: debug e verifica dei requisiti

• Mantenimento: installazione del prodotto e controllo del funzionamento per il resto della sua vita.

L’esempio: il sistema solare

Supponiamo di voler progettare e realizzare un programma per la simulazione del sistema solare. Occorre

• prima una definizione del modello

• poi una analisi dettagliata dell’applicazione prima di scrivere il codice.

• un disegno di un modello dell’applicazione utilizzando un linguaggio grafico formale nell’intento di individuare le caratteristiche delle classi che parteciperanno alla realizzazione dell’applicazione

• Rendere disponibile la documentazione a tutti coloro che in futuro partecipano alla soluzione del problema.

• La produzione con il successivo test completano la fase di realizzazione del progetto, che però ha anche bisogno di essere mantenuto nel tempo in una fase successiva.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

10

Page 106: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

106

Per far ciò si possono utilizzare diversi modelli tra cui quello a cascata del tipo indicato nella seguente schematizzazione:

Oppure quello evoluzionario del tipo indicato nel grafico seguente:

Confronto tra i modelli di sviluppo

Il modello a cascata:

• 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

Nel modello evoluzionario:

• Processo ciclico (brevi processi completi)

• Attività distribuite su più fasi

• Difficile da gestire

• Facile da modificare e integrare

• Prototipo utilizzabile fin dal primo ciclo

CORSO DI INFORMATICA PER LA FISICA 106

Page 107: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

107

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. E’ possibile delegare parte del lavoro richiesto ad altri: il sistema è indipendente da chi è il suo utente.

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!!!

Disegno

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

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

10

Suddivisione del tempo per il primo ciclo

Analisi30%

Disegno35%

Codifica15%

Testing20%

Page 108: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

108

Codifica

Non sopravvalutare questa fase. Come si vede nello schema precedente alla codifica è riservata una parte esigua del tempo globale (circa il 15%). Grossa parte del tempo di progettazione è presa invece dall’analisi e dal disegno (65%).

Test

• 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.

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.

Gli scopi di un linguaggio unificato di modellizazione risiedono principalmente nel:

• Dare agli utenti un linguaggio espressivo e visuale per consentire la modellizzazione dei sistemi utilizzando concetti OO

• Fornire meccanismi di estensibilità e specializzazione per estendere i concetti di base• Essere indipendente da particolari linguaggi di programmazione• Supportare lo sviluppo di concetti a più alto livello come

1. Collaborazioni2. Framework3. Patterns4. Compomenti

• Creare un linguaggio di modellizzazione usabile da umani e da macchine

Diagrammi

In un linguaggio di modellizzazione ad oggetti hanno particolare risalto i diagrammi, che, data la storia passata e controversa dei diversi linguaggi di modelizzazione, continuano a persistere in diverse forme e catalogazione. I più comuni sono:

• use case• “class” • di comportamento (Statechart , Activity )• di interazione (sequenze, Collaborazione)• di implementazione (component, deployement)

CORSO DI INFORMATICA PER LA FISICA 108

Page 109: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

109

UML per l’analisi e il disegno

Si possono classificare i diagrammi in grandi categorie:

Class Diagrams : riguardano l’aspetto statico del sistema. Descrivono le classi con attributi e metodi e le relazioni tra di esse.

Sequence e collaboration diagrams : riflettono invece il comportamento dinamico del sistema. Sequenza dei messaggi scambiati fra gli oggetti.

Use case diagrams: illustrano gli use cases, le relazioni fra di essi e gli attori che vi partecipano.

State diagrams: descrivono gli stati in cui ogni oggetto si può trovare e le modalità con cui passa da uno stato all’altro.

Class diagrams

Un class diagram descrive i tipi di oggetti nel sistema e i vari tipi di relazioni statiche che esistono tra essi. Esistono due tipi principale di relazioni statiche:

● associazioni (un cliente può noleggiare diversi video)

● sottotipi (una infermiera è un tipo di persona)

Un diagramma di questo tipo mostra gli attributi e le operazioni di una classe e i vincoli che si applicano al modo in cui gli oggetti sono connessi.

I concetti tra le classi vengono rivisitati. Si valutano le relazioni tra i diversi oggetti e si attua una decomposizione funzionale all’interno di una classe. Si affida una responsabilità ai metodi.

Rappresentazione delle classi

Rappresentazione di una classe C++ in UML

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

10

Page 110: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

110

Nome.hclass Nome {private: Tipo1 variabile1; Tipo2 variabile2; Tipo3 variabile3;public: Nome(); ~Nome(); Tipo4 funzione1 ( arg );protected: Tipo5 funzione2 ( arg );private: Tipo6 funzione3 ( arg );};

Attributi e metodi

Principali relazioni tra classi

• associazione

• aggregazione by reference

(il composito non vive senza il componente)

• aggregazione by value

(aggregazione fisica: esistenza contemporanea)

• dipendenza

• generalizzazione (inheritance)

CORSO DI INFORMATICA PER LA FISICA 110

Nome - variabile1:Tipo1 - variabile2:Tipo2 - variabile3:Tipo3

+ funzione1(arg):Tipo4# funzione2(arg):Tipo5- funzione3(arg):Tipo6

**1

Page 111: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

111

Associazioni

Esse rappresentano le relazioni tra le istanze delle classi (una persona lavora per una azienda, una società ha un numero di uffici). Da una prospettiva concettuale le associazioni rappresentano le relazioni.

ll diagramma indica la relazione di associazione tra le classi, la molteplicità. L’asterisco tra Cliente e ordine indica che il cliente può avere molti ordini associati, l’ 1 indica che un ordine viene de un unico cliente. In generale la molteplicità indica i limiti inferiori e superiori per il numero di oggetti partecipanti.

Le associazioni indicano responsabilità. Esiste quindi uno ed un solo metodo associato ad un cliente che dice quali ordine un determinato cliente ha fatto. Similarmente ci sono anche metodi nella classe ordine che fanno conoscere quale cliente ha fatto un determinato ordine.

Aggregazione (contenimento)

By reference (condivisa)Un autista guida più automobili

By value (possesso)Una automobile possiede il suo motore

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

11

Autista

Motore

Automobile

ordine cliente

dataRicevimentoPrepagatoNumero:stringPrezzo:denaro

NomeIndirizzo

Rateazione():string

* 1

associazioneassociazione

molteplicitàmolteplicità

classeclasse

Page 112: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

112

Composizione

La composizione è una aggregazione, ma sentita più fortemente, come appartenenza. Con la composizione l’oggetto parte può appartenere a solo un tutto. In più le parti sono attese vivere e morire con il tutto. Ogni annullamento del tutto prevede un annullamento a cascata delle parti.

Nell’esempio del punto del poligono qui riportato, la freccia aperta indica che il punto non è navigabile. Il punto non conosce i poligoni. Un punto può apparire in un poligono alla volta. Il poligono è costituito da punti.

Dipendenza

Non c’è nessuna associazione, ma c’è comunque relazione di uso. Un esempio:

● Il CD non conosce il CDPlayer

● Il CDPlayer usa il CD: se cambia il formato del CD il CDPlayer deve essere modificato

Generalizzazione (ereditarietà)

CORSO DI INFORMATICA PER LA FISICA 112

PointPolygone

1 1..*1..*1

-_points

{virtual}

AutoSportiva AutoDiLusso

Ferrari

Autista

Automobile

#_autista

Motore

#_motore

{virtual}

Page 113: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

113

Esempi di Class Diagram

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

11

Shape

draw()cancel()moveBy()

Circle

radius_ : double

draw()

Point2d

CenteredShape

moveBy() 1 11

Square

CenterToUpperCorner_ : Vector2d

draw()

relazione di aggregazione

relazioni di ereditarietà

classi concrete

c lassi astratte

1

Page 114: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

114

Interaction Diagrams

Gli interaction diagrams sono modelli che descrivono come gruppi di oggetti collaborano in qualche comportamento. Generalmente un interaction diagram descrive il comportamento di un singolo use case. Il diagramma mostra un numero di oggetti-esempio e i messaggi che vengono passati tra di essi nello use case. Due sono i tipi principali di interaction diagrams: i sequence diagrams e i collaboration diagrams.

Nei primi un oggetto è mostrato come una scatola in alto rispetto ad una linea verticale tratteggiata che parte da esso. Questa linea verticale è chiamata la lifeline dell’oggetto e rappresenta la vita dell’oggetto durante l’interazione. Ogni messaggio è rappresentato da una freccia tra le lifelines di due oggetti. L’ordine con cui questi messaggi vengono inviati è mostrato scorrendo il diagramma dall’alto in basso.

CORSO DI INFORMATICA PER LA FISICA 114

Page 115: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

115

Collaboration Diagrams

In un collaboration diagram gli oggetti esempio sono indicati entro rettangoli e i messaggi che caratterizzano uno use case sono numerati. Numerare i messaggi rende più difficile vederne la sequenza, ma in questo layout spaziale si possono mostrare altre informazioni più facilmente. Si può mostrare come gli oggetti sono connessi e usare il layout per sovrapporre altra informazione.

Altri diagrammi

I package diagram vengono utilizzati per la gestione di grandi progetti di software.

Gli state diagrams descrivono il comportamento di un sistema, cioè tutti i possibili stati in cui un oggetto può presentarsi o come i cambi di stato di un oggetto possano avvenire su un oggetto in relazione ad un evento che lo raggiunge.

I deployment diagrams indicano le relazioni tra componenti software e hardware di un sistema. Lo studio di questi particolari diagrammi esula però gli scopi di questo corso e la trattazione viene rimandata a testi specialistici.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

11

Page 116: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

116

CRC (Classi, Responsabilità, Collaborazioni)

Quando si inizia a pensare ad un progetto e a delinearne le classi che lo costituiscono diventa di fondamentale importanza una serie di operazioni che permettono di arrivare con maggior facilità a una progettazione ragionata e realistica del problema. Innanzitutto occorre identificare i protagonisti ed analizzare il ruolo dei vari oggetti. Inoltre concentrarsi sul comportamento degli oggetti e non sulla rappresentazione è fondamentale. Occorre poi cercare Oggetti con proprietà comuni: oggetti diversi appartengono a classi diverse, o sono solo oggetti diversi?

Occorre poi definire le interfacce (le operazioni che soddisfano le responsabilità): una corretta assegnazione delle responsabilità è la chiave di una buona modularità e riuso.

Le responsabilità vanno suddivise tra i vari oggetti del sistema e non deve esistere un controllo centralizzato. Un oggetto deve compiere le proprie responsabilità e delegare ad altri operazioni specifiche.

La legge di Demeter recita: non usate oggetti lontani. Nell’esempio precedente di esplicitazione di classi punto e polygon

invece di usare traiettoria.listapunti().aggiungi(Punto);

è preferibile usare traiettoria.aggiungiPunto(Punto);.

Nell’attuazione di un progetto occorre identificare le relazioni attraverso alcune ricerche di base che aiutano a stilare un progetto realistico:

• Cercare collaborazioni• Cercare aggregazioni• Cercare generalizazioni

Le relazioni di tipo logico si possono classificare in tre categorie principali:

1. generalizzazioni (del tipo ln –s) che implicano uso di inheritance

2. aggregazioni (che rispondono alla domanda has) e che richiedono composizioni by value

3. dipendenze (che rispondono alla domanda knows) e che richiedono composizioni by reference.

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?

CORSO DI INFORMATICA PER LA FISICA 116

C

DE

F

BA

xz

f q

p

w

Page 117: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

117

Per risolvere il problema bisogna guardare a che cosa fanno! In C++ la scelta fra aggregazione by value o by reference 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!

(a ogni new deve corrisponde un delete! )

Un approccio corretto è 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.

CRC Workshop

Il CRC workshop è un metodo per la definizione di una architettura bilanciata.Ogni partecipante al workshop svolge il ruolo di una classe. Quando si vede affrontare la risoluzione di un problema attraverso la stesura di un progetto. Prima di iniziare occorre passare attraverso le seguenti fasi:

• Individuazione delle classi• Contrattazione delle responsabilità• Definizione delle collaborazioni

Occorre difendersi dal tentativo di assegnazione di responsabilità contrarie alla natura della classe e quindi occorre tentare di rifiutare le responsabilità. Ogni attore deve porsi le seguenti domande:

Dovrei? (Non sono io che lo devo fare!)Potrei? (Non ho i mezzi, o lo stato per farlo!)

Occorre cercare di fare poco lavoro. Se si è accettata una responsabilità, occorre cercare di far fare il lavoro a qualcun altro. Occorre potenziare i collaboratori, non interferire.

Design patterns

Sono elementi di software OO riutilizzabile. Piccoli insiemi di classi che collaborano implementando dei comportamenti tipici. Alcune categorie di patterns:

• Creational patterns• Structural patterns• Behavioral patterns

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

11

Page 118: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

118

I client possono richiedere la creazione di un prodotto senza dipendervi. La Factory dipende dai prodotti concreti, mentre i client dipendono solo da quelli astratti.

Una richiesta da un client a un server, può essere mediata dal Proxy, che può compiere anche altre operazioni (I/O, caching, etc.).

Composite

Il client può trattare componenti e compositi usando la stessa interfaccia. La composizione può essere ricursiva.

Esempio: programmi di grafica.

CORSO DI INFORMATICA PER LA FISICA 118

Leaf

operation( )

Component

operation( )

Composite

operation( )

1..*1..*

Client

for c in all _children c->operation();

_children

AbstractProduct

ConcreteProduct1 ConcreteProduct2

Factory

createProduct1 () : AbstractProductcreateProduct2 () : AbstractProduct

Client

Subject

request( )

RealSubject

request( )

Proxy

_subject : RealSubject

request( )11

Client

_subject

. . ._subject->request();. . .

Page 119: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

119

Gruppo di Shapes

Il gruppo di shapes è il Composite. La shape è il Component. Le shapes concrete (Circle, Square, ecc...) sono le Leaf.

Il codice del modello composite:

Shape.hclass 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 Circleprivate: double radius_; Point2D center_;};

//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 componentiprotected: Container components;};

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

11

Page 120: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

120

Strategy

Il pattern Strategy permette di scegliere l’algoritmo da eseguire a run-time. Nuovi algoritmi possono essere introdotti senza modificare il codice utente.

Observer

Lo stato dell’Observer dipende dallo stato del Subject. Il Subject notifica a tutti gli Observer registrati che il suo stato è cambiato.

Open/Closed principle

In generale un buon codice deve essere aperto ad estensioni e chiuso a modifiche.

Modificare un codice funzionante può introdurre bachi…

L’Object Oriented, con il meccanismo delle classi virtuali, permette di applicare questo principio.

CORSO DI INFORMATICA PER LA FISICA 120

Observer

update( )Subject

_observers : Observer

attach (Observer)notify ()

0..*0..*

for all o in _observables o->update();

_observers

return _status;_status = _subject->status();

ConcreteSubject

_status : Status

status( )

ConcreteObserver

_status : Status_subject . ConcreteSubject

update( )

_subject

ConcreteStrategyA

doAlgorithm( )

ConcreteStrategyB

doAlgorithm( )

ConcreteStrategyC

doAlgorithm( )

Client Strategy

doAlgorithm( )

{ . . . Strategy* s; s->doAlgorithm(); . . .}

Page 121: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

121

HTML

HTML (HyperText Markup Language) è un linguaggio sviluppato presso i laboratori del CERN di Ginevra, evoluto poi nel W3 Consortium: collaborazione tra il laboratori for Computer Science del MIT e l’INRIA (gruppo tecnologico francese in collaborazione con il CERN). Esso consente di formattare testo, aggiungere grafica, suoni, video in forma di un ASCII file che qualunque computer può leggere (per proiettare poi video e avere il suono occorre che il computer abbia l’hardware necessario).

La chiave di comprensione di HTML sta nei tags, parole chiave che sono situate tra i simboli “<” e “>” e che indicano quale tipo di contenuto segua nella dichiarazione. HTML è quindi testo che contiene questi simboli e che può essere interpretato da un programma speciale, il browser. Quindi un browser può interpretare i tags di HTML e poi mostrare il documento formattato sullo schermo.

Esso non è solo un modo per creare documenti dall’apparenza eccellente, ma è anche un Hypertext: documenti scritti in HTML possono contenere links ad altri documenti in HTML o a qualunque altro documento su internet per la creazione di links ad altri siti realizzando quindi un “web”.

Molti programmi sul web consentono di scrivere intere pagine di HTML senza doverne necessariamente imparare le caratteristiche. I programmi più diffusi sono: il composer di Nestcape/Mozilla, Adobe Page Mill, Microsoft Publisher, Microsoft Front Page, Macromedia Dream Weawer.

In questo corso vi si insegna a programmare in HTML step-by-step utilizzando il linguaggio HTML direttamente nella sua versione 4.0.

DTML, XML HTML browsers

DHTML è una combinazione di tecnologie usate per creare un contenuto dinamico per pagine web. Si basa su HTML(4), Cascading Style Sheets e Java Script: questi elementi sono supposti lavorare insieme utilizzando le regole del Document Object Model (DOM) per cambiare il contenuto di una pagina anche dopo che è stata caricata nel browser.

XML (Extensible Markup Language) è linguaggio che può essere utilizzato per creare i propri markup languages particolarmente utili ed indicati per i propri specifici sviluppi.

I tools più importanti per creare documenti in HTML format sono gli HTML Browsers: i più noti sono Netscape Communicator (ora parte del progetto Mozilla) e Microsoft Internet Explorer. All’oggi la percentuale di users che normalmente utilizza Netscape è ∼60%, mentre il restante 40% è per Internet Explorer.

Utilizzatori e Programmatori

OGNI computer può leggere HTML, ma ognuno lo fa a suo modo, in accordo con quanto concesso dal proprio sistema operativo (alcuni vecchi PC possono solo mostrare testo o supportare solo pochi colori)

Il modo con cui i visitatori di un sito si connettono a Internet può influenzare il modo con cui i loro computers possono vedere le pagine web. Es: un MAC user può non vedere la grafica di una vostra pagina se è connesso al web attraverso una shell Unix o con un ssh…

Un visitatore su un computer lento con un modem lento odierà tutte le ‘fancy things’ della vs. pagina (pupazzetti in moto, figure con risoluzioni da fotografo professionista, ecc.)

Ogni persona che guarda la vostra pagina può vederla in modo diverso da quello che voi pensate perchè:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

12

Page 122: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

122

Dipende la sistema del suo computer Dal browser che ha scelto Dalle capacità di grafica della sua macchina Dalla velocità del suo modem Dal tipo di connessione al web Dai settings scelti per il proprio browser

Il programmatore ha controllo limitato sull’apparenza finale della pagina quando arriva allo user. Quanto universale volete che il vostro documento sia? Tutti o pochi eletti?

Le basi di HTML

Si può creare un documento HTML con qualunque word processor o text editor (per esempio: vi o emacs, in Linux, Notepad WordPad in Window$, o TeachText e SimpleText nel regno Macintosh)

tags

I tags sono comandi scritti tra una coppia di simboli di minore (<) maggiore (>), noti anche come angle brackets, che indicano come il browser deve mostrare il testo. Entrambe le tag di apertura e chiusura utilizzano la stessa parola di comando (command word), il tag di chiusura porta un carattere “/” in più.

<EM>blue moon</EM>

attributes

Molti tag hanno speciali attributi che offrono una varietà di opzioni per il testo contenuto. L’attributo sta tra la opening tag e il simbolo di maggiore finale come nell’esempio seguente:

<TABLE BORDER>

BORDER in questo caso è l’attributo mentre TABLE è il tag.

values

Gli attributi hanno a loro volta dei valori. Talvolta si può scegliere un valore in un gruppo di opzioni possibili. Nell’esempio seguente CLEAR è un attributo di BR ed ha valore left. Si possono aggiungere anche i doppi apici “” per indicare il valore da attribuire ad un attributo, ma non sono indispensabili se i caratteri utilizzati sono lettere dell’alfabeto (maiuscole o minuscole) numeri o “-“ o il punto “.”.

<BR CLEAR=left>

I tag possono essere anche inclusi uno nell’altro per modificare un testo già modificato.

<H1>Cherry<EM>tomato</EM></H1>

La spaziatura o i caratteri di blank non vengono contati in un documento HTML, mentre un nuovo paragrafo è contrassegnato dal simbolo <P>. La fine dello stesso paragrafo è contrassegnata dal tag </P>.

Simboli speciali

Il set di caratteri ASCII standard ne contiene 128, ma altri di uso comune non sono inclusi. Per vederli nel proprio documento stampati correttamente occorre definirli utilizzando il set d caratteri

CORSO DI INFORMATICA PER LA FISICA 122

Page 123: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

123

ISO Latin-1. Nell’esempio seguente si vede l’effetto delle diverse richieste di stampa del carattere speciale:

<H1> Visca el Barça</H1>

porta alla stampa della linea: Visca el Barÿa mentre la scritta:

<H1> Visca el Bar&#231;a</H1>

porta alla scritta voluta.

Se invece non si vuole che l’autowrapping del test separi due parole contigue (es. Coca Cola) allora occorre frapporre tra le due parole i caratteri &nbsp.

Il testo “x> 3” o “x<2” è impossibile da scrivere direttamente dato che il simbolo di maggiore (minore) è parte di un tag del linguaggio. Si può ottenere il risultato voluto scrivendo &gt o &lt. Sono caratteri speciali anche i doppi apici percè’ delimitano un campo nel linguaggio. Se si vuole che invece il doppio apice sia scritto nel testo occorre indicarlo come &quot. Se invece si desidera il simbolo +- occorre indicarlo come &plusmn.

Se invece si desidera introdurre nella propria pagina web del testo preformattato (tipicamente stralci di codice programma) la cosa più semplice è quella di far precedere al testo che si importa il tag <pre> seguito alla fine del testo dal tag </pre>. In questo modo tutte le indentazioni tipiche del linguaggio di programmazione vengono salvate.

URL(Uniform Resource Locator)

URL, Uniform Resource Locator, indica l’indirizzo di un file su internet: esso è unico.

“http://www.site.com/liz/file.html”“news:soc.culture.catalan”“mailto:[email protected]”“File:///harddisk/Web/home.html”

nell’esempio http:// è lo schema, www.site.com/ è il nome del server, /liz/ è il path e file.html è il nome del file. Esiste anche la possibilità di utilizzare path relativi:

“../info/data.html”

Questa scrittura significa che si vuole accede al file data.html nel direttorio info che è ad un livello superiore di quello in cui si opera (a quello della pagina in questione)

Il design del proprio sito web

Esistono regole pratiche e di buon senso da utilizzare per la stesura di una propria pagina web. Essenzialmente rispondere alle seguenti domande può dare già una traccia. Seguire poi le semplici istruzioni può portare ad una buona stesura del proprio sistema di pagine.

Quale informazione deve essere contenuta nella proprie pagine web?

Qual è l’audience a cui è rivolta?

Quante pagine sono necessarie per comunicare quello che si desidera?

Disegnare il proprio sito su CARTA con una PENNA, anche se sembra anacronistico.

Informarsi facendo surfing su web.

Organizzare i propri file in forma di una cartella centrale o di base e sottocartelle utilizzando nomi semplici senza punteggiatura ed uno schema consistente per nomenclatura per la creazione della propria home page.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

12

Page 124: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

124

Creare una pagina web

Aprire un text editor. Creare il corpo del testo in HTML. Salvare come text o ASCII con estensione .htm o .html. Guardare la propria pagina creata in un browser (Mozilla o Internet Explorer).

Per iniziare la propria pagina web:

<HTML>

</HTML>

Occorre che la pagina sia riconosciuta indipendentemente dal browser utilizzato, e questo sta nella dichiarazione della prima riga dell’esempio precedente.

• Header: il campo delimitato dallo header si sviluppa tra <HEAD> e </HEAD>• Title: il campo delimitato dal titolo si sviluppa tra <TITLE> e </TITLE>• Body: il campo delimitato dal corpo del documento si sviluppa tra <BODY> e </BODY>• La dimensione dei caratteri può essere resa variabile dichiarando <Hn> </Hn> dove n è il

numero dei pixel di un carattere• <BR> indica un line break e non ha il corrispettivo barrato.• <P> indica un nuovo paragrafo che termina con </P>

Formattazione del testo

Non si può prevedere esattamente come uno user potrà visualizzare il testo a causa dei browsers diversi a disposizione e dell’hardware utilizzato, tuttavia alcune operazioni possono essere riconosciute dai vari browsers come:

• Cambiare le fonts<FONT FACE=“fontname1”>lklklk</FONT><FONT FACE=“Garamond Bold” COLOR=#rrggbb SIZE=10>aaaa</FONT>

• Scrivere un testo in corsivo <I>aaaa</I>• In testo in grassetto <B>bbbb</B> (anche EM o STRONG meno usati)• Scegliere una grandezza di default per un testo (body text) • Cambiare il font size rispetto al resto del testo <BIG> <SMALL>• Creare apici o pedici <SUB> <SUP> con i relativi </SUB> </SUP>• Usare testo preformattato <PRE> testo formattato </PRE>• Fare lampeggiare il testo <BLINK>testo</BLINK>• Aggiungere commenti al proprio testo in HTML <!- - commenti - ->

Creare immagini

Formato

I formati più usati per le immagini sono GIF, JPEG (PNG è meno diffuso).

Colore

Molti monitor (detti 8 bit) sono limitati a 256 colori, in più il sistema software e il browser ne riservano fino a 40 per il proprio uso. Alcuni monitor (browser safe palette) usano 216 colori (256-40). Se nella propria applicazione si usano più di 216 colori o colori diversi dai 216

CORSO DI INFORMATICA PER LA FISICA 124

Page 125: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

125

disponibili il browser fa dithering, cioè combina alcuni colori esistenti per riprodurre i mancanti, su quelli mancanti con risultati non sempre ottimi.

Trasparenza

Caratteristica interessante per dare ad una immagine contorni non netti (GIF e PNG non JPEG)

Velocità

Di download : occorre ottimizzare la procedura per ottenere un tempo minimo. Per far questo occorre che:

• le immagini siano piccole• Se sono di grande formato occorre ridurle • aggiustare la risoluzione: in questo modo la size è automaticamente aggiustata (con il crop

tool)• Se possibile comprimerle• Offrire un preview• Il tempo di download proporzionale alla size delle immagini.• Se possibile usare colori browser safe

Animazione

Solo immagini GIF possono essere animate.

Utilizzare le immagini

Inserire immagini in una pagina

<IMG SRC=“image.ext” BORDER=n>

Offrire testo alternativo se le immagini non appaiono (HTML 4 considera ALT come un attributo richiesto)

…ALT=

Specificare una grandezza (size) per una visione più veloce

<IMG SRC=“image.ext” WIDTH=x HEIGTH=y>

Connettere icone a immagini più grandi

<A HREF=image.location”> <IMG SRC=“icon.location”></A>

Un esempio:

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”><HTML><HEAD><TITLE> Providing alternate text </TITLE> </HEAD><BODY><H1>Snoopy</H1><P>Snoopy dorme sopra la cuccia</P><P><IMG SRC=“snoopy.gif” ALT=“Image of Snoopy sleeping”></BODY></HTML>

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

12

Page 126: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

126

Testo attorno alle immagini

<IMG SRC=“image.location” ALIGN=left><BR CLEAR=left>

Questa istruzione ferma il flusso di testo finché non ci sono più immagini allineate al margine di sinistra.

<BR CLEAR=all>

effettua la stessa operazione ad entrambi i margini

HSPACE=x e VSPACE=y

aumentano invece lo spazio attorno all’immagine(x e y sono i numeri di pixels da riservare)

<HR SIZE=n WIDTH=w>

per far apparire una riga di separazione della larghezza e della lunghezza voluta.

Layout

Per un corretto layout di una pagina occorre: specificare i margini

LEFTMARGIN=x TOPMARGIN=y

Creare indentazioni (36 è il numero di pixel per l’indentazione)

<SPACER TYPE=“horizontal” SIZE=36>

Centrare testo in una pagina

<CENTER>xxxx </CENTER>

Posizionare elementi in layers

<LAYER ID=name TOP=m LEFT=n WIDTH=x HEIGTH=h SRC=“source.html BGCOLOR=color BACKGROUND=“image.gif” Z-INDEX=z> .... </LAYER>

Per utilizzare un’immagine come background basta dare un attributo a body

<body background=”image.gif>

Si salva tempo al proprio utilizzatore se si usa la medesima pagina di background per un gruppo di pagine. In questo modo dopo che l’immagine è caricata per la prima pagina ogni, pagina successiva usa una versione salvata sulla “cache” dell'utente.

Il comando <blockquote> </blockquote> determina il rientro de testo in esso contenuto, l’analogo del tasto tab in un testo word.

Links

Per creare un link ad un’altra pagina web:

<A HREF=“page.html”> </A>

Se invece si vuole cambiare il colore dei links non ancora visitati si usa LINK, quelli già visitati VLINK. Quando lo user sceglie un link il testo cambia colore con il comando ALINK.

<A HREF=http://www.site.com/directory/page.html>Label text</A> (Figures 7.5 7.6).

CORSO DI INFORMATICA PER LA FISICA 126

Page 127: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

127

Liste

Si possono:

• Creare liste ordinate <OL TYPE=x START=n>, </OL> (ordered lists). Il valore di n indica il numero dell’elemento della lista

• Creare liste non ordinate <UL> (unordered lists) sono liste con bullets iniziali• Creare definition lists <DL>,</DL>. In esse ci sono due campi il primo indica la lista dei

termini, il secondo è la loro definizione. Ad esempio per una definition list:

<dl><dt> primo termine </dt><dd> la sua definizione </dd><dt> secondo termine</dt><dd> la definizionne del secondo termine </dd></dl>

Le liste possono essere una nell’altra

<ul><p> <li> <a HREF=1elementiC.ppt>Elementi di C </a><br> <li><a HREF=2dalcalc++.ppt> Dal C al C++ </a><br> <li><a HREF=3classi.ppt> Classi </a><br> <li><a HREF=4templates.ppt> Templates </a><br> <li><a HREF=5stl.ppt> STL (Standard Template Library) </a><br> <li><a HREF=6polimorfismo_ereditarieta.ppt> Polimorfismo ed Ereditarieta' </a><br> <li><a HREF=7uml.ppt> UML (Unified Modeling Language) </a><br> <li><a HREF=8html.ppt> HTML (HyperText Markup Language) </a><br> <li><a HREF=9java.ppt> Introduzione al linguaggio Java </a><br> <br></li></ul>

Tabelle

Il comando da utilizzare è <TABLE>. <TR> definisce l’inizio della prima riga. <TH> crea uno header nella prima riga. <TD> crea un cella regolare. Alla fine </TABLE>

Un esempio:

…<table WIDTH="100%" BGCOLOR="#00AACC" NOSAVE > <tr NOSAVE> <td NOSAVE><img SRC="adele.jpg" height=150 width=200 align=CENTER> </td> <td ALIGN=CENTER VALIGN=CENTER WIDTH="100%"><h1> <font color="#FFFFFF">ADELE RIMOLDI</font></h1> <h3> <font color="#FFFFFF"> <a HREF=http://www.pv.infn.it/~dfntwww/> <font color="#CCBBEE">Dipartimento di Fisica Nucleare e Teorica</a></font> <br> Universit&agrave; degli Studi di Pavia & INFN<br> <font size=+0>Via Bassi, 6 - 27100 Pavia <br> phone 0382-507433 - fax 0382-423241 <br> e-mail <a href="mailto:[email protected]"><font color="#000000">[email protected]</a></font></font></h3> </td> <td NOSAVE><img SRC="dip.gif" height=150 width=150 align=CENTER> </td> </tr> </table>

Frames

Una pagina web è detta frameset. Per creare un frameset dopo </HEAD>:

<FRAMESET ROWS=“a,b,c,…” NAME=“name”> </FRAMESET>

La pagina può essere suddivisa in frames in modo da rendere visibile più di una pagina per volta, come finestra separata.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

12

Page 128: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

128

Contents frame: i dati contenuti cambiano ogni volta che un visitatore sceglie un nuovo argomento nella tavola dei contenuti.

I frames possono essere combinati, si possono cambiare i colori dei bordi, nasconderli,modificare le dimensioni dei frames e gli spazi tra di essi…

Forms

Consentono ai visitatori di comunicare con il server.

Struttura o shell: Consiste di campi, labels, bottoni che il visitatore vede sulla pagina e poi eventualmente riempie.

Si possono creare text boxes, bottoni, drop-down menu, immagini selezionabili..

Tale informazione può essere passata (tramite CGI: Common Gateway Interface) al processing script, scritto in Perl, Python o altri linguaggi di scripting, che esegue operazioni su tali dati: li salva su un database, produce una nuova pagina, ritorna un valore in base alla richiesta, etc..

CORSO DI INFORMATICA PER LA FISICA 128

Page 129: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

129

Java

Le pagine web sono ormai diffusissime e la competizione per il possesso del primato di audience ha forzato i designer ad essere sempre più evoluti per offrire un prodotto sempre più competitivo. Il linguaggio utilizzato per le pagine web, HTML (Hypertext Markup Language), è statico.

Una evoluzione da HTML ha portato a pensare ad un modo per rendere interattive le pagine web. Ad un primo approccio sembrerebbe possibile per uno sviluppatore poter scrivere un programma nel proprio linguaggio favorito (C,C++, Visual Basic o altro) compilarlo, renderlo eseguibile, caricarlo dal server attraverso la pagina HTML. Una aggiunta minore potrebbe essere quella di consentire al web browser di caricare automaticamente il programma dal server ed eseguirlo sul computer del cliente. Il programma potrebbe aprire finestre, finestre di dialogo, suonare ecc. Questo però genererebbe molti problemi.

I linguaggi convenzionali non sono progettati per essere eseguiti attraverso il web.

Essi non hanno le caratteristiche necessarie per effettuare le più basilari operazioni (il programmatore dovrebbe programmare le operazioni più basilari come ad esempio caricare un immagine da un server per essere poi visualizzata sulla macchina del cliente)

• I programmi convenzionali hanno degli eseguibili massivi (500KB sono pochi se si sta eseguendo un programma sul proprio PC, ma diventano una pena se vanno trasferiti sulla rete alla velocità imposta dal proprio modem (28.8 Kbps)

• La sicurezza: si desidererebbe proprio vedersi eseguire dei programmi sul proprio computer senza un controllo personale? (Se un programma è stato scaricato sulla macchina del cliente ed inizia ad essere eseguito nulla può esser fatto per “limitarlo”; e se il programma contenesse qualche istruzione che fa un remove dei file residenti?)

• I diversi computer environments: al web sono attaccati i computer più disparati e quindi dovrebbe esistere una versione dell’eseguibile per ognuno dei diversi tipi (PCs, ma anche Macintoshes, e altri) e per ognuno dei diversi software installati (Linux, HP-UX, Microsoft Windows 3.1, Microsoft Windows 95,98,2000, Microsoft Windows NT, ecc.)

Il linguaggio Java è nato per risolvere questi problemi. Esso genera eseguibili estremamente contenuti in grandezza per facilitare un caricamento veloce supplendo alla lentezza delle linee di comunicazione. Un programma Java non può accedere a nulla a cui il computer client non dia accesso. Java è machine independent, semplice e potente.

Ad un primo utilizzatore esso sembra simile ad un qualunque altro linguaggio OO (come il C++) ma esso ne differisce per alcuni aspetti fondamentali. Infatti il C++ era stato creato come estensione del linguaggio C (non OO oriented) e quindi per poterlo contenere ed ampliarsi verso l’OO è divenuto estremamente complesso. I designers di Java hanno rinunciato alla compatibilità con il linguaggio C guadagnandoci in semplicità.

Le trasparenze relative a questo capitolo del corso si trovano all’indirizzo web indicato nell’introduzione e sono raggiungibili mediante click alla posizione: Introduzione al linguaggio java (in formato powerpoint).

Che cosa c’è di nuovo in Java?

Questa panoramica, più che insegnare a programmare in Java, vuole chiarire quali sono gli aspetti originali di questo linguaggio e perché esso desta tanto interesse negli ultimi tempi

• Java è un linguaggio di programmazione orientato agli oggetti• Le applicazioni sono indipendenti dalla piattaforma in cui vengono prodotte• Java è stato progettato con l’intento di creare un linguaggio semplice, robusto, sicuro• Esso è particolarmente adatto per l’ambiente grafico e le applicazioni in rete.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

12

Page 130: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

130

Java ed Internet

Java è un linguaggio OO come molti altri, tuttavia il suo sviluppo ha subito una enorme spinta dalla diffusione di Internet. Portabilità e sicurezza sono le caratteristiche che hanno decretato il successo di Java per le applicazioni di rete. L’indipendenza dalla piattaforma fa sì che un programma Java possa essere scaricato dalla rete e direttamente eseguito su tutte le più diffuse architetture di computer (PC, Unix, Mac ...)

Linguaggi compilati ed interpretati

Un linguaggio compilato richiede che un compilatore produca un eseguibile in codice macchina. L’esecuzione è molto veloce, ma lo stesso eseguibile non può essere usato su piattaforme diverse.

Invece un linguaggio interpretato è tale per cui il codice é indipendente dalla piattaforma, ma deve essere eseguito attraverso un interprete che in genere è molto poco efficiente. Java ha un compilatore ed un interprete.

Bytecode

E’ la novità di Java. Il compilatore non produce codice macchina, ma un insieme ottimizzato di istruzioni detto BYTECODE. Il sistema run-time di Java emula una macchina virtuale (Java Virtual Machine) che esegue il BYTECODE . Ogni architettura per la quale la Virtual Machine sia disponibile (installata), può eseguire lo stesso programma Java. L’efficienza di esecuzione di Java è superiore rispetto agli altri linguaggi interpretati (Tcl, Perl...), anche se non raggiunge quella dei linguaggi compilati.

Inoltre l’interprete Java fornisce compilatori “just in time” per trasformare a run-time il BYTECODE in codice macchina, guadagnando in velocità, ma perdendone la portabilità.

Possedere un BYTECODE significa intrinsecamente non minare la sicurezza dato che l’esecuzione di un BYTECODE Java è confinata nel sistema run-time che lo interpreta. L’applet non può scrivere né leggere sul client, né aprire connessioni con altri sistemi. Nel linguaggio, inoltre, non esistono i puntatori.

Ma procediamo per gradi, occorre prima definire una applicazione ed un applet e le differenze.

Applicazioni ed applets

In Java si possono produrre due tipi diversi di programmi: applicazioni ed applets.

• Un’applicazione viene eseguita sul proprio computer ed è equivalente ad un programma C o C++.

• Un applet è fatto per essere trasmesso in rete tra un Web server ed un client, ad eseguito attraverso un browser.

In un programma Java tutto il codice è contenuto all’interno di classi. Java non è concepito per essere compatibile con altri linguaggi, tuttavia è possibile invocare “Metodi Nativi” in linguaggi compilati. Si perde però la portabilità.

Un esempio di applicazione

Occorre innanzitutto verificare che sul proprio computer java sia già installato, altrimenti occorre andare al sito www.sun.com e seguire le istruzioni per il download a seconda del tipo di sistema si possegga. Scritto il codice in un file:

CORSO DI INFORMATICA PER LA FISICA 130

Page 131: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

131

//Example.javaclass Example { public static void main (String args[]) { System.out.println(“Hello World!”); }}

Il “programma” è costituito da una classe che implementa un metodo main. Occorre poi compilare:

javac Example.java

ed eseguire l’applicazione:

java Example

Java vs. C++

La sintassi è fondata sul C++, con alcune semplificazioni e differenze:

• Java non consente l’uso dei puntatori.• Un sistema di garbage collection si occupa della gestione automatica della memoria. • Non è possibile l’ereditarietà multipla, ma Java fornisce le interfacce.• Le classi ed i metodi di I/O sono diversi da quelli del C++.

Creazione degli oggetti

La allocazione di nuovi oggetti avviene con new esattamente come in C++:

Box mybox = new Box( );

Gli oggetti non hanno un distruttore, il sistema di garbage collection di Java, associato al metodo finalize, si occupa della gestione della memoria.

Ereditarietà

Una sottoclasse viene creata con l’istruzione extends;

class HeavyBox extends Box {...}

Ogni sottoclasse può ereditare da una sola superclasse .È consentita la ridefinizione (override) dei metodi. Si possono definire classi abstract, di cui non si possono creare istanze, ma possono essere usate come riferimento alle sottoclassi (Polimorfismo run-time).

Interfacce

Una interface è definita in modo analogo ad una classe, ma ha metodi non implementati e non ha variabili di istanza. Una interface può contenere la definizione di costanti, che sono condivise dalle classi che implementano l’ interface. Più classi possono implementare la stessa interfaccia, definendone tutti i metodi.

class MyClass implements MyInterface { ... }

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

13

Page 132: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

132

Un esempio

//IntStack.javainterface IntStack { void push(int item); int pop( );}

//FixedStack.javaclass FixedStack implements IntStack { … variabili di istanza e metodi propri ... public void push(int item) { … corpo di push per FixedStack… } public int pop( ) { … corpo di pop per FixedStack… }}

//DynStack.javaclass DynStack implements IntStack { … variabili di istanza e metodi propri ... public void push(int item) { … corpo di push per DynStack… } public int pop( ) { … corpo di pop per DynStack… }}

Uso delle interfacce

InterfaceTest.javaclass InterfaceTest { public static void main (String args[]) { IntStack mystack; FixStack fs = new FixStack(8); DynStack ds = new DynStack(5); mystack = ds; for (int i=0; i<12; i++) mystack.push(i); mystack = fs; for (int i=0; i<8; i++) mystack.push(i); }}

Pacchetti

Un package raggruppa un insieme di classi correlate, che possono essere importate nelle applicazioni. L’appartenenza ad un pacchetto si realizza inserendo all’inizio del file l’istruzione :

package MyPackage;

Per importare in una applicazione le classi del pacchetto:

import MyPackage.*;

java.lang java.io java.utiljava.net java.applet java.awt java.awt.image java.awt.peer

CORSO DI INFORMATICA PER LA FISICA 132

Page 133: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

133

Un Applet

import java.awt.*;import java.applet.*;public class SimpleApplet extends Applet { public void paint(Graphics g) { g.drawString(“Hello World!”); }}

L’applet è pilotato ad eventi. Un applet non ha metodo main. L’I/O è realizzato attraverso AWT (Abstract Window Toolkit).

L’esecuzione dell’applet

Un applet può essere eseguito dall’appletviewer oppure attraverso un web browser. Per accedere all’applet bisogna inserirlo in un file HTML con il tag APPLET.

Nell’applet si ridefiniscono i metodi delle classi Applet e AWT che vengono poi chiamati dall’applet viewer.

public void init( ){...}public void start( ){...}public void paint( ){...}public void stop( ){...}public void destroy( ){...}

Un esempio di applet

Scriviamo un esempio con 3 bottoni che provocano il cambio di colore dello sfondo. Implementeremo i metodi:

• init per definire lo stato iniziale• action per rivelare gli eventi connessi alla pressione dei bottoni• paint per ridisegnare l’applet

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

13

Page 134: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

134

import java.awt.*;import java.applet.*;public class ButtonDemo extends Applet {

String msg = “Ti piace Java?”;public void init() {

Button yes = new Button(“Si”);Button no = new Button(“No”);Button maybe = new Button(“Non so”);SetBackground(Color.white);add(yes);add(no);add(maybe);

}public void paint(Graphics g) {

g.drawString(msg,6,100); }

public boolean action(Event evtObj, Object arg) { if (evtObj.target instanceof Button) {

if (arg.equals(“Si”)) { setBackground(Color.green); msg = “I love Java!”;

} if (arg.equals(“No”)) {

setBackground(Color.red); msg = “Io odio Java!”;

} if (arg.equals(“Non so”)) {

setBackground(Color.yellow); msg = “Non me ne importa niente!”;

} }

}

La programmazione multithread

Più parti del programma possono essere eseguite contemporaneamente, in diversi threads. Tutti i threads sono figli del main. Se un thread si blocca in attesa di un evento, gli altri continuano a girare. Si possono definire le priorità di esecuzione e sincronizzare l’esecuzione mediante semafori. Il metodo più semplice per creare un thread è creare una classe che implementa l’interfaccia Runnable e implementare il metodo run( ).

NB: il metodo di programmazione multithread è supportato anche in C, ma non è facile da usare. La STD library non offre classi specifiche per la gestione delle thread. Se non si fa ricorso a librerie specifiche (per esempio: Boost) è compito del programmatore scriverle.

La gestione delle eccezioni

Una eccezione è una condizione di errore a run-time. In java, come in C++, una eccezione è un oggetto creato e lanciato nel metodo che ha provocato l’errore.

CORSO DI INFORMATICA PER LA FISICA 134

Page 135: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

135

class Exc1 { public static void main(String args[]) { int d, a; try { d = 0; a = 42 / d; System.out.println(“This will not be printed”); } catch (AritmeticException e) { System.out.println(“Division by zero”); }}}

Esiste un gestore default delle eccezioni. Si possono lanciare eccezioni con l’istruzione throw.

Un ulteriore esempio

L'esempio seguente porta alla visualizzazione di una applicazione Java per il web e di conseguenza alla visualizzazione di una pagina web d’uso dove l’applicazione è stata introdotta.

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

13

Page 136: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

136

<body TEXT="#000000" BGCOLOR="#F7FFCE" LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000"><!-- Changed by: Adele Rimoldi, 26-September -2001 --><p><a HREF="http://www.cern.ch/"><img SRC="http://atlasinfo.cern.ch/Atlas/GROUPS/INNER_DETECTOR/cernhead.gif" HEIGHT=20 WIDTH=400></a>&nbsp;<a HREF="http://www.cern.ch/Atlas/"><img SRC="http://atlasinfo.cern.ch/Atlas/GROUPS/INNER_DETECTOR/atl_head.gif" HEIGHT=20 WIDTH=210></a>&nbsp;<a href="http://www.cern.ch/Atlas/GROUPS/MUON/muon_page.html"><img src="http://home.cern.ch/muondoc/software/Database/img/muonhead.gif" alt="Muon Home Page"></a><img SRC="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif" HEIGHT=120 WIDTH=120 ALIGN=left VSPACE=20><h1><br>Muon Spectrometer<br> Simulation<br> using<br> Geant3</h1><p><body topmargin="5" leftmargin="5" background=" " bgcolor="#FFFFFF" text="#0000FF" link="#3366CC" vlink="#666666" alink="#996600"><!--mstheme--><font face="Tahoma"><div id="dot0" style="position: absolute; visibility: hidden; height: 11; width: 11;"><img src="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/redball.gif" height="11" width="11"></div><div id="dot1" style="position: absolute; height: 11; width: 11;"><img src="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif" height="21" width="21"></div><div id="dot2" style="position: absolute; height: 11; width: 11;"><img src="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif" height="21" width="21"></div><div id="dot3" style="position: absolute; height: 11; width: 11;"><img src="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif" height="21" width="21"></div><div id="dot4" style="position: absolute; height: 11; width: 11;"><img src="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif" height="21" width="21"></div><div id="dot5" style="position: absolute; height: 11; width: 11;"><img src="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif" height="21" width="21"></div><div id="dot6" style="position: absolute; height: 11; width: 11;"><img src="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif" height="21" width="21"></div>

<script LANGUAGE="JavaScript"><!-- hide code

/*Elastic Trail script (By Philip Winston @ [email protected], URL:http://members.xoom.com/ebullets)Script featured on Dynamicdrive.comFor this and 100's more DHTML scripts, visit http://dynamicdrive.com*/

// Thanks to Troels Jakobsen <[email protected]>// for fix which makes it work when the page is scrolled

var nDots = 7;if (document.all&&window.print)document.body.style.cssText="overflow-x:hidden;overflow-y:scroll"

var Xpos = 0;var Ypos = 0;// stopping criteria to prevent endless jittering// doesn't work when sitting on bottom since floor// doesn't push back so acceleration always as big// as gravityvar STOPVEL = 0.1;var STOPACC = 0.1;var DOTSIZE = 11; // BOUNCE is percent of velocity retained when bouncing off a wallvar BOUNCE = 0.75;

var isNetscape = navigator.appName=="Netscape";

CORSO DI INFORMATICA PER LA FISICA 136

Page 137: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

137

// always on for now, could be played with to // let dots fall to botton, get thrown, etc.var followmouse = true;

var dots = new Array();init();

function init(){ var i = 0; for (i = 0; i < nDots; i++) { dots[i] = new dot(i); } if (!isNetscape) { // I only know how to read the locations of the // <LI> items in IE //skip this for now // setInitPositions(dots) } // set their positions for (i = 0; i < nDots; i++) {

dots[i].obj.left = dots[i].X;

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

13

Page 138: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

138

dots[i].obj.top = dots[i].Y; } if (isNetscape) { // start right away since they are positioned // at 0, 0 startanimate(); } else { // let dots sit there for a few seconds // since they're hiding on the real bullets setTimeout("startanimate()", 2000); }}

function dot(i) { this.X = Xpos; this.Y = Ypos; this.dx = 0; this.dy = 0; if (isNetscape) { this.obj = eval("document.dot" + i); } else { this.obj = eval("dot" + i + ".style"); }}

function startanimate() { setInterval("animate()", 20);}

// This is to line up the bullets with actual LI tags on the page// Had to add -DOTSIZE to X and 2*DOTSIZE to Y for IE 5, not sure why// Still doesn't work greatfunction setInitPositions(dots){ // initialize dot positions to be on top // of the bullets in the <ul> var startloc = document.all.tags("LI"); var i = 0; for (i = 0; i < startloc.length && i < (nDots - 1); i++) { dots[i+1].X = startloc[i].offsetLeft startloc[i].offsetParent.offsetLeft - DOTSIZE; dots[i+1].Y = startloc[i].offsetTop + startloc[i].offsetParent.offsetTop + 2*DOTSIZE; } // put 0th dot above 1st (it is hidden) dots[0].X = dots[1].X; dots[0].Y = dots[1].Y - SEGLEN;}

// just save mouse position for animate() to usefunction MoveHandler(e){ Xpos = e.pageX; Ypos = e.pageY; return true;}

// just save mouse position for animate() to usefunction MoveHandlerIE() { Xpos = window.event.x + document.body.scrollLeft; Ypos = window.event.y + document.body.scrollTop; }

if (isNetscape) { document.captureEvents(Event.MOUSEMOVE); document.onMouseMove = MoveHandler;} else { document.onmousemove = MoveHandlerIE;

CORSO DI INFORMATICA PER LA FISICA 138

Page 139: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

139

}

function vec(X, Y){ this.X = X; this.Y = Y;}

// adds force in X and Y to spring for dot[i] on dot[j]function springForce(i, j, spring){ var dx = (dots[i].X - dots[j].X); var dy = (dots[i].Y - dots[j].Y); var len = Math.sqrt(dx*dx + dy*dy); if (len > SEGLEN) { var springF = SPRINGK * (len - SEGLEN); spring.X += (dx / len) * springF; spring.Y += (dy / len) * springF; }}

function animate() { // dots[0] follows the mouse, // though no dot is drawn there var start = 0; if (followmouse) { dots[0].X = Xpos; dots[0].Y = Ypos; start = 1; } for (i = start ; i < nDots; i++ ) { var spring = new vec(0, 0); if (i > 0) { springForce(i-1, i, spring); } if (i < (nDots - 1)) { springForce(i+1, i, spring); } // air resisitance/friction var resist = new vec(-dots[i].dx * RESISTANCE,

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

13

Page 140: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

140

-dots[i].dy * RESISTANCE); // compute new accel, including gravity var accel = new vec((spring.X + resist.X)/ MASS, (spring.Y + resist.Y)/ MASS + GRAVITY); // compute new velocity dots[i].dx += (DELTAT * accel.X); dots[i].dy += (DELTAT * accel.Y); // stop dead so it doesn't jitter when nearly still if (Math.abs(dots[i].dx) < STOPVEL && Math.abs(dots[i].dy) < STOPVEL && Math.abs(accel.X) < STOPACC && Math.abs(accel.Y) < STOPACC) { dots[i].dx = 0; dots[i].dy = 0; } // move to new position dots[i].X += dots[i].dx; dots[i].Y += dots[i].dy; // get size of window var height, width; if (isNetscape) { height = window.innerHeight + document.scrollTop; width = window.innerWidth + document.scrollLeft; } else { height = document.body.clientHeight + document.body.scrollTop; width = document.body.clientWidth + document.body.scrollLeft; } // bounce of 3 walls (leave ceiling open) if (dots[i].Y >= height - DOTSIZE - 1) { if (dots[i].dy > 0) { dots[i].dy = BOUNCE * -dots[i].dy; } dots[i].Y = height - DOTSIZE - 1; } if (dots[i].X >= width - DOTSIZE) { if (dots[i].dx > 0) { dots[i].dx = BOUNCE * -dots[i].dx; } dots[i].X = width - DOTSIZE - 1; } if (dots[i].X < 0) { if (dots[i].dx < 0) { dots[i].dx = BOUNCE * -dots[i].dx; } dots[i].X = 0; } // move img to new position dots[i].obj.left = dots[i].X; dots[i].obj.top = dots[i].Y; }}

// end code hiding -->

</script>

<br CLEAR=left><center><i><font COLOR ="teal"> This page is meant to be a reference for ongoing studies that use the current simulation with Geant3(DICE 3.21)</font></i></center> <p> The main web page of <a HREF="http://wwwinfo.cern.ch/asd/geant/"> GEANT3 </a> could give you some more information.

CORSO DI INFORMATICA PER LA FISICA 140

Page 141: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

141

<p><i><b><font SIZE=+1 COLOR ="navy">Available Documentation :</i></b></font><br><dd><br> <dd><img SRC="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/redball.gif" HEIGHT=14 WIDTH=14><b> <a HREF="http://atlasinfo.cern.ch/Atlas/GROUPS/PHYSICS/TDR/access.html"> Physics TDR </b></a>(main page)<dd> In particular in Chapter 2 you will be informed on<font COLOR="navy"> Simulation of detector and physics performance</font>.<br><dd> The simulation program is described here.</dd> <br>

<br><br><p> On this web page you can find information on: <h2>How to:</h2><p><dd><img SRC="http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/yellowball.gif" HEIGHT=14 WIDTH=14><b><a HREF="http://www.cern.ch/Atlas/GROUPS/SOFTWARE/DOCUMENTS/DICE_320/dice320.html"> Use Geant3 </b></a><br>in this case you'll use the existing version of it built on the official ATLAS repository. Follow then the pointer to DICE from <a HREF="http://atlasinfo.cern.ch/Atlas/GROUPS/SOFTWARE/DOCUMENTS/DICE_320/dice_cvs.html">srt/cvs</a></dd> <p> Some pictures obtained with Geant3 are also availale here:<hr><center><a HREF=/afs/cern.ch/user/r/rimoldi/www0/muonspectadele.eps> <img SRC=http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/muonspectadele.gif HEIGHT=70 WIDTH=70 ></a><a HREF=/afs/cern.ch/user/r/rimoldi/www0/precisionadele.eps> <img SRC=http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/precisionadele.gif HEIGHT=70 WIDTH=70 ></a><a HREF=../../afs/cern.ch/user/r/rimoldi/www0/triggeradele.eps> <img SRC=http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/triggeradele.gif HEIGHT=70 WIDTH=70 ></a><a HREF=../../afs/cern.ch/user/r/rimoldi/www0/results/3dd.eps> <img SRC=http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/results/3dd.gif HEIGHT=70 WIDTH=70 ></a><a HREF= ../../afs/cern.ch/user/r/rimoldi/www0/nofcha3d.eps> <img SRC=http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/nofcha3d.gif HEIGHT=70 WIDTH=70></a><a HREF= /afs/cern.ch/user/r/rimoldi/www0/rphi.eps> <img SRC=http://atlasinfo.cern.ch/Atlas/GROUPS/MUON/www0/rphi.gif HEIGHT=70 WIDTH=70></a></center><hr><dd>Figures captions:<dd>1: 3D view of the Muon Spectrometer (MDT + RPC + TGC + CSC)<dd>2: 3D view of the Precision Chamber System (MDT + CSC)<dd>3: 3D view of the Trigger System (RPC + TGC)<dd>4: Muon Spectrometer Longitudinal view<dd>5: Barrel system (calorimeters + RPC + MDT)<dd>6: Radial view for barrel: MDT(green), RPC(tourquoise), tile cal(blue), ecal(red), TGC (violet)</li></p><p>Page updated : 18-January-2004<imgSRC="http://atlasinfo.cern.ch/Atlas/SUB_DETECTORS/TILE/icons/line1.gif"></b><address>Maintained by<a HREF="http://consult.cern.ch/xwho/people/03306">AR</a></address>

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

14

Page 142: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

142

Python

Il linguaggio Python è un linguaggio interpretato (compilazione e link non sono necessari), interattivo e object-oriented. Viene spesso paragonato al linguaggio Perl e Java e combina una grande potenza con una sintassi molto pulita. Esso ha moduli, classi, eccezioni, data types ad alto livello dinamico e dynamic typing. Esistono interfacce a molte chiamate di sistema, librerie e a vary sistemi di windowing (X11, Motif, Mac….). Nuovi moduli built-in possono esser scritte in C o C++. Python è usabile come linguaggio di estensione per applicazioni che necessitano una interfaccia programmabile.

L’implementazione in Python è portabile: essa infatti può lavorare su UNIX, Windows, Mac… e molte altre piattaforme. Il linguaggio Python ha copyright ma è liberamente usabile e distribuibile anche per uso commerciale.

Immaginiamo un tipo di conversazione telefonica tra due persone così lontane che possa esistere un ritardo di comunicazione di un minuto tra i due. Poi immaginiamo un discorso tra due persone che stanno in stanze attigue o faccia a faccia. Lo stesso discorso viene affrontato con procedure diverse. In Python sviluppare software è come trovarsi faccia a faccia in una conversazione. Sviluppare software e testare il proprio codice mentre lo si sviluppa è simulataneo. La diversità di metodo e di apprendimento è’ la stessa che tra due persone al telefono. Il tipo di programmazione è diverso, non solo più veloce, ma anche differente.

Python ha un set completo di operazioni su stringhe e non richiede allo user una manipolazione della memoria diretta; questa caratteristica lo rende un linguaggio ideale per sviluppare prototipi.

Un programma in Python può essere costituito da un numero di moduli ognuno dei quali definisce il proprio namespace e i moduli possono definire classi che quindi offrono una ulteriore incapsulazione. L’exception handling rende possibile trovare gli errori di programmazione dove necessario. Un debugger per Python può essere scritto in Python.

Il nome del linguaggio deriva dal nome dello show sulla BBC “Monthy Python Flying Circus”, non dal nome del rettile.

Un esempio di una funzione che inverte una tavola:

def invert(table): index = {} # empty dictionary for key in table.keys(): value = table[key] if not index.has_key(value): index[value] = [] # empty list index[value].append(key) return index

Python usa l’indentazione per definire i blocchi di programma. Invece per introdurre un commento si usa il carattere “#” . Un esempio dell’uso interattivo di questa funzione (“>>>” è il prompt dell’interpreter):

>>> phonebook = {'guido': 4127, 'sjoerd': 4127, 'jack': 4098}>>> phonebook['dcab'] = 4147 # add an entry>>> inverted_phonebook = invert(phonebook)>>> print inverted_phonebook{4098: ['jack'], 4127: ['guido', 'sjoerd'], 4147: ['dcab']}>>>

Page 143: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

143

Usare l’interpreter di Python

L’interprete di Python è installato in /usr/local/bin/python sulle machine (Unix) in cui è disponibile. Ponendo /usr/local/bin nella propria UNIX shell si può invocarlo scrivendo semplicemente:

python

Per uscire dal prompt occorre scrivere un end-of-file (Control-D su UNIX, Control-z su Windows). Se non funzionasse basta scrivere “import sys; sys.exit()”.

La risposta dell’interpreter è usualmente:

Python 1.5.2b2 (#1, Feb 28 1999, 00:02:06) [GCC 2.8.1] on sunos5Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam>>>

Quando si immettono piu’ linee occorrono 3 punti all’inizio linea per dichiarare la continuazione della scrittura, come nell’esempio seguente:

>>> the_world_is_flat = 1>>> if the_world_is_flat:... print "Be careful not to fall off!"... Be careful not to fall off!

Usare python come una calcolatrice

L’interpreter può essere usato come una calcolatrice. Basta scrivere l’espressione e l’interpreter scriverà il risultato di essa. La sintassi è diretta, le parentesi possono essere usate per raggruppare le operazioni. Un esempio:

>>> 2+24>>> # This is a comment... 2+24>>> 2+2 # and a comment on the same line as code4>>> (50-5*6)/45>>> # Integer division returns the floor:... 7/32>>> 7/-3-3

altre caratteristiche generali del linguaggio

il segno = indica un’assegnazione

>>> width = 20>>> height = 5*9>>> width * height>>> 900

un valore può essere assegnato a diverse variabili simultaneamente:

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

143

Page 144: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

144

>>> x = y = z = 0 # Zero x, y and z>>> x0>>> y0>>> z0

Operazioni a typing misto subiscono le trasformazioni aspettate:

>>> 3 * 3.75 / 1.57.5>>> 7.0 / 23.5

I numeri complessi sono supportati e si possono scrivere direttamente nella forma reale + immaginario o creati attraverso una funzione complex(real, imag):

>>> 1j * 1J(-1+0j)>>> 1j * complex(0,1)(-1+0j)>>> 3+1j*3(3+3j)>>> (3+1j)*3(9+3j)>>> (1+2j)/(1+1j)(1.5+0.5j)

Per estrarre la parte reale o immaginaria di un numero complesso z basta usare i metodi z.real z.imag:

>>> a=1.5+0.5j>>> a.real1.5>>> a.imag0.5

stringhe

Un programma in python può manipolare stringhe in vari modi. Esse sono scritte tra serie di doppi apici o di apici singoli:

>>> 'spam eggs''spam eggs'>>> 'doesn\'t'"doesn't">>> "doesn't""doesn't">>> '"Yes," he said.''"Yes," he said.'>>> "\"Yes,\" he said."'"Yes," he said.'>>> '"Isn\'t," she said.''"Isn\'t," she said.'

Stringhe su più linee si ottengono utilizzando il carattere \n per indicare la continuation line.

CORSO DI INFORMATICA PER LA FISICA 144

Page 145: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

145

hello = "This is a rather long string containing\n\several lines of text just as you would do in C.\n\ Note that whitespace at the beginning of the line is\ significant."

print hello

docstrings

help rende accessibile la documentazione a stringhe di oggetti. Ogni stringa letterale che appare come primo elemento nella definizione di una classe, funzione, metodo o modulo è considerata essere la propria docstring.

Tipi numerici

Int, floating double… siamo ormai abituati a questi tipi..

Complesso: 1+ 1j

Long

>> Scrivere una funzione in C++ che calcoli il fattoriale di 100

moduli

importare moduli

sequences

lists

tuples

strings

unpacking tuples

indexing and slicing

sequence operations

binding – call by value

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

145

Page 146: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

146

Bibliografia

1.Stephen G.Kochan

Programming in ANSI C

HaydenBooks

2.Koenig Moo

Accelerated C++

Addison Wesley

3.B.Stroustrup

The C++ Programming Language

Addison Wesley

4.Herbert Schildt

C++

McGraw Hill

5.Lippman Lajoie

C++ Primer – Third Edition

Addison Wesley

6.Meyers

Effective C++

Addison Wesley

7.C.Savy

Da C++ a UML

McGraw Hill

8.Sinan Si Alhir

UML in a nutshell

O’Reilly

9.N. Josuttis

CORSO DI INFORMATICA PER LA FISICA 146

Page 147: elementi di C++rimoldi/CorsoAdele.pdfElementi di C++ con UML, HTML, Java e Python Corso di Informatica per la Fisica per studenti del primo anno del Corso Triennale di FISICA Adele

147

The C++ Standard Library

Addison Wesley

10.E.Castro

HTML for the World Wide Web 4

Peachpit Press

11.P. Naughton, H.Schildt

Java

McGraw Hill

12.D. Flanagan

Java in a Nutshell

O’ Really

13.S.R.Davis

Learn Java now

Microsoft Press

14.A.Wu

Java per la programmazione a oggetti

McGraw Hill

ADELE RIMOLDI DIPARTIMENTO DI FISICA NUCLEARE E TEORICA - UNIVERSITÀ DI PAVIA

147