Appunti OOP Cpp Matlab v2009d

97
DRAFT ver.2009.d Copyright © A. De Marco Agostino De Marco Appunti di programmazione a oggetti in C++ e Matlab Maggio 2009 ver. 2009.d

description

Appunti per la programmazione a oggetti C++ e Matlab

Transcript of Appunti OOP Cpp Matlab v2009d

Page 1: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Agostino De Marco

Appunti di programmazionea oggetti in C++ e Matlab

Maggio 2009ver. 2009.d

Page 2: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Page 3: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Indice

Introduzione 5

I Introduzione alla programmazione a oggetti 9

1 Tecniche di programmazione supportate dal C++ 111.1 Paradigmi di programmazione . . . . . . . . . . . . . . . . . . . . . . . 111.2 Programmazione procedurale . . . . . . . . . . . . . . . . . . . . . . . . 12

1.2.1 Procedure e funzioni . . . . . . . . . . . . . . . . . . . . . . . . 131.2.2 Parametri di scambio e campi di visibilità . . . . . . . . . . . . . 131.2.3 Hello world! . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161.2.4 Un semplice programma C++ con procedure . . . . . . . . . . . 17

1.3 Programmazione modulare . . . . . . . . . . . . . . . . . . . . . . . . . 181.3.1 Creare moduli attraverso gli spazi dei nomi . . . . . . . . . . . . 191.3.2 Lo spazio dei nomi della libreria standard . . . . . . . . . . . . . 201.3.3 Compilazione separata . . . . . . . . . . . . . . . . . . . . . . . 211.3.4 Gestione delle eccezioni . . . . . . . . . . . . . . . . . . . . . . 23

1.4 Astrazione dei dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251.4.1 Tipi definiti dall’utente . . . . . . . . . . . . . . . . . . . . . . . 251.4.2 Tipi concreti . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311.4.3 Tipi astratti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351.4.4 Funzioni virtuali . . . . . . . . . . . . . . . . . . . . . . . . . . 40

1.5 Programmazione orientata agli oggetti . . . . . . . . . . . . . . . . . . . 411.5.1 Un esempio: l’aerodinamica di un velivolo completo . . . . . . . 411.5.2 Dalle classi concrete alle gerarchie di classi . . . . . . . . . . . . 46

1.6 Cosa non abbiamo detto? . . . . . . . . . . . . . . . . . . . . . . . . . . 49

2 Ancora sulla programmazione in C++ 512.1 Elementi di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

2.1.1 Interfaccia dei programmi con il sistema operativo . . . . . . . . 522.1.2 Le funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542.1.3 Tipi nativi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552.1.4 Il preprocessore e le unità di traduzione dei programmi . . . . . . 55

2.2 Il mondo delle classi e degli oggetti . . . . . . . . . . . . . . . . . . . . 592.2.1 Tipi definiti dall’utente e terminologia . . . . . . . . . . . . . . . 592.2.2 Le strutture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602.2.3 Dalle strutture alle classi . . . . . . . . . . . . . . . . . . . . . . 62

Page 4: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

4 Indice

2.3 La libreria standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622.4 Le librerie Boost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622.5 Esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

2.5.1 Una classe completa per la lettura dati da file . . . . . . . . . . . 632.6 Come imparare il C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

3 Strumenti di sviluppo 693.1 Il Compilatore gcc in ambiente GNU/Linux o Cygwin . . . . . . . . . . 69

3.1.1 Il progetto GNU . . . . . . . . . . . . . . . . . . . . . . . . . . 693.1.2 I passi della compilazione . . . . . . . . . . . . . . . . . . . . . 703.1.3 L’utilità make . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

3.2 Ambienti integrati di sviluppo (IDE) . . . . . . . . . . . . . . . . . . . . 713.2.1 L’ambiente di sviluppo Microsoft Visual Studio . . . . . . . . . . 723.2.2 L’ambiente di sviluppo Code::Blocks . . . . . . . . . . . . . . . 72

II Programmazione a oggetti con Matlab 77

4 Una panoramica su Matlab 794.1 Elementi di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794.2 Toolboxes e Simulink . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804.3 Sessioni di lavoro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814.4 Usare l’help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.5 Nozioni e notazioni fondamentali . . . . . . . . . . . . . . . . . . . . . . 84

4.5.1 Le variabili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.5.2 Matrici e vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . 864.5.3 Altri tipi di dati . . . . . . . . . . . . . . . . . . . . . . . . . . . 874.5.4 Le funzioni in Matlab . . . . . . . . . . . . . . . . . . . . . . . . 88

4.6 Operazioni di Input / Output . . . . . . . . . . . . . . . . . . . . . . . . 91

5 Programmazione a oggetti in Matlab 935.1 Strutture dati di Matlab . . . . . . . . . . . . . . . . . . . . . . . . . . . 935.2 Classi e oggetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 945.3 Esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

A. De Marco

Page 5: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Introduzione

Questo non è un manuale di programmazione C++ o di Matlab, ci vorrebbe troppo tempoe impegno per scriverne uno vero. Ho solo raccolto alcune esperienze maturate nel corsodegli ultimi anni di lavoro con questi linguaggi. Alcuni esempi sono molto semplici, madovrebbero servire a mettere in luce alcuni degli aspetti più importanti che riguardano laprogrammazione a oggetti.

Di sicuro questi appunti non sono una guida per il principiante, anche se ci sono tuttele indicazioni fondamentali su come reperire informazioni sull’uso corretto dei comandi;tuttavia anche chi è agli inizi potrebbe trovare qualche spunto interessante per avvicinarsial mondo delle classi, degli oggetti, dei puntatori e della programmazione generica.

La trattazione di alcune tecniche di programmazione orientata agli oggetti si serve deilinguaggi C++ e Matlab. Ovviamente, esistono già numerosi manuali che si occupanodi C++, sia a livello introduttivo che a livello avanzato. Anche sull’ambiente Matlab esul suo linguaggio di programmazione esiste una vastissima possibilità di documentarsi,dal potente sistema di help online ai numerosi manuali e libri di testo. Va osservato peròche i manuali di livello avanzato, in particolare per il C++, molto spesso sono destinati aprogrammatori professionisti o, in generale, alla platea degli utenti informatici di media edelevata esperienza. Il lettore troverà una lista dei manuali più importanti nella bibliografia,primo fra tutti il libro di Bjarne Stroustrup [1], il ricercatore di origine danese che haideato il linguaggio.

È pur vero, d’altra parte, che per gli studenti di ingegneria dell’area industriale (mec-canica, aerospaziale, navale, chimica, gestionale, eccetera) non è facile trovare manualiche trattino la programmazione in C++ in maniera adeguata al loro percorso formativo.Spesso i corsi di informatica impartiti ai primi anni delle facoltà di ingegneria finisconoper utilizzare il linguaggio C++ come mero strumento di codifica, con il quale mostraregli aspetti di base del mondo della programmazione dei calcolatori elettronici. Ad esem-pio, quasi sempre si propone l’esercizio di implementare algoritmi di ordinamento di unvettore o di manipolazione di matrici. Per la soluzione di simili problemi nei corsi diinformatica si propone spesso il C++ perché è facile trovare strumenti di lavoro interattivigratuitamente scaricabili da internet — come, ad esempio, Dev-C++ [29], Code::Blocks[28] o Microsoft Visual C++ (200X) Express [27] — che permettono di imparare a com-pilare codice C++ in poco tempo e offrono la possibilità di mettere subito in pratica iconcetti generali della programmazione. Sia chiaro, ciò è cosa buona e giusta, anzi èassolutamente necessario per i programmatori alle prime armi, e rientra negli scopi deicorsi sui fondamenti dell’informatica. Ciò che gli studenti spesso non arrivano a com-prendere, però, è la straordinaria potenza di un linguaggio come il C++, che supporta laprogrammazione a oggetti e permette di esplorare delle tecniche di programmazione al-lo stesso tempo avanzate ed eleganti. Non è raro ascoltare uno studente del terzo anno

Page 6: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

6 Introduzione

di ingegneria aerospaziale che dichiara di aver studiato il C++ ma nega di conoscere ilconcetto di classe. Per chi conosce la programmazione a oggetti ciò risulta quanto menosorprendente. Da questo punto di vista ho ritenuto necessario, dunque, proporre un’o-perazione di “ampliamento” delle conoscenze informatiche del lettore meno esperto, macomunque in possesso delle nozioni di base sulla programmazione, introducendo con imodi dell’ingegnere la programmazione a oggetti, prima in C++ e successivamente nellinguaggio Matlab (che la maggioranza degli ingegneri conosce).

Come poter fare esperienza al riguardo? Ponendosi, ad esempio, un problema concre-to e decidendo di risolverlo — se è il caso di farlo — con una tecnica di programmazioneorientata agli oggetti, attraverso un programma di calcolo in C++ o in Matlab.

La prima parte di questi appunti tratta della programmazione orientata agli oggetti(Object-Oriented Programming, OOP) e si serve del linguaggio C++ sia per spiegarne ivari aspetti sia per fornire direttamente degli esempi pratici.

La seconda parte, dando per noti i principi di base della programmazione Matlab, nepresenta le caratteristiche (alquanto recenti) che permettono di costruire classi e svilup-pare programmi “a oggetti”.

Ho cercato di essere il meno formale possibile e mi sono limitato a dare esempi con-creti, con qualche omissione di parti di codice troppo lunghe da riportare integralmente enon fondamentali ai fini della comprensione del particolare concetto. Spero che ciò nonporti a maggiore confusione. Non si troverà qui una descrizione formale della grammaticadei linguaggi C++ e Matlab, per le quali si rimanda ai manuali specialistici.

* Le parti di testo in carattere ridotto trattano argomenti su cui è bene tornare solo dopo aver digerito ilresto, oppure contengono questioni meno importanti di quelle esposte in corpo normale.

Alcune spiegazioni potrebbero essere poco chiare: ne chiedo scusa e cercherò dirimediare in future edizioni. Commenti e richieste possono essere inviate all’indirizzo

agostino dot demarco at unina dot it

Sicuramente ci saranno sviste e imprecisioni: sarò lieto di correggerle, sperando di noncausare problemi a chi leggerà queste note.

Un commento alla veste grafica. Questo documento è stato composto con PDFLATEX.Si è usata, con poche modifiche, la classe book; i caratteri impiegati sono Times, Helveticae Bera Mono.

Napoliaprile 2009

A. De Marco

Page 7: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Appunti di programmazionea oggetti in C++ e Matlab

Page 8: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Page 9: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Parte I

Introduzione allaprogrammazione a oggetti

Page 10: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

[: : :] non cè niente di più difficile da realizzare, né il cui successo sia menosicuro, né più difficile da maneggiare, che iniziare un nuovo ordine di cose.Perché il riformatore si crea nemici tra tutti quelli che traggono vantaggio dalvecchio ordine, e solo tiepidi sostenitori tra tutti quelli che trarrebberovantaggio dal nuovo ordine [: : :]

– Niccolò Macchiavelli

(da Il principe, §vi)

Page 11: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Capitolo 1

Tecniche di programmazionesupportate dal C++

Programmare è capire.– Kristen Nygaard

Indice1.1 Paradigmi di programmazione . . . . . . . . . . . . . . . . . . . . . 111.2 Programmazione procedurale . . . . . . . . . . . . . . . . . . . . . 121.3 Programmazione modulare . . . . . . . . . . . . . . . . . . . . . . . 181.4 Astrazione dei dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251.5 Programmazione orientata agli oggetti . . . . . . . . . . . . . . . . 411.6 Cosa non abbiamo detto? . . . . . . . . . . . . . . . . . . . . . . . . 49

1.1 Paradigmi di programmazione

In informatica, una tecnica di programmazione — un paradigma per scrivere “buoni”programmi per un insieme di problemi — è uno stile fondamentale di programmazione,ovvero un insieme di strumenti concettuali per la stesura di programmi.

Lo stile di programmazione definisce e determina il modo in cui il programmato-re concepisce e percepisce il programma. Per esempio, un programma scritto secondoil paradigma della “programmazione a oggetti” (Object-Oriented Programming, OOP)è costituito da oggetti che interagiscono fra loro. Diversamente, un programma svilup-pato secondo il paradigma della “programmazione funzionale” è una composizione difunzioni.

Ogni linguaggio di programmazione è generalmente ispirato (e riconducibile) a unparticolare paradigma di programmazione. Per esempio, il Pascal e il C sono basati sulparadigma della programmazione strutturata, il linguaggio Lisp su quello della program-mazione funzionale, il Prolog su quello della programmazione logica e così via. Alcu-ni linguaggi di programmazione sono influenzati da molteplici paradigmi; un esempiomacroscopico è dato dal linguaggio Ada, che fu esplicitamente progettato per incorpora-re diversi concetti provenienti dalla programmazione strutturata, dalla programmazione

Page 12: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

12 Capitolo 1 Tecniche di programmazione supportate dal C++

modulare, dalla programmazione generica, dalla programmazione concorrente, e dallaprogrammazione per tipi di dati astratti.

A questo punto occorre fare un’importante distinzione. Si dice che un linguaggiosupporta un dato stile di programmazione se fornisce funzionalità che rendono conve-niente (ragionevolmente facile, sicuro ed efficiente) l’utilizzo di tale stile. Il linguaggioC++ è stato progettato sia per consentire una efficiente programmazione di sistema (in-globando praticamente le caratteristiche del linguaggio C) sia per fornire meccanismi cheben supportassero la programmazione a oggetti (si dice che il C++ è un linguaggio diprogrammazione “orientato agli oggetti”).

Al contrario, un linguaggio non supporta una data tecnica se per applicarla vengo-no richiesti uno sforzo o un’abilità straordinari; un simile linguaggio non supporta, masemplicemente permette di utilizzare tale tecnica. Per esempio si possono scrivere pro-grammi orientati agli oggetti in C, ma questo richiede uno sforzo improbo, in quanto talelinguaggio non supporta direttamente questa tecnica. Supportare un paradigma non hasolo il significato ovvio di mettere a disposizione funzionalità che permettano di usarlodirettamente, ma anche quello, più sottile, di fornire meccanismi di controllo statico e/odinamico su eventuali violazioni del paradigma.

* Il controllo dei tipi rappresenta l’esempio più ovvio di quanto detto. L’individuazione di ambiguità e icontrolli dinamici sono anche utilizzati per estendere il supporto linguistico ai paradigmi di programmazio-ne. Funzionalità extra-linguistiche, quali librerie e ambienti integrati di sviluppo, possono fornire ulterioresupporto ai paradigmi.

Va ribadito che il C++ è stato progettato per supportare l’astrazione dei dati, la pro-grammazione orientata agli oggetti e la programmazione generica, oltre alle tecniche diprogrammazione C tradizionali. Non è stato pensato invece con l’intento di forzare tutti iprogrammatori a seguire un particolare stile di programmazione.

I paragrafi seguenti prendono in considerazione alcuni stili di programmazione, dalparadigma della programmazione procedurale al paradigma della programmazione a og-getti. Un aspetto importante sarà quello di arrivare a distinguere due tra le tecniche piùusate per il design dei programmi: il cosiddetto approccio Top-Down, tipico della pro-grammazione strutturata e procedurale, e l’approccio Bottom-Up, tipico della program-mazione a oggetti.

Allo stesso tempo l’attenzione sarà rivolta, inizialmente, al C++ data l’importanza chequesto linguaggio riveste oggi nel campo della programmazione. Più avanti, nella secondaparte verranno presentate le nuove caratteristiche del linguaggio Matlab che supportanola programmazione a oggetti.

1.2 Programmazione procedurale

Il paradigma della programmazione procedurale è il seguente:

Decidi quali procedure ti occorrano;individua e utilizza i migliori algoritmi possibili.

Il punto focale di questa tecnica è l’elaborazione, cioè l’algoritmo necessario a svolgerela computazione desiderata.

A. De Marco

Page 13: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.2 Programmazione procedurale 13

1.2.1 Procedure e funzioni

Nella programmazione procedurale si organizzano i programmi come sequenze o com-binazioni di sottoprogrammi — in generale funzioni — creando dei blocchi di codiceche interagiscono fra di loro opportunamente. Questi blocchi sono identificati da un no- Sottoprogrammi e

funzionime e sono racchiusi da dei delimitatori. Di fatto, i delimitatori definiscono un campo divisibilità (detto anche scope) delle variabili definite nel blocco di codice.

I vari linguaggi supportano il paradigma di programmazione procedurale fornendo glistrumenti per passare argomenti alle funzioni e ottenere dei valori di ritorno. A secondadel linguaggio e dei ruoli che le funzioni e le procedure hanno all’interno del linguaggiostesso, il nome del generico sottoprogramma sarà proprio il nome di una funzione o diuna procedura. Ad esempio nel linguaggio Fortran un sottoprogramma, denominato adesempio Task1, è delimitato dalle istruzioni SUBROUTINE Task1 ed END SUBROUTINE. InFortran esistono anche le funzioni, in altre parole dei sottoprogrammi che ritornano unvalore, definiti dalla parola chiave FUNCTION.

Il nome “programmazione procedurale” deriva dal linguaggio COBOL, che è stato Parametri di scambio

il primo ad utilizzare questo concetto. Le procedure possono essere definite in mododa accettare argomenti, detti anche parametri di scambio. In fase di esecuzione di unprogramma i parametri di scambio sono dati da una lista di variabili fornite alle procedureattraverso le istruzioni di chiamata. Dal punto di vista dei sottoprogrammi, i parametridi scambio sono delle variabili locali, i cui valori, oltre che ad essere forniti dall’esternodel blocco di codice, possono essere eventualmente esportati. Ad esempio, in Fortran leistruzioni

REAL x1, x2, x3, outx1 = 1d-1; x2 = -0.5CALL Task1(x1,x2,out)x3 = out/2.

potrebbero voler dire che la chiamata alla procedura Task1 attraverso l’istruzione CALL

serve ad eseguire un insieme di calcoli che porteranno ad assegnare un certo valore allavariabile out. Essa è dichiarata ed è visibile nella parte di codice su riportata ed ha senso Valori esportati

attraverso gli argomentidi una procedura

utilizzarla dal punto immediatamente successivo alla chiamata a Task1. In questo casoout, che compare come terzo parametro di scabio di Task1, è stata utilizzata per contenereun valore esportato dalla procedura.

Una procedura nel linguaggio C++ è semplicemente una funzione che non ritornavalori. Essa assume la forma:

void hNomeProcedurai(hlista di parametrii){hdichiarazioni e istruzionii

}

in cui si esplicita che il tipo di ritorno è void. In altri termini, questa funzione non ritornaalcun valore.

1.2.2 Parametri di scambio e campi di visibilità

È pensabile concepire due tipi di parametri di scambio per le funzioni e le procedure: Passaggio dei parametri“per valore” e“per riferimento”

quelli scambiati per valore e quelli scambiati per riferimento. Nei primi vengono pas-sate delle copie di valori che, se modificati, non vengono comunque salvati al termine

Appunti di programmazione a oggetti in C++ e Matlab

Page 14: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

14 Capitolo 1 Tecniche di programmazione supportate dal C++

del sottoprogramma. Nell’esempio precedente in linguaggio Fortran, se le variabili x1 edx2 fossero passate a Task1 per valore significherebbe che all’interno di questa sarebberovisibili due copie dei loro rispettivi valori, 0.1 e -0.5. Una eventuale modifica di questiultimi all’interno della definizione della procedura verrebbe persa una volta che il control-lo del flusso del programma passa dall’istruzione di terminazione di Task1 nuovamente alcodice chiamante (istruzione successiva alla istruzione CALL).

Con i parametri scambiati per riferimento, la procedura riceve l’indirizzo di una datavariabile in memoria, che può quindi essere modificata effettivamente e permanentemen-te. In Fortran, ad esempio, il passaggio dei parametri di scambio per riferimento avvienedi default, salvo i casi in cui venga esplicitamente richiesto altrimenti nella definizionedelle SUBROUTINE e delle FUNCTION. In C ed in C++ lo scambio dei parametri avvieneRegole di passaggio dei

parametri in C e C++ per valore. Quando è necessario scambiare parametri per riferimento si ricorre all’uso deipuntatori. Nel frammento di codice che segue l’esempio precedente fornito in Fortranviene replicato in linguaggio C++:In C++ gli argomenti di

tipo puntatore realizzanolo scambio per

riferimanto

float x1, x2, x3;float *out;x1 = 0.1; x2 = -0.5;Task1(x1,x2,out);x3 = (*out)/2.0;

La variabile out di quest’ultimo esempio è di tipo puntatore a float perché dichiarataattraverso l’operatore * (asterisco) che segue la parola chiave float e precede l’identifi-catore out. In questo contesto si dice che * è un operatore unario di dichiarazione (daritenersi applicato al nome della variabile). Di fatto, la variabile puntatore out contieneun indirizzo di memoria, in particolare punta ad una porzione di memoria adatta a conte-nere un valore di tipo float. Perché la funzione Task1 possa esportare, attraverso out, unvalore verso il codice chiamante essa va definita nel modo seguente:

void Task1(float v1, float v2, float *output){

int j = 7;v1 = -0.02; // modificano variabili scambiatev2 = -j*v1; // per valore (x1 ed x2 non vengono modificate)// ...

*output = huna qualsiasi espressione che dà un floati;}

Le parentesi graffe, { }, esprimono il raggruppamento in C++. In questo caso tali parente-si indicano l’inizio e la fine del corpo della funzione. Si noti come nella definizione dellefunzioni i parametri di scambio possano essere nominati diversamente dalle corrispon-denti variabili passate dal codice chiamante. In questo esempio l’istruzione di chiamata èTask1(x1,x2,out) mentre nella definizione di Task1 si usano i nomi v1, v2 ed output.

Nell’ultima istruzione della definizione di Task1 l’operatore * che precede output èDereferenziazione dellevariabili puntatore usato come operatore unario di dereferenziazione (de-referencing): in pratica esso per-

mette di eseguire un’operazione di inserimento di un valore di tipo float in un’area dimemoria puntata da output. Al termine della funzione Task1, quando il controllo passaal codice chiamante, quest’area di memoria conterrà il valore appena calcolato all’internodi Task1 e ad esso punterà la variabile out. Ecco il senso di aver dichiarato out comepuntatore a float. Nell’istruzione immediatamente successiva del codice chiamante siha x3 = (*out)/2.0 in cui l’operatore * dereferenzia out. In questo caso si dice che con

A. De Marco

Page 15: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.2 Programmazione procedurale 15

*out si esegue un’operazione di estrazione del valore float puntato dalla variabile out.Tale valore viene convenientemente usato nell’istruzione di assegnamento della variabilex3.

In C++ l’operazione opposta di quella di de-referencing è quella cosiddetta di estra- Operatore & diestrazione dell’indirizzozione dell’indirizzo di una variabile. Ciò è realizzato dall’operatore & applicato al nome

di una variabile. Il risultato è un valore che è lecito assegnare ad una variabile di tipopuntatore. Il seguente frammento di codice è perfettamente lecito:

double x = 3.5;double *p = &x;

In linguaggi come il Pascal o il Fortran, ad esempio, le procedure sono distinte dallefunzioni perché non restituiscono un valore associato al nome della procedura stessa, enon possono quindi apparire a destra di una istruzione di assegnazione. Nel linguaggioC, così come nel C++, esiste solo la funzione, che può o meno restituire valori; in praticauna funzione che non restituisce valore è una procedura.

All’interno di un sottoprogramma possiamo generalmente definire delle variabili loca-li, che vengono deallocate al termine del sottoprogramma stesso (variabili automatiche). Variabili locali alle

funzioni ed alleprocedure

Il loro contenuto viene quindi perso se non salvato o trasmesso altrimenti. La variabilej, dichiarata, definita ed usata nella definizione precedente di Task1, è una variabile auto-matica. Essa ha campo di visibilità che si estende alla sola definizione della funzione incui è dichiarata.

Si osservi che secondo lo standard del linguaggio C++ si può limitare il ciclo di vitadi una qualsiasi variabile dichiarandola all’interno di una porzione di codice delimitata dadue parentesi graffe. Il seguente frammento di programma è perfettamente lecito:

double a, b, c;a = 3.5;{

double *p;b = -1.2;p = &a; // & estrae l’indirizzo di a (un possibile valore di p)c = (*p)+b;

}double d = c; // qui p è out-of-scope

In C++ è possibile dichiarare variabili in qualsiasi punto del codice sorgente. Nel punto Definire limiti di visibilitàin C++ attraverso leparentesi graffe

in cui la variabile d è dichiarata ed assegnata il puntatore p non è più visibile. Le parentesigraffe che fissano il ciclo di vita della variabile p definiscono a tutti gli effetti un bloccodi codice. Questo blocco non ha il ruolo di una procedura ma soltanto quello di definirel’inizio e la fine della visibilità delle variabili in esso definite. Va osservato che nell’in-terno del blocco risultano visibili le variabili dichiarate esternamente (nello stesso filesorgente). Alla variabile a viene applicato l’operatore unario & di estrazione di indirizzoper poter assegnare un valore lecito alla variabile locale p, di tipo puntatore a double.

* È interessante esaminare una situazione che si sarebbe avuta se nell’esempio precedente avessimodichiarato all’esterno del blocco, prima delle parentesi graffe, il puntatore p e se, viceversa, avessimo di-chiarato e assegnato la variabile a all’interno del blocco. In quel caso, l’assegnazione p = &a all’internodel blocco sarebbe stata ancora lecita ma stavolta a sarebbe risultata out-of-scope dopo la chiusura dellaseconda parentesi graffa. Al contrario, p sarebbe rimasto ancora in vita. In una situazione del genere siparla di dangling reference (riferimento penzolante), cioè il valore del puntatore è quello di un indirizzo Dangling reference

non più corrispondente ad a ma ad un’area di memoria probabilmente destinata ad un uso diverso.

Appunti di programmazione a oggetti in C++ e Matlab

Page 16: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

16 Capitolo 1 Tecniche di programmazione supportate dal C++

Il concetto di ambito visibilità limitato ad un blocco trova riscontro, ad esempio, neiLimiti di scope pervariabili definite

all’interno dei ciclicostrutti ciclici. Si esamini il seguente frammento di programma:

int k = 1;float v = 1.5;float *pf;for(unsigned int i=0; i<10; i++){

float w;w = (k++)*v - 1.0;Task1(v, w, pf);// stampa sul canale di output standardcout << "Task1 restituisce: " << *pf << endl;

}// qui i e w sono out-of-scope

Sia la variabile intera i, che serve da contatore delle iterazioni, che la variabile w cheviene passata a Task1 sono inaccessibili all’esterno delle parentesi che delimitano il ciclodi for. Si dice che esse sono out-of-scope. Si noti come la variabile v, che prima vieneusata per assegnare w e poi viene passata a Task1, sia visibile all’interno del ciclo. Lostesso dicasi per la variabile pf.

Dal punto di vista dell’organizzazione del programma le funzioni vengono utilizzateper creare ordine in una selva di algoritmi. Gli algoritmi stessi sono scritti utilizzan-do chiamate di funzioni e altri strumenti del linguaggio. Il progetto di un programmaDesign dei programmi

secondo l’approccioTop-Down

secondo il paradigma della programmazione procedurale segue un approccio di tipo Top-Down: si individuano i passi fondamentali dell’algoritmo che il programma deve eseguiree per ognuno si sviluppa un’apposita procedura; ciascuna procedura, a seconda della suacomplessità, viene a sua volta sviluppata secondo lo stesso criterio.

1.2.3 Hello world!

Il programma più piccolo che si possa scrivere in C++ è:Funzione main

int main() { }

Definisce una funzione che si chiama main, la quale non prende argomenti e non fa nulla.Ogni programma C++ deve avere una funzione che si chiama main. Il programma iniziaeseguendo quella funzione. Il valore di tipo int restituito da main, se esiste, è il valore cheil programma restituisce al “sistema”. Se non viene restituito alcun valore, il sistema nericeverà (secondo lo standard ISO) uno che indica una terminazione corretta. Un valorediverso da zero restituito da main indica una terminazione non corretta. La funzione main

è una funzione speciale che, in C come in C++, si interfaccia con il sistema operativo edè detta, tecnicamente, entry point del programma eseguibile.

Tipicamente un programma produce qualche messaggio. Ecco un programma chescrive il famoso tormentone “Hello world!” sul canale di output standard:I/O standard con

iostream

#include <iostream>int main(){

std::cout << "Hello world!\n" ;}

A. De Marco

Page 17: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.2 Programmazione procedurale 17

La riga #include <iostream> dice al compilatore di includere le dichiarazioni dellefunzioni standard per l’ingresso/uscita (I/O) su canali di caratteri (stream) che si trovanonel file iostream. Senza queste dichiarazioni l’espressione std::cout << "Hello world

!\n" non avrebbe senso. L’operatore << (“metti su”) scrive il suo secondo argomento(quello alla sua destra) sul primo. In questo caso si ha che la stringa letterale "Hello

world!\n" viene scritta sul canale di uscita predefinito std::cout, tipicamente, una fine-stra di console. Una stringa letterale del C++ è una sequenza di caratteri delimitata dadoppie virgolette. In una stringa letterale il carattere \ (barra inversa) seguito da un altrocarattere denota un singolo carattere speciale. In questo caso \n è il carattere di fine riga(newline) cosicché i caratteri stampati sono "Hello world!" seguiti da un fine riga.

1.2.4 Un semplice programma C++ con procedure

Rispetto al semplicissimo esempio precedente si può fare molto di più. Ecco un esempiodi semplice programma in C++ decomposto in procedure e funzioni.// Forward declarationsbool options(const int, const char**);void PrintHelp(void);void Task1(void);void Task2(void);

// Global dataconst char *hostname = "localhost";int port = 5501;realtime = false;

int main(const int argc, const char *argv[]){

bool success = false;

// *** PARSE COMMAND LINE OPTIONS *** //success = options(argc, argv);if (!success) {

PrintHelp();exit(-1);

}realtime = true;

// *** EXECUTE TASKS *** //Task1();Task2();

return 0;}// Define here functions: options, PrintHelp, Task1, Task2// ...

Qui la main, oltre che a ritornare un valore al sistema, ne riceve due: argc e argv (inomi di questi due argomenti sono quelli usati dalla maggior parte dei programmi). Piùavanti si approfondirà quest’aspetto con un esempio più dettagliato. Qui basta sapere i dueargomenti di main, passati alla funzione dal sistema operativo, permettono al programmadi risalire alla riga di comando completa utilizzata dall’utente per lanciarne l’esecuzione.

Appunti di programmazione a oggetti in C++ e Matlab

Page 18: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

18 Capitolo 1 Tecniche di programmazione supportate dal C++

Il programmatore ha predisposto in questo caso la funzione options che prende di-rettamente in consegna gli argomenti di main e li elabora restituendo un valore booleano.Un valore vero ritornato da options dovrebbe indicare una riga di comando ben scritta(lecita). In caso contrario viene invocata la procedura PrintHelp, che non ha bisogno diritornare alcun valore perché probabilmente scriverà semplicemente una serie di messag-gi sul canale di output standard. Per come è fatta qui la funzione main, ad una riga dicomando non lecita corrisponde la stampa di un testo di aiuto e l’interruzione immediatadell’esecuzione tramite la funzione exit (il cui argomento -1 viene ritornato al sistema).Se il controllo del flusso di operazioni del programma supera la fase di lettura della riga dicomando, allora verranno eseguite le procedure Task1 e Task2, e verrà restituito al sistemaun valore di ritorno nullo con l’istruzione return 0.

Il programmatore è evidentemente abbastanza sicuro che queste ultime non diano luo-go a condizioni “eccezionali”, non preoccupandosi (apparentemente) di controllarne l’e-sito. Le due funzioni probabilmente assolvono a compiti semplici e non c’è bisogno cheritornino valori.

Questo programma, che può essere memorizzato, ad esempio, in un file main.cpp,è ovviamente incompleto. Andrebbero definite nello stesso file le funzioni options,PrintHelp, Task1, Task2, soltanto dichiarate prima della definizione della funzione main

(le cosiddette forward declarations). Tra queste solo la funzione options ritorna un va-lore, che è di tipo bool; le altre sono a tutti gli effetti delle procedure: esse definisconodelle variabili interne ed, al più, manipolano delle variabili globali come hostname, porte realtime. In questo caso, le variabili globali sono quelle definite all’esterno di tuttefunzioni definite nel file main.cpp. Esse vengono assegnate tipicamente in sede di di-chiarazione (quasi sempre all’inizio del file, prima della definizione di main) e risultanovisibili ovunque nel file sorgente (hanno global scope). In particolare le variabili globaliverranno usate nelle definizioni delle singole funzioni utilizzate da main.

1.3 Programmazione modulare

Nel corso degli anni, l’enfasi nella progettazione dei programmi si è spostata dal progettodelle procedure all’organizzazione dei dati. Tra le altre cose, questo riflette un un aumentodella dimensione dei programmi. Un insieme di procedure correlate e dei dati da essemanipolati è spesso chiamato un modulo. Il paradigma della programmazione modulareè dunque:

Decidi quali moduli ti occorrano;suddividi il programma in modo che i datisiano nascosti all’interno dei moduli.

Questo paradigma è anche noto come il principio di occultamento dei dati (data hi-Il principio dioccultamento dei dati ding). Nei problemi la cui soluzione può essere modellata senza raggruppare necessaria-

mente le procedure ed i dati che esse manipolano lo stile di programmazione procedu-rale risulta sufficiente. Quando viene applicato il paradigma modulare le tecniche per ilprogetto di “buone procedure” sono da applicarsi per ogni procedura in un modulo.

Se i dati sono occultati nei moduli ma, allo stesso tempo, per la costruzione deglialgoritmi vi è necessità di far interagire i moduli di programma gli uni con gli altri —

A. De Marco

Page 19: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.3 Programmazione modulare 19

scambiando dati fra di loro —, nasce l’esigenza di concepire le procedure e le funzioni diciascun modulo come delle interfacce con l’esterno (interfacce utente). Inoltre, è neces-sario permettere di accedere alla rappresentazione dei dati di un modulo solo attraversol’interfaccia stabilita dal programmatore ed assicurare che i moduli inizializzino i lorodati prima che questi vengano usati.

1.3.1 Creare moduli attraverso gli spazi dei nomi

Il C++ fornisce un meccanismo per raggruppare dati, funzioni ed altre entità che siano ad La parola chiavenamespaceessi correlate. Questo tipo di raggruppamento viene effettuato creando i cosiddetti spazi

dei nomi (o namespace) attraverso la parola chiave namespace.Per comprendere il ruolo di un namespace si pensi ad un modulo con il quale il pro-

grammatore si prefigge di gestire e calcolare le caratteristiche aerodinamiche di un’ala.In C++ si potrà scrivere:

namespace Wing // interfaccia{

bool defGeometry(string);void setAlpha(double);void setMach(double);void calculate(void);double getCL(void);double getCD();

}

Questa è l’intefaccia del modulo Wing. Si intuisce che la funzione defGeometry serve a Interfaccia di un modulo

configurare i dati geometrici dell’ala e che le funzioni setAlpha e setMach servono adassegnare delle grandezze che definiscono la corrente che investe il corpo aerodinamico(˛ e M1). La funzione calculate è probabilmente destinata ad effettuare i calcoli piùimportanti e ad assegnare valore ad alcune variabili interne al modulo Wing. Tra queste vicompariranno, ad esempio quelle che contengono i valori dei coefficienti di portanza e diresistenza (CL e CD). Un frammento di codice che usa questo modulo potrebbe essere il Codice utente di un

moduloseguente:

if ( Wing::defGeometry("wing_geometry_1.xml") )printf("Errore nel file di configurazione della geometria!\n");

else {Wing::setAlphaDeg(3.0);Wing::setMach(0.5);Wing::calculate();printf(" CL = %f \n CD = %f \n", Wing::getCL(), Wing::getCD());

}

La dicitura Wing:: preposta ai nomi delle funzioni indica che queste appartengonoallo spazio dei nomi Wing. Altri usi di questi stessi nomi non interferiscono e non causanoconfusione. Ad esempio l’uso del solo nome calculate potrebbe riferirsi ad un’altrafunzione, definita per uno scopo diverso da quello previsto dal programmatore per Wing::calculate. Nel gergo del C++ si dice che qui i :: (doppio due punti) sono usati comeoperatore di risoluzione di visibilità; la funzione calculate del namespace Wing risultavisibile all’esterno del modulo come Wing::calculate.

La definizione del modulo Wing —cioè la sua “implementazione” — potrebbe essere Implementazione di unmodulofornita in una parte del programma compilata separatamente:

Appunti di programmazione a oggetti in C++ e Matlab

Page 20: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

20 Capitolo 1 Tecniche di programmazione supportate dal C++

namespace Wing // implementazione{

double referenceSurface, span, aspectRatio, taperRatio, leSweep,dihedral, geomTwist, aeroTwist;

double alpha, Mach;double CL, CD;const int max_size = 200;double y[max_size];bool defGeometry(string filename){hlegge il file di configurazione in formato XMLireturn hesito della lettura filei;

}void setAlphaDeg(double val){ alpha = val/57.3; }void setMach(double val){ mach = val; }void calculate(void){hesegue i calcoli aerodinamicii// verranno assegnate e manipolate le y[i]// verranno assegnati CL e CD

}double getCL(void){ return CL; }double getCD(void){ return CD; }

}

Il punto chiave riguardo al namespace Wing è che l’interfaccia esterna risulta isolatadalla struttura dati sottostante. In questo caso i dati occultati all’interno del modulo so-no le variabili double dichiarate all’inizio dell’implementazione ed assegnate nelle variefunzioni appartenenti al namespace. I dati ed il codice delle funzioni del modulo rappre-sentano Wing. L’utente non ha bisogno di conoscere i dettagli di come sono gestiti i datiall’interno di Wing. L’implementazione del modulo può essere modificata — ad esempio,potrebbe essere migliorata la funzione calculate — senza che il codice utente ne siainfluenzato.

Poiché i dati sono solo una delle cose che si può volere “nascondere”, la nozionedi occultamento dei dati viene estesa facilmente a quella, più generale, di occultamentodell’informazione; ovvero, così come i nomi delle funzioni, anche i nomi dei tipi e di altrielementi del linguaggio possono essere resi locali a un modulo. Di conseguenza, il C++permette di collocare qualsiasi dichiarazione in un namespace.

1.3.2 Lo spazio dei nomi della libreria standard

Il C++ è dotato di una libreria standard che mette a disposizione dei programmatori ungran numero di funzionalità. La libreria standard è usabile in ogni implementazionecompleta del C++, cioè con ogni sistema di compilazione che sia standard compliant,e permette di scrivere codice portabile.

La libreria standard è definita in uno spazio dei nomi chiamato std. Per questo motivosi scrive std::cout invece che cout, cioè per essere espliciti nell’usare il cout standardinvece che qualche altro cout. Anche il nome std::endl è definito nella libreria standarde coincide con il carattere di newline ’\n’.

Ogni funzionalità della libreria è fornita tramite qualche file header simile al fileiostream. Per esempio:

A. De Marco

Page 21: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.3 Programmazione modulare 21

#include <string>#include <list>

rendono disponibili le classi standard string e list. Per usare queste classi al di fuoridel namespace std si dovrebbe usare il prefisso std::

std::string s = "A che ora si cena?";std::list<std::string> phrases;

Per semplicità il prefisso std:: può essere omesso a patto di dichiarare l’uso globaledello spazio dei nomi std così:

using namespace std ;

Questa dichiarazione può essere fatta, ad esempio, ad un livello globale subito dopo ledirettive #include. Si dice allora che il nome di namespace std è trasferito nel namespaceglobale. Ad esempio:

#include <string>using namespace std;string s = "Perche’ sprecare tempo a imparare? L’ignoranza e’ immediata!";

È generalmente uno stile sconsigliato quello di trasferire nel namespace globale tutti inomi di un namespace. Spesso in questo documento, per abbreviare i pezzi di programmiusati per illustrare le caratteristiche del linguaggio e della libreria, sono omesse le ripe-tizioni delle direttive #include e delle specifiche di std::. Si capisce dal contesto chealcune funzionalità hanno senso solo se vengono lette le opportune dichiarazioni da fileheader di libreria e se vengono resi globali alcuni nomi del namespace std.

1.3.3 Compilazione separata

Il C++ supporta la nozione del C di compilazione separata. Questa può essere usata perorganizzare il programma in un insieme di frammenti semi-indipendenti.

Tipicamente, nella programmazione modulare si collocano le dichiarazioni che spe-cificano l’interfaccia di un modulo in un file che un nome che indica l’uso a cui esso èpreposto. Ad esempio, le dichiarazioni di interfaccia di Wing sarebbero collocate nel fileWing.h:

//----------------------------------------// File: Wing.h//----------------------------------------namespace Wing // interfaccia{

bool defGeometry(string);void setAlpha(double);void setMach(double);void calculate(void);double getCL(void);double getCD();

}

e gli utenti dovrebbero includere (direttiva #include) tale file così:

//----------------------------------------// File: user.cpp//----------------------------------------

Appunti di programmazione a oggetti in C++ e Matlab

Page 22: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

22 Capitolo 1 Tecniche di programmazione supportate dal C++

#include "Wing.h" // ottiene l’interfaccia

void f(){

if ( Wing::defGeometry("wing_geometry_1.xml") )printf("Errore nel file di configurazione della geometria!\n");

else {Wing::setAlphaDeg(3.0);Wing::setMach(0.5);Wing::calculate();printf(" CL = %f \n CD = %f \n", Wing::getCL(), Wing::getCD() );

}}

Per aiutare il compilatore ad assicurare la consistenza, il file che fornisce l’implemen-tazione del modulo Wing, Wing.cpp, includerà anche l’interfaccia://----------------------------------------// File: Wing.cpp//----------------------------------------#include "Wing.h" // ottiene l’interfaccia

namespace Wing // rappresentazione{

double referenceSurface, span, aspectRatio, taperRatio, leSweep,dihedral, geomTwist, aeroTwist;

double alpha, Mach;double CL, CD;const int max_size = 200;double y[max_size];

}

// implementazione dell’interfacciabool Wing::defGeometry(string filename){ /* ... */ }void Wing::setAlphaDeg(double val){ alpha = val/57.3; }void Wing::setMach(double val){ mach = val; }void Wing::calculate(void){ /* ... */ }double Wing::getCL(void){ return CL; }double Wing::getCD(void){ return CD; }

Il codice utente va inserito in un terzo file, per esempio user.cpp. I codici in user.cpp

e Wing.cpp condividono le informazioni relative all’interfaccia presentate in Wing.h, mai due file sono indipendenti sotto tutti gli altri punti di vista e possono essere compilatiseparatamente.

La compilazione separata è una questione che riguarda tutti i programmi reali. Nonè semplicemente di pertinenza dei programmi che forniscono servizi, come Wing, sottoforma di moduli. A rigor di termini, l’uso della compilazione separata non è tanto unaquestione di linguaggio, quanto piuttosto di avvalersi al meglio di una particolare imple-mentazione del linguaggio (cioè di un particolare sistema di compilazione, ad esempiol’infrastruttura dei compilatori di sistema di Linux oppure un particolare ambiente di svi-luppo integrato). Ciononostante, la compilazione separata è di grande importanza dalpunto di vista pratico. Il miglior approccio consiste nel massimizzare la modularità —cioè creare per quanto è possibile, specialmente in programmi di una certa dimensione,tanti moduli gerarchicamente organizzati —, rappresentare tale modularità dal punto di

A. De Marco

Page 23: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.3 Programmazione modulare 23

vista logico per mezzo delle funzionalità del linguaggio e sfruttarla dal punto di vistafisico per mezzo di file, per permettere un’efficace compilazione separata.

1.3.4 Gestione delle eccezioni

Un programma, spesso, dopo il rilevamento di un errore deve essere concluso, perchénon è possibile immaginare una maniera sensata di continuarlo. Ciò può essere ottenutochiamando exit(), che per prima cosa ripulisce le risorse in uso come gli stream di outpute poi conclude il programma restituendo il valore del suo argomento. Meccanismi digestione degli errori più sofisticati possono realizzarsi con l’uso delle eccezioni, ma perun programma di meno di 150 righe è più che sufficiente l’uso di messaggi d’errore edella funzione exit().

Quando un programma è progettato come un insieme di moduli, la gestione degli erro-ri deve essere presa in considerazione alla luce dell’organizzazione modulare. Va stabilitoquale modulo è responsabile di un certo tipo di errore. Spesso il modulo che individua unerrore non sa quale azione intraprendere. L’azione di ripristino dipende dal modulo che hainvocato l’operazione piuttosto che dal modulo che ha riscontrato l’errore mentre cercavadi eseguire tale operazione. Man mano che i programmi crescono, e specialmente quandoviene fatto uso estensivo di librerie scritte da altri, diventano importanti degli standard digestione dell’errore e, più in generale, delle “circostanze eccezionali”.

Si consideri ancora l’esempio di Wing. Cosa dovrebbe essere fatto quando cerchiamodi caricare dal file wing_geometry_1.xml i dati geometrici dell’ala e si verifica un erroredovuto ad un formato inatteso? Chi ha scritto il modulo Wing non sa cosa l’utente vorrebbefosse fatto in un caso simile. L’utente, d’altro canto, non può individuare il problema inmaniera coerente (se avesse potuto, avrebbe fatto in modo da evitare l’errore di lettura).La soluzione è che chi ha implementato Wing individui l’eventualità di un errore di letturada file e quindi lo comunichi all’utente (sconosciuto). A questo punto il codice utente puòessere modellato in modo di intraprendere l’azione appropriata. Per esempio:

//----------------------------------------// File: Wing.h//----------------------------------------namespace Wing // interfaccia{

bool defGeometry(string);void setAlpha(double);void setMach(double);void calculate(void);double getCL(void);double getCD();

class BadFormatFile { /* ... */ }; // tipo che rappresenta le eccezioni// relative agli errori di lettura// dati da file

}

in cui compare per la prima volta la parola chiave class che in C++ serve in generalea definire nuovi tipi. In questo caso si definisce il tipo badConfigFile all’interno delnamespace.

Appunti di programmazione a oggetti in C++ e Matlab

Page 24: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

24 Capitolo 1 Tecniche di programmazione supportate dal C++

Quando riscontra un errore di lettura da file, Wing::defGeometry può invocare il co-dice di gestione dell’errore, ovvero, si dice che essa “può sollervare un’eccezione di tipoWing::BadConfigFile”:bool Wing::defGeometry(string filename){

bool goodFormat = false;bool goodData = false;hfunzione che apre e legge il file di input in formato XMLi;// goodFormat e gooddata vengono opportunamente assegnateif (!goodFormat) throw BadFormatFile();// ...return goodData;

}

Si noti che nell’ultimo frammento di codice si possono verificare due situazioni da ge-stire come errori: una è la possibile incompletezza dei dati presenti nel file filename

(ad esempio chi ha composto il file XML ha dimenticato di inserire il dato dell’aperturaalare), l’altra è l’eventuale cattivo formato del file. Nel primo caso la funzione Wing::

defGeometry ritorna un valore falso e spetta al codice utente preoccuparsi di controllarlo.Il secondo caso è quello di cui qui ci stiamo occupando come situazione eccezionale (inrealtà entrambe le situazioni sono di questo tipo ma qui ci piace far vedere come le dueeventualità possono essere trattate in modo separato).

L’istruzione throw trasferisce il controllo del programma da quel punto (e non all’u-scita della funzione) ad un gestore delle eccezioni di tipo Wing::BadFormatFile definitoin qualche funzione che ha invocato, direttamente o indirettamente, Wing::defGeometry.Per fare ciò il compilatore ha predisposto meccanismi che permettono al flusso del pro-gramma di risalire la catena di invocazioni fino a tornare al contesto del chiamante. Quindisi dice che “l’istruzione throw si comporta come un return multilivello”. Per esempio://----------------------------------------// File: user.cpp//----------------------------------------#include "Wing.h" // ottiene l’interfaccia

void f() {// ...try { // qui le eventuali eccezioni sono gestite

// dal gestore definito sotto (catch)if ( Wing::defGeometry("wing_geometry_1.xml") )

printf("Dati mancanti nella configurazione geometrica!\n");else {

Wing::setAlphaDeg(3.0);Wing::setMach(0.5);Wing::calculate();printf(" CL = %f \n CD = %f \n", Wing::getCL(), Wing::getCD());

}}catch (Wing::BadFormatFile) { // gestore dell’eccezione

// oops: errore di formato// intraprendere l’azione appropriata// ...

}}

A. De Marco

Page 25: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 25

Se vi è un errore di formato nel file wing_geometry_1.xml l’istruzione

if ( Wing::defGeometry("wing_geometry_1.xml") )

prima ancora di pervenire ad un valore di ritorno nell’espressione condizionale, solleveràl’eccezione. Pertanto, la clausola catch, che fornisce un gestore per l’eccezione di tipoWing::BadFormatFile, viene necessariamente eseguita dopo l’operazione di lettura da fileche ha causato un throw dall’interno della funzione Wing::defGeometry.

L’uso di meccanismi di gestione delle eccezioni può rendere la gestione degli erroripiù regolare e leggibile e si presta in maniera appropriata alla programmazione modu-lare. Quando un programma è composto da moduli separati, e soprattutto se i moduliprovengono da librerie sviluppate da altri programmatori, la gestione degli errori va ne-cessariamente suddivisa in due parti: (i) la segnalazione di condizioni di errore che nonpossono essere risolte localmente e (ii) la gestione degli errori identificati altrove. L’au-tore di una libreria può identificare errori in fase di esecuzione, ma generalmente non saquale operazione intraprendere. l’utente della libreria, invece, sa come reagire all’errore,ma non è in grado di identificarlo — altrimenti l’errore sarebbe stato gestito dal codiceutente e non lasciato alla libreria.

Le eccezioni sono il meccanismo che il C++ impiega per separare la gestione degli er-rori dalla segnalazione degli errori. Se le istruzioni inserite in un blocco try, o le funzioniivi chiamate, sollevano un’eccezione, viene esaminata la parte di gestione dell’eccezione.Se l’eccezione sollevata è di un tipo trattato da un gestore di eccezioni, tale gestore vieneeseguito. In caso contrario i gestori di eccezione vengono ignorati e il blocco try si com-porta come un blocco ordinario. se viene sollevata un’eccezione e nessun blocco try latratta, il programma termina.

Fondamentalmente il trattamento delle eccezioni in C++ è un modo di trasferire incontrollo a una determinata parte della funzione chiamante. Quando serve, possono esserepassate al chiamante alcune informazioni sull’errore.

1.4 Astrazione dei dati

La modularità è un aspetto fondamentale di qualsiasi programma che non sia tanto sem-plice da esaurirsi in meno di un centinaio di righe ed in un solo file. Quest’aspetto diventavia via più importante al crescere delle dimensioni dei programmi e del numero di file cheli compongono. Nella progettazione delle applicazioni di successo la modularità diventaun fattore chiave. Ciononostante, la sola suddivisione del software in moduli può risultareinsufficiente ad esprimere in maniera pulita sistemi complessi.

Per fare ciò si deve passare alla nozione di tipi definiti dall’utente che rappresentanola caratteristica fondamentale messa a disposizione dal C++. I tipi che un programmatoreC++ può costruire a piacimento (seppur rispettando un insieme di regole, se non vuolecombinare pasticci) permettono di definire variabili che hanno un ciclo di vita del tuttosimile a quello delle variabili dei tipi predefiniti.

1.4.1 Tipi definiti dall’utente

Il C++ consente di definire direttamente un nuovo tipo che si comporta (pressoché) allostesso modo di un tipo predefinito come int o double. Qualcuno chiama i tipi definiti

Appunti di programmazione a oggetti in C++ e Matlab

Page 26: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

26 Capitolo 1 Tecniche di programmazione supportate dal C++

da utente “tipi di dati astratti”, ma c’è chi osserva che, probabilmente, è meno fuorviantechiamarli tipi definiti dall’utente. Anzi, come vedremo poco più avanti, un nuovo tipo didato può anche essere confezionato in modo tale da essere chiamato tipo concreto.

Il paradigma di programmazione che utilizza i tipi definiti dall’utente diventa:

Decidi quali tipi ti occorrano;fornisci un insieme completo di operazioni per ogni tipo.

Nei casi in cui non c’è necessità di usare più di un oggetto di un dato tipo, lo stile diprogrammazione modulare basato sull’occultamento dei dati per mezzo dei moduli restasufficiente.

Un esempio immediati di possibile tipo definito dall’utente è quello che rappresentaun numero complesso. Come è noto, i numeri complessi hanno una parte reale ed unaimmaginaria ed hanno una loro aritmetica; e già questo permette di “astrarre” questecaratteristiche peculiari in un nuovo tipo di dato a partire dal tipo predefinito double. InC++ si può definire il tipo complex per mezzo della parola chiave class scrivendo, perParola chiave class

esempio:

class complex {double re, im;

public:complex(double x, double y) { re=x; im=y; } // costruisce un complesso

// da due scalaricomplex(double x) { re=x; im=0; } // costruisce un complesso

// da uno scalarecomplex() { re=0; im=0; } // costruisce il complesso

// di default (0,0)

double real() const { return re; } // estrae parte realedouble imag() const { return im; } // estrae parte immaginaria// ... eventuali altre operazioni possibili

};

Questa è la dichiarazione di una classe complex, cioè di un tipo di dato definito dall’utente,che specifica la rappresentazione di un numero complesso e di alcune operazioni ad essoapplicabili (si noti il ; dopo la fine del blocco di dichiarazioni). La rappresentazioneconsiste semplicemente nei due dati double contenuti nelle variabili re ed im. SecondoRappresentazione

privata dei dati le regole del C++ la posizione in cui compaiono le dichiarazioni di queste due variabilile rende di default dei dati privati, cioè accessibili solo dalle funzioni specificate dallaclasse complex. I dati che sono in dotazione ad una particolare classe si dicono proprietàVariabili membro

o variabili membro.

* In questa dichiarazione, oltre alla rappresentazione privata di complex dovrebbe colpire la specifica diben tre funzioni che hanno lo stesso nome della classe, senza valore di ritorno e ciascuna con una listadifferente di argomenti. Esse si dicono i costruttori della classe ed offrono all’utente la possibilità di crearevariabili di tipo complex in vari modi. Se ne parlerà tra poco.

In C++ si può dichiarare esplicitamente che delle variabili e delle funzioni sono privatecon la clausola chiave private:. Ecco come un programmatore riscriverebbe la classecomplex:

class complex {public:

A. De Marco

Page 27: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 27

// costruttoricomplex(double x, double y) { re=x; im=y; }complex(double x) { re=x; im=0; }complex() { re=0; im=0; }// funzioni membro pubblichedouble real() const { return re; }double imag() const { return im; }// ...

private:double re, im;complex fmp(void);// ...

};

In questo caso si ha anche la dichiarazione privata di una funzione, la fmp(), all’internodella classe. le funzioni incorporate nei tipi definiti dall’utente vengono chiamate metodi Funzioni membro

o funzioni membro, possono operare sulle variabili membro ed eventualmente accettaredegli argomenti.

Essa è solo dichiarata nella parte privata della classe e può essere definta altrove (aldi fuori del blocco di dichiarazioni di complex o in un altro file). Potrebbe aversi, peresempio:

// qui la classe complex e la funzione sqrt// devono risultare dichiarate// ...complex fmp(void) {

double a = (re - im);double b = sqrt(re*re - im*im);return complex(a,b);

}

Si noti come le funzioni membro possano accedere alla rappresentazione della classe acui appartengono. Le variabili private re ed im sono visibili dall’interno della definizionedi fmp() (sarebbero addirittura modificabili, ma è assolutamente sconsigliabile in un casodel genere). Inoltre, nell’ultima istruzione di fmp() si “costruisce al volo” un oggetto ditipo complex a partire da due scalari e lo si consegna all’istruzione return.

Una funzione membro con lo stesso nome della classe di appartenenza viene chiamata Il costruttore di unaclassecostruttore. Un costruttore definisce un modo per inizializzare un oggetto della sua classe.

La classe complex fornisce tre costruttori. Significa che gli utenti hanno tre possibilitàdiverse per inizializzare un complex: lo si può creare a partire da una coppia di double, apartire da un double oppure si può creare un complex con un valore di default. In pratica,il costruttore è una funzione definita più volte con liste di argomenti diverse. Quando ciò Overloading delle

funzioniavviene per le funzioni si dice che esse sono “sovraccaricate” (function overloading).

* L’overloading delle funzioni è una delle caratteristiche più potenti ed allo stesso tempo più delicate delC++. Questa funzionalità è dovuta al controllo rigoroso dei tipi.

Come si è certamente notato, le due funzioni membro real() e imag() sono pubbli-che e corrispondono alle operazioni di estrazione della parte reale e della parte immagi-naria del numero complesso. I metodi pubblici sono espressione dell’interfaccia del tipocomplex verso i suoi utenti. Ad esempio:

void nice_printc(complex z) {cout << "Parte reale: " << z.real() << ", "

Appunti di programmazione a oggetti in C++ e Matlab

Page 28: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

28 Capitolo 1 Tecniche di programmazione supportate dal C++

<< "Parte immaginaria: " << z.imag() << "\n";}

int main(void) {double x = 0.0, y = 0.0;for(int k=0; k<10; k++){ // stampa 10 numeri complessi

x = x + k*0.2;y = x*x*x;complex w = complex(x,y);nice_printc(w);

}}

Il codice della funzione nice_printc accede (in sola lettura, parola chiave const nelledefinizioni di real e di imag) alla rappresentazione dell’argomento z, una variabile ditipo complex, attraverso le due funzioni membro pubbliche. L’invocazione di tali funzioniviene fatta attraverso l’operatore . (punto) applicato alla variabile z.

Fino a questo punto l’utilità della classe complex sembra limitata. L’utente può co-struire complessi ed al massimo usarne la parte reale e immaginaria. Anche una funzionemembro privata come fmp(), se non usata direttamente o indirettamente da qualche me-todo pubblico sembra del tutto inutile. In effetti ha senso definire un nuovo tipo se, oltrea raggruppare convenientemente dei dati, si riescono a definire anche delle operazioni sudi essi che permettano all’utente di costruire efficientemente dei sistemi più complessi.

Nel caso di complex ciò significa allargare lo spettro di funzioni, oltre a real() edimag(), che diano ai suoi utenti la possibilità di compiere delle operazioni complesse.Non è detto, in realtà, che queste nuove funzioni debbano necessariamente far parte dellaclasse. Esse potranno semplicemente essere “accreditate” ad usare i suoi dati privati. InC++ questa possibilità è data dalla parola chiave friend. Si può pensare, ad esempio, aduna funzione sumc che permetta di sommare due complessi. Si dichiarerà all’interno dellaclasse:

class complex {public:

// costruttori ....// funzioni membro pubbliche// ...friend complex sumc(complex z1, complex z2);// ...

private:// ...

};

ed altrove si definirà:

complex sumc(complex z1, complex z2) {return complex( z1.re + z2.re, // sumc ha accesso alle

z1.im + z2.im ); // variabili private}

Qui l’operatore . (punto) applicato agli argomenti z1 e z2 permette di accedere diretta-mente ai valori delle variabili membro private. Questo meccanismo è permesso dal fattoche sumc è stata dichiarata come funzione friend (amica) della classe. L’operazione disomma di due complessi è usata da questo frammento di codice:

A. De Marco

Page 29: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 29

complex u(1.0), w(0,1.0);nice_printc( sumc(u,w) );

Il valore ritornato da sumc è di tipo complex e viene passato a nice_printc che stampa inbella forma il risultato della somma.

Il C++ offre anche qualcosa di meglio rispetto a questa situazione. È possibile infattidefinire delle funzioni che vengono invocate in maniera appropriata quando in un’espres-sione aritmetica compaiono variabili di tipo complex. Questo permetterebbe al program-matore di scrivere del codice come quello seguente:

complex u(1.0), w(0,1.0);complex z1, z2;z1 = 3.5 * u - w; // prodotto per scalare e sommaz2 = complex(-1,-1) + z1*z1 + z1/z2; // prodotto e divisionebool sure = ( z1 != z2 ); // confronto (!= significa: e’ diverso da?)

Per permettere un uso legale di queste operazioni bisogna estendere, al livello del lin-guaggio, l’uso degli operatori aritmetici +, - (sia binario che unario), *, / e degli operatoribinari booleani == e != di uguaglianza e differenza. Tecnicamente si dice che bisogna“sovraccaricare” questi operatori (operator overloading, così come avviene per le fun- Overloading degli

operatorizioni) attraverso delle funzioni opportune. Il compilatore farà in modo di invocare que-ste ultime se nelle espressioni aritmetiche troverà dei dati di tipo complex. In C++ lefunzioni che permettono l’overloading degli operatori devono avere un nome del tipo:operatorhoperatorei.

Una più conveniente dichiarazione della classe complex sarà:

class complex {public:

// costruttoricomplex(double x, double y) { re=x; im=y; }complex(double x) { re=x; im=0; }complex() { re=0; im=0; }// funzioni membro pubblichedouble real() const { return re; }double imag() const { return im; }// funzioni amichefriend complex operator+(complex, complex);friend complex operator-(complex, complex); // binariofriend complex operator-(complex); // unariofriend complex operator*(complex, complex);friend complex operator/(complex, complex);friend complex operator+(double, complex); // mistofriend complex operator+(complex, double); // mistofriend complex operator-(double, complex); // mistofriend complex operator-(complex, double); // mistofriend complex operator*(double, complex); // mistofriend complex operator*(complex, double); // mistofriend complex operator/(double, complex); // mistofriend complex operator/(complex, double); // misto

friend bool operator==(double, complex); // uguaglianzafriend bool operator!=(complex, double); // differenza// ...

private:

Appunti di programmazione a oggetti in C++ e Matlab

Page 30: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

30 Capitolo 1 Tecniche di programmazione supportate dal C++

double re, im;// ...

};

dove sarà:

complex operator-(complex z1, complex z2) // es.: u-w{

return complex( z1.re-z2.re, z1.im-z2.im );}complex operator-(complex z) // es.: -w{

return complex( -z.re, -z.im );}complex operator-(double x, complex z2) // es.: 2.1-w{

return complex( x-z2.re, -z2.im );}//... e cosi’ via

Siccome l’appetito vien mangiando, sembra naturale realizzare anche l’overloading diun operatore come <<, per l’inserimento di un complex nell’oggetto predefinito cout. Inquesto modo il programmatore può fare a meno della funzione nice_printc ed utilizzarein un modo uniforme il meccanismo di output standard dei caratteri anche se c’è da stam-pare un nuovo tipo di dato. L’operatore di inserimento vuole alla sua destra l’indirizzo dimemoria di un oggetto di tipo std::ostream messo a disposizione dalla libreria standard.Si può scrivere allora:

#include <iostream>using namespace std;

class complex; // Class forward declaration

ostream& operator<<(ostream& s, const complex& z){

// inserisce tipi predefiniti e poi ritorna sreturn s << ’(’ << z.real() << ’,’ << z.imag() << ’)’;

}

int main(){

complex x(1,2), y(-2,0.5), z;y += x; // aggiunge x ad y, poi riassegna ad yz = 8.5*x-y/x;cout << "x = " << x << ’\n’

<< "y = " << y << ’\n’<< "z = " << z << ’\n’;

return 0; // ridondante in ISO C++}

Il nome std::cout è il nome predefinito dell’indirizzo di un oggetto di tipo std::ostream.Il compilatore converte gli operatori che coinvolgono numeri complex in opportune

invocazioni di funzioni. Per esempio, x!=y cignifica operator!=(x,y) e 1/z significaoperator/(1,z).

In C++ la dichiarazione

A. De Marco

Page 31: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 31

class complex; // Class forward declaration

posta, ad esempio, all’inizio di un file, serve ad asserire (ad un livello di visibilità globale) Dichiarazione anticipatadi una classeche nel resto del file, in una o più definizioni di funzione che seguiranno, sarà allocato un

oggetto di tipo complex. Qui la parola chiave class è usata in una dichiarazione.

1.4.2 Tipi concreti

I tipi definiti dall’utente possono essere progettati in modo da soddisfare un’ampia varietàdi esigenze. Il tipo complex visto in precedenza è solo un esempio e rappresenta un primoesercizio di scrittura di una classe. La libreria standard definisce una classe std::complex

che può essere inclusa con la direttiva #include <complex>.

* La libreria standard definisce in realtà una classe “parametrica”, cioè un tipo cosiddetto generico, incui il tipo primitivo della parte reale ed immaginaria può essere scelto dal programmatore. Ad esempio, cisi potrebbe accontentare che la rappresentazione di questi due dati si basi sul tipo primitivo float anzichésul double. Alla programmazione generica, che è alla base delle Standard Template Libraries (STL) siaccennerà più avanti.

Consideriamo un esempio più realistico che trae spunto dall’esempio del namespaceWing e ne presenta una versione migliore. Definiamo qui una classe Wing:

//----------------------------------------// File: Wing.h//----------------------------------------class Wing {public:

// costruttoriWing(); // dichiarazioneWing(string filename); // dichiarazione// distruttore~Wing(); // dichiarazione// funzioni membro pubblichevoid SetAlpha(double); // dichiarazionedouble GetAlpha(void){ return alpha; } // implementazionevoid SetMach(double); // dichiarazionedouble GetMach(void){ return mach; } // implementazione// ...bool Init(string filename); // dichiarazionevoid Calculate(void); // dichiarazionedouble GetCL(void){ return cL; } // implementazionedouble GetCD(){ return cD; } // implementazione// ...class BadFormatFile { /* ... */ }; // una classe definita in una classe

// definisce le eccezioni di formatoprivate:

double referenceSurface, span, aspectRatio, taperRatio, leSweep,dihedral, geomTwist, aeroTwist;

double alpha, mach;double cL, cD;double *y; // puntatore ad un vettore in heap// ...bool loadGeometry(string); // dichiarazione// ...

};

Appunti di programmazione a oggetti in C++ e Matlab

Page 32: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

32 Capitolo 1 Tecniche di programmazione supportate dal C++

Le stesse variabili utilizzate nell’esempio precedente del namespace Wing sono stateposte nella parte privata della classe. Questo risponde ancora al principio dell’occul-tamento dei dati. Quando si ha a che fare con le classi si usa anche il termine incap-sulamento. Grazie all’incapsulamento l’utente della classe Wing può accedere alla suarappresentazione — ai suoi dati — solo attraverso l’interfaccia della classe — l’insiemedelle funzioni pubbliche predisposto dal programmatore di Wing. Le seguenti istruzionimostrano esempi d’uso corretto e scorretto di questa classe:

Wing w; // definisce una variabile di tipo Wingcout << "Apertura alare (m): "

<< w.GetSpanMT() << "\n"; // bene, se GetSpanMT è definitaw.span = 12.5 // errore: span e’ privata

In pratica, i programmatori che creano dei nuovi tipi di variabili — diversi da quelliprimitivi, cioè predefiniti dal linguaggio —, istruiscono il compilatore C++ ad organizzaremeccanismi di gestione della memoria e delle funzioni di manipolazione dei dati. Que-sti meccanismi sono associati a delle singole entità, rappresentate appunto dalle variabilistesse. Le variabili di un qualsiasi tipo sono anche dette “oggetti”, anche le variabili diOggetti

tipi primitivi. Ma questa terminologia esprime bene le peculiarità delle variabili apparte-nenti a tipi definiti dall’utente. Gli oggetti sono tipicamente delle variabili appartenenti adeterminate classi, le quali possono essere definite in modo tale da permettere agli oggettidi interagire fra di loro attraverso le funzioni membro.

Nel gergo tecnico ogni oggetto è un’istanza di una data classe, cioè una variabile cheoccupa la memoria necessaria a contenere le strutture dati e le funzioni previste dalla clas-se. Il costruttore è la funzione invocata ogni volta che viene creato un oggetto della classeIl costruttore di una

classe e si occupa dell’inizializzazione. Un costruttore come Wing(), che non ha argomenti, èdetto costruttore di default, invocato da un’istruzione come Wing w; ed effettua un’inizia-lizzazione che il programmatore ritiene di default per oggetti di questa classe. Nel casosia necessario fare pulizia quando un oggetto di una classe non è più visibile, è possibileIl distruttore di una

classe dichiarare il complementare di un costruttore, detto distruttore:

Wing::Wing() // costruttore di default{

// inizializza tutte le variabili private// ...y = new double[100] // alloca gli elementi nella

// memoria dinamica (heap)}

Wing::~Wing() // definisce il distruttore{

// le variabili private sono automatcamente distrutte// tranne quelle indirizzate sullo heap

delete[] y // libera lo spazio occupato dagli elementi// di y per permettere un futuro riuso

}

Il costruttore di default inizializza una nuova variabile di tipo Wing. Per fare ciò allocanella memoria dinamica (detta anche heap) utilizzando l’operatore new. La parola chiaveMemoria dinamica

(heap) e operatore newnew del C++ permette di allocare memoria dinamica utile a contenere una variabile o unasequenza di variabili di un determinato tipo (anche di tipi definiti dll’utente). L’operazione

A. De Marco

Page 33: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 33

di allocazione di memoria dinamica restituisce (alla sinistra di new) un puntatore ad essa.Nel nostro esempio y è un array di 100 elementi di tipo double. Come avverrebbe per il C,anche nel linguaggio C++ la y non è altro che un puntatore al primo elemento dell’array,ovvero y[0]. Conservare in una variabile di tipo puntatore il risultato di new è anche dettoindirizzare.

Quando un oggetto di classe Wing esce dal campo di visibilità, ad esempio il flusso dicontrollo del programma passa al di fuori di un blocco, viene invocato auomatcamente ilsuo distruttore ~Wing(). La parola chiave delete usata nel codice del distruttore serve aistruire una liberarazione di memoria dinamica. Essa deve essere usata insieme ad un pun-tatore all’area di memoria che si desidera rendere nuovamente disponibile. Nell’esempioprecedente y è il puntatore e l’istruzione delete[] y serve a dire al compilatore che lamemoria da liberare è quella occupata dall’intero array, dal primo all’ultimo elemento.Tutto ciò si verifica senza l’intervento dell’utilizzatore di Wing. L’utente semplicementecrea e usa degli oggetti Wing come se fossero variabili di tipi predefiniti. Per esempio:

Wing wvar1("wing_config_1.xml"); // oggetto globale, costruito con dati// letti da file

void f(){Wing wvar2("wing_config_2.xml"); // oggetto localewvar1.Calculate();wvar2.Calculate();cout << "CL ala 1: " << wvar1.GetCL() << "\n"

<< "CL ala 2: " << wvar2.GetCL() << "\n";} // qui viene invocato il distruttore di wvar2cout << "CL ala 1: " << wvar1.GetCL() << "\n" // bene, wvar1 è globale

<< "CL ala 2: " << wvar2.GetCL() << "\n"; // errore: wvar2 e’// out-of-scope

Per le variabili di tipo Wing valgono le stesse regole di nomi, visibilità, allocazionevita, copia, e così via, che valgono per i tipi predefiniti come int e char.

Si osservi che le funzioni membro come Init o loadGeometry, che sono solo dichiara- Classi dichiarate in fileheader e funzionimembro definite in file diimplementazione

te nel costrutto class, devono anch’esse essere definite da qualche parte. La definizionequi è sinomino di implementazione. La dichiarazione di una (interfaccia di una) classecome Wing — quella vista sopra — viene posta in un file apposito detto header, di esten-sione .h (o anche .hpp e .hxx). Il nome dell’header (esclusa l’estensione) coincide ingenere con il nome della classe. La classe Wing avrà un header file di nome Wing.h ed unfile di implementazione di nome Wing.cpp. Guardiamo un frammento di possibile file diimplementazione della classe Wing:

//----------------------------------------// File: Wing.cpp//----------------------------------------// Headers#include "Wing.h" // dichiara la classe Wing// ...//----------------------------------------// costruttoriWing::Wing() { /* ... */ }Wing::Wing(string filename) { /* ... */ }//----------------------------------------// distruttoreWing::~Wing() { /* ... */ }

Appunti di programmazione a oggetti in C++ e Matlab

Page 34: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

34 Capitolo 1 Tecniche di programmazione supportate dal C++

//----------------------------------------bool Wing::Init(string filename){

// effettua delle inizializzazioni preliminari// ...return loadGeometry(filename);

}//----------------------------------------bool Wing::loadGeometry(string filename){

// cerca di caricare i parametri geometrici leggendoli// dalle direttive contenute in un file di configurazione// in formato XML (eXtended Markup Language)// ...return hesito della lettura filei;

}//----------------------------------------Wing::Calculate() { /* ... */ }// ...

Nella logica dei programmi organizzati in più file sorgente compilati separatamente,anche il codice utente di Wing dovrà includere l’header che dichiara la classe. Ecco unesempio:

// File: main.cpp// Headers#include "Wing.h" // dichiara la classe Wing#include <iostream>using namespace std;// ...int main(){

Wing wing, htail;if ( (!wing.Init("finite_wing_1.xml"))

||(!htail.Init("small_wing_2.xml")) ) {cout << "Unable to configure wings from file." << endl;PrintHelp();exit(-1);

}// da qui normale esecuzionewing.SetAlphaDeg(3.0);wing.SetMach(0.5);wing.Calculate();cout << "CD = " << wing.GetCD() << endl

<< "CL = " << wing.GetCL() << endl<< "Cm = " << wing.GetCm() << endl;

// ...return 0;

}

All’interno della funzione main vengono dichiarati due oggetti, wing e htail, di classeWing, inizializzati ed usati.

La funzione Init è un esempio di metodo pubblico che fornisce un valore di ritornoValori di ritorno difunzioni membro non void. Tale valore è previsto dal progettista della classe in modo che venga utile agli

utenti di Wing. Infatti Init ritorna un valore logico che informa il codice chiamante sul-

A. De Marco

Page 35: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 35

l’esito dell’inizializzazione avvenuta tramite caricamento dei dati da file. Nella funzionemain su riportata, il significato della negazione !htail.Init("small_wing_2.xml") usatanell’espressione logica del costrutto if potrebbe non essere immediato per i program-matori meno esperti. Un codice più prolisso, ma non meno efficiente, potrebbe essere ilseguente:

Wing wing; // inizializzazione di defaultWing htail;bool ok1 = wing.Init("finite_wing_1.xml"); // configura da filebool ok2 = htail.Init("small_wing_2.xml"); // configura da fileif ( !ok1 || !ok2 ) { // OR logico

cout << "Unable to configure from file." << endl;exit(-1);

}

Si assegnano alle variabili booleane ok1 ed ok2 i valori ritornati da Init invocate attraver-so gli oggetti wing e htail. Queste variabili vengono usate per controllare l’esito delleoperazione di configurazione da file ed eventualmente interrompere il programma con uncomando exit.

Secondo una buona pratica della programmazione in C++, gli oggetti hanno nomi che Consuetudini nellascelta dei nomi di classie di oggetti

iniziano con una lettera minuscola — ad esempio “wvar”, o anche “wing” — mentre inomi delle classi di appartenenza hanno iniziali maiuscole. A volte, scorrendo il codice ola documentazione di qualche libreria si possono trovare classi con nomi che iniziano per“C”. Ad esempio può capitare di incontrare il tipo non predefinito “CString” che secondouna consuetudine dei programmatori di intefacce grafiche in ambiente Windows serve asegnalare che CString è una classe e non una semplice struttura dati (la struct del C) oaltro ancora. La consuetudine che è bene seguire resta comunque quella di dare alle classidei nomi con iniziali maiuscole.

Una ulteriore consuetudine, usata soprattutto per progetti software di grandi dimen- Nomi di classi definite inprogetti di grandidimensioni

sioni, è quella di anteporre al nome naturale di una classe una sigla che indichi inequi-vocabilmente il nome del progetto. Ad esempio, nel codice sorgente del software disimulazione di volo FlightGear [12] si trova la definizione della classe FGColumnVector3.Le iniziali “FG” fanno capire a chi ispeziona il codice che si tratta di una delle classi de-finite nell’ambito del progetto e non una classe che appartiene ad una libreria da cui essoeventualmente dipende. Il resto del nome “ColumnVector3” fa capire che si tratta di unaclasse di utilità che serve a gestire i punti dello spazio tridimensionale, espressi comematrici colonna (3 � 1). Analogamente si definiscono le classi FGMatrix33 per le matrici(3 � 3) ed FGQuaternion per la gestine del quaternione dell’orientamento. Si rimanda illettore alla consultazione del sito internet di ispezione interattiva del codice sorgente diFlightGear Flight Simulator [13].

Tipi come Wing sono chiamati tipi concreti, in contrapposizione ai tipi astratti, neiquali l’interfaccia isola in maniera ancora più completa l’utente dai dettagli implementa-tivi.

1.4.3 Tipi astratti

Nei tipi concreti come la classe Wing la rappresentazione dei dati non è disaccoppiatadall’interfaccia esterna della classe, ma piuttosto è parte di quanto verrebbe incluso in unframmento di programma che facesse uso di Wing. Pur essendo privata, e quindi acces-

Appunti di programmazione a oggetti in C++ e Matlab

Page 36: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

36 Capitolo 1 Tecniche di programmazione supportate dal C++

sibile solo attraverso le funzioni membro, la rappresentazione è comunque presente nelladichiarazione della classe (ovvero nel file Wing.h incluso nel codice utente dalla direttiva#include). Se tale rappresentazione cambiasse in maniera significativa (aggiunta di varia-bili membro, manutenzione dell’implementazione, eccetera), l’utente sarebbe costretto aricompilare i file sorgenti della classe. Questo è il prezzo da pagare per avere tipi concretiche si comportano esattamente come quelli predefiniti.

Per i tipi poco soggetti a modifiche, e per i quali l’utilizzo tramite variabili locali for-nisce una maggior chiarezza ed efficienza, ciò è accettabile e spesso ideale. Tipicamente,i programmatori non interessati a sviluppare librerie o progetti di ampio respiro possonodisegnare il loro software facendo uso per lo più di classi concrete, delle librerie standarded eventualmente di librerie esterne.

Tuttavia il C++ offre agli sviluppatori di software la possibilità di mantenere com-pletamente isolati gli utilizzatori di una classe dalle eventuali modifiche della sua imple-mentazione. Ma per fare questo una classe come Wing definita nel paragrafo precedenterisulta insufficiente. Per raggiungere lo scopo bisogna disaccoppiare l’interfaccia dal-la rappresentazione e abbandonare l’uso di autentiche variabili locali (variabili membroprivate).

Ridefiniamo una classe Wing come pura interfaccia (detta anche classe astratta):

class Wing {public:

virtual bool Init(string filename) = 0;virtual void Calculate(void) = 0;virtual double GetCD(void) = 0;virtual double GetCL(void) = 0;virtual double GetCm(void) = 0;class BadFormatFile { /* ... */ }; // usata come eccezione

};

Questa è una dichiarazione di classe molto semplice e molto particolare. La parolavirtual che precede una funzione membro significa “può essere ridefinita successiva-mente in una classe derivata da questa”. Una classe derivata da un’altra è praticamenteFunzioni membro virtuali

pure e classi interfaccia un tipo utente identico al primo ed eventualmente con qualche variabile membro e fun-zione membro in più. Una classe derivata da Wing dell’ultimo esempio è una classe che,in pratica, fornisce l’implementazione per l’interfaccia Wing. La curiosa sintassi =0 indicache una classe derivata da Wing deve necessariamente definire quella funzione (che si dicefunzione virtuale pura). Di conseguenza, questo tipo Wing può fungere da interfaccia perogni classe che implementi le sue funzioni Init, Calculate, GetCD, GetCL e GetCm.

Un simile tipo Wing può essere usato come segue:

bool f(Wing *w, string fname){

if ( !w->Init(fname) ) return false;w->Calculate();return true;

};

L’operatore -> del C++ permette di accedere alle funzioni ed alle variabili membro di unoggetto quando se ne ha a disposizione un puntatore (Wing *w dichiara w come variabiledi tipo puntatore a Wing). Si noti come la funzione f utilizzi l’interfaccia di Wing igno-randone completamente i dettagli implementativi. Una classe che fornisce l’interfaccia aTipi polimorfi

A. De Marco

Page 37: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 37

una serie di altre classi è spesso chiamata tipo polimorfo. In questo caso Wing presupponenecessariamente che debbano esistere classi derivate da essa poiché le sue funzioni mem-bro sono funzioni virtuali pure. I programmatori C++ progettano classi come Wing con ilproposito di costruire una gerarchia di classi che derivano da questa.

Come è intuibile, l’implementazione in una classe derivata potrebbe consistere di tuttociò che apparteneva alla classe concreta del paragrafo precedente ed è stato invece omes-so nell’ultima versione dell’interfaccia Wing. Se si ha in mente di risolvere problemi dianalisi aerodinamica allora la funzione Calculate dovrà rappresentare quasi certamentel’aspetto più importante dell’implementazione. La funzione Init sarà altrettanto impor-tante e provvederà a fornire all’utente di ciascuna classe derivata la possibilità di crearefile di dati e di configurazione iniziale del modello aerodinamico.

Si esamini la figura 1.1 nella quale sono richiamati schematicamente due diversi mo-delli aerodinamici di un’ala finita. Quello rappresentato nella figura 1.1a è dovuto allafamosa Teoria della linea portante (Lifting-Line Theory, LLT) di Prandtl [38] e permettedi calcolare, con un certo livello di approssimazione, le caratteristiche aerodinamiche diun’ala — ad esempio, i coefficienti di resistenza indotta, CDi , di portanza, CL, e di mo-mento di beccheggio, Cm — per una corrente di assegnato angolo d’attacco ˛ e numerodi Mach asintotico M1.

A questo punto si potrebbe definire il nuovo tipo:

class Wing_LLT : public Wing { // Wing_LLT implementa Wingpublic:

Wing_LLT();~Wing_LLT();bool Init(string filename);void Calculate(void);// double GetCD(void);// double GetCL(void);// double GetCm(void);// ...

private:// double referenceSurface, span, aspectRatio, taperRatio, leSweep,// dihedral, geomTwist, aeroTwist;// double alpha, mach;// double cL, cD, cm;// double *y; // span-wise stationsdouble *gamma // span-wise vorticity distribution// ...bool loadGeometry(string);bool loadProfileData(string); // nella LLT è possibile usare dati// ... // sperimentali dei profili

};// ...void Wing_LLT::Calculate(void){

// calcolo delle caratteristiche alari secondo la// teoria della linea portante// ...

}// ...

Appunti di programmazione a oggetti in C++ e Matlab

Page 38: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

38 Capitolo 1 Tecniche di programmazione supportate dal C++

punti dicontrollo

centroidi

vorticitaaderente vorticita

libera

V1

i

i C 1

y

(a) Modello basato sulla Teoria della linea portante di Prandtl.

centroidi

vorticitaaderente

vorticitalibera

V1

i

i C 1

y

(b) Modello basato sulla Teoria del reticolo di vortici aderenti “ad anello” (Vortex Lattice Method, VLM).

Figura 1.1 Due possibili modelli per due diverse implementazioni di classi derivate da Wing.

Nella dichiarazione class Wing_LLT : public Wing { } il :public può essere lettocome “è derivato da”, “implementa” oppure “è un sottotipo di”. Perché una funzionecome la f definita in questo paragrafo possa usare un’istanza di Wing ignorando comple-tamente i dettagli implementativi, qualche altra funzione deve farsi carico della creazionedi un oggetto sul quale f possa operare:

void g() {Wing_LLT wllt; // inizializzazione di defaultwllt.SetAlpha(2.0); // potrebbero anche essere funzioniwllt.SetMach(0.3); // membro di Wing anziche’ di Wing_LLTtry {

if ( !f( &wllt, // indirizzo di wllt"wing_with_LLT_subdivisions.xml" ) )

{cout << "Unable to configure from file." << endl;exit(-1);

}cout << "CL = " << wllt.GetCL() << endl;

}catch (Wing::BadFormatFile) { // gestore dell’eccezione

A. De Marco

Page 39: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.4 Astrazione dei dati 39

// oops: errore di formatocout << "Bad format in Wing (LLT) configuration file" << endl;

}}

Questa funzione è perfettamente lecita in C++ e mostra una delle caratteristiche piùimportanti del linguaggio. La f non sa niente di Wing_LLT, ma conosce solo la classeinterfaccia Wing; opererà altrettanto bene per una diversa implementazione di Wing.

Quale potrebbe essere una implementazione alternativa? In Aerodinamica applicatail modello della linea portante non è l’unico disponibile per effettuare studi ingegneristicisulle proprietà delle ali. Esiste, ad esempio, un metodo di calcolo numerico dei coeffi-cienti aerodinamici di un’ala chiamato Vortex-Lattice Method (VLM) che è basato sullaTeoria dei vortici aderenti “ad anello” [39]. Una rappresentazione schematica di questomodello alternativo è riportata nella figura 1.1b. Ecco un esempio di implementazionealternativa:

class Wing_VLM : public Wing { // Wing_VLM implementa Wingpublic:

Wing_VLM();~Wing_VLM();bool Init(string filename);void Calculate(void);// ...

private:const int max_sw = 100; // span-wiseconst int max_cw = 5; // chord-wisedouble x[max_sw][max_cw]; // chord-wise divisionsdouble y[max_sw][max_cw]; // span-wise stationsdouble gamma[max_sw][max_cw] // bound vorticity// ...bool loadGeometry(string);// ...

};// ...void Wing_VLM::Calculate(void){

// calcolo delle caratteristiche alari com// il Vortex Lattice Method// ...

}// ...

In questo caso la rappresentazione del tipo Wing_VLM è basata su un diverso insieme di dati:le variabili private y e gamma — che nella classe Wing_LLT sono array monodimensionali erappresentano la discretizzazione dell’ala nel senso dell’apertura e le intensità dei vorticiaderenti ad essa associate (figura 1.1a) — sono adesso degli array bidimensionali poichéè necessario gestire anche i nodi lungo la direzione della generica corda alare. Per questomotivo a questa rappresentazione dei datisi è aggiunto l’array x. Per quanto riguardal’inizializzazione e la configurazione dall’esterno, per Wing_VLM sarà certamente diversoil meccanismo di lettura da file della geometria del modello (funzione loadGeometry).Questa classe derivata è una diversa implementazione dell’interfaccia Wing e l’indirizzodi un oggetto di tipo Wing_VLM può essere lecitamente passato come primo argomentodella funzione f. Si dice che la classe derivata Wing_VLM, così come la Wing_LLT, “è

Appunti di programmazione a oggetti in C++ e Matlab

Page 40: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

40 Capitolo 1 Tecniche di programmazione supportate dal C++

una” (“is a”) Wing. Quest’ultima è detta anche classe base o sopraclasse (base class oLa classe derivata “èuna” (“is a”) classe base super-class) mentre quelle da essa derivate si dicono sottoclassi (subclasses). L’esempio

seguente mostra un possibile uso di un oggetto di tipo Wing_VLM:

void h() {Wing_VLM wvlm; // inizializzazione di defaultwvlm.SetAlpha(2.0); // potrebbero anche essere funzioniwvlm.SetMach(0.3); // membro di Wing anziche’ Wing_VLMtry {

if ( !f( &wvlm, // indirizzo di wvlm"wing_with_VLM_subdivisions.xml" ) )

{cout << "Unable to configure from file." << endl;exit(-1);

}cout << "CL = " << wvlm.GetCL() << endl;

}catch (Wing::BadFormatFile) { // gestore dell’eccezione

// oops: errore di formatocout << "Bad format in Wing (VLM) configuration file" << endl;

}}

1.4.4 Funzioni virtuali

Come viene associata alla giusta definizione della funzione w->Init(fname), oppure del-la funzione w->Calculate(), nella f? Quando f viene invocata dalla funzione h, devonoessere eseguite Wing_VLM::Init e Wing_VLM::Calculate. Per ottenere questo tipo di as-sociazioni, un oggetto di tipo Wing deve contenere informazioni che indichino la funzioneche deve essere invocata durante l’esecuzione (at execution time, che è ben diverso daat compilation time). Una tecnica che viene adottata dai compilatori moderni è quella diconvertire il nome di ciascuna funzione virtual in un indice all’interno di una tabelladi puntatori a funzione. Questa tabella nel gergo tecnico degli sviluppatori di compila-tori viene normalmente chiamata “tabella delle funzioni virtuali” o, semplicemente vtbl.Ogni classe che possieda funzioni virtuali possiede una propria vtbl che identifica talifunzioni.

Le funzioni nella vtbl permettono un corretto utilizzo dell’oggetto anche quando lasua dimensione e la struttura dei suoi dati siano sconosciuti al chiamante. Tutto ciò cheil chiamante serve sapere è dove si trovi la vtbl in una Wing e l’indice utilizzato per cia-scuna funzione virtuale. Questo meccanismo di chiamate virtuali viene implementato daicompilatori in maniera così efficiente da essere paragonabile al meccanismo di “normalechiamata di funzione”. Il suo costo aggiuntivo in termini di spazio occupato in memoriaè il puntatore (un intero) in ogni oggetto di una classe che contenga funzioni virtuali piùuna vtbl per ognuna di tali classi.

A. De Marco

Page 41: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.5 Programmazione orientata agli oggetti 41

1.5 Programmazione orientata agli oggetti

1.5.1 Un esempio: l’aerodinamica di un velivolo completo

Sebbene l’astrazione dei dati — cioè quella tecnica che porta alla progettazione e all’usodi classi concrete — sia fondamentale per un buon progetto, si deve osservare che un tipoconcreto definisce una sorta di scatola nera. Una volta che la scatola nera è stata definita,questa interagisce in maniera “rigida” con il resto del programma, nel senso che non èpossibile adattarla a nuovi usi, se non modificando la sua definizione. Questa situazionepuò essere ideale ma può anche dimostrarsi poco flessibile in una serie di casi applicativi.

Nella progettazione delle classi Wing, Wing_LLT e Wing_VLM del paragrafo precedente,visto il problema che si intende risolvere, si potrebbe pensare a cosa accomuna veramentele implementazioni delle due classi derivate e a cosa, invece, le distingue. Nella formu-lazione di molti problemi pratici l’astrazione dei concetti può portare effettivamente adindividuare un insieme di proprietà comuni al gruppo dei possibili oggetti che il program-matore intende mettere in gioco. Per ciascuno degli oggetti tipicamente si possono anchedistinguere delle proprietà specifiche, non possedute dagli altri. La capacità di di fatto-rizzare le proprietà comuni e di distinguere tra le proprietà comuni e quelle specifichetraendone vantaggio definisce la programmazione orientata agli oggetti. I linguaggi do-tati di costrutti che permettono di esprimere e utilizzare questa distinzione supportano laprogrammazione orientata agli oggetti, gli altri no. Il meccanismo dell’ereditarietà è uno Ereditarietà

degli elementi fondamentali di questo stile di programmazione.Per approfondire questo concetto rivolgiamo l’attenzione ad un problema simile a Il calcolo aerodinamico

di un velivolo completo,possibile applicazionedella tecnica diprogrammazione aoggetti

quello del calcolo aerodinamico delle ali dei velivoli ma, in un certo senso, più generale.Supponiamo che il programmatore debba progettare un sistema di calcolo delle forze e deimomenti agenti sull’intera configurazione aerodinamica di un aeromobile. I progettisti deivelivoli affrontano questo argomento integrando e sintetizzando le conoscenze provenientidall’Aerodinamica applicata ai profili alari, alle ali finite isolate, ai corpi affusolati, allecombinazioni ala-fusoliera, e così via. Un esempio di configurazione aerodinamica di unvelivolo completo è mostrato nella figura 1.2f.

Come sanno bene gli ingegneri aerospaziali, per una data condizione di volo (quota,velocità, angolo d’attacco, angolo di derapata, posizione effettiva dei comandi di volo, ec-cetera), la stima delle forze e dei momenti aerodinamici agenti sul velivolo è un problematutt’altro che banale. Una schematizzazione ingegneristicamente accettabile dell’azioneaerodinamica sulla configurazione del velivolo nella sua interezza è quella di conside-rare quest’ultima come una sovrapposizione di effetti (aerodynamic build-up). L’azionetotale è la somma delle azioni aerodinamiche esercitate dai singoli elementi presi isolata-mente (ala, fusoliera, piani di coda, gondole dei motori, eccetera); tipicamente, a questicontributi isolati vanno aggiunti dei termini ulteriori: i cosiddetti effetti di interferenzaaerodinamica (dovuti al fatto che ciascun elemento aerodinamico è posto nella stessa cor-rente aerodinamica ma in presenza degli altri). Le rappresentazioni schematiche mostratenella figura 1.2 danno un’idea di questo principio.

In particolare, nella figura 1.2a è evidenziato il ruolo prevalente dell’ala principale diun velivolo di configurazione tradizionale nella genesi della portanza. La figura 1.2b sche-matizza un’altra situazione di particolare importanza nel progetto di un velivolo che è datadalla necessità di realizzare e mantenere stabilmente un equilibrio al beccheggio attraver-

Appunti di programmazione a oggetti in C++ e Matlab

Page 42: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

42 Capitolo 1 Tecniche di programmazione supportate dal C++

(a) isolated wing (W) (b) wing-horizontal tail (WH)

(c) wing-body (WB) (d) wing-body-vertical tail (WBV)

(e) wing-body-horizontal tail (WBH) (f) Velivolo completo

Figura 1.2 Possibili sottoinsiemi della configurazione aerodinamica di un velivolo. Essa può es-sere concepita come la composizione di un certo numero di “corpi aerodinamici”. Ciò può esseretradotto opportunamente a livello di astrazione dati.

so un piano di coda orizzontale. Nelle figure 1.2c, 1.2d e 1.2e sono rappresentate le partidi configurazione che devono essere necessariamente considerate, ad esempio, per unaragionevole stima del coefficiente di resistenza del velivolo, o anche per un raffinamentodel calcolo delle caratteristiche aerodinamiche connesse alla portanza e al momento dibeccheggio.

Anche per il calcolo delle caratteristiche latero-direzionali dei velivoli valgono consi-derazioni analoghe. In quel contesto è importante stimare la forza aerodinamica lateralee i momenti di rollio e imbardata in condizioni di volo non simmetriche e risulta determi-nante la successione di schematizzazioni: fusoliera o body (B), ala-fusoliera o wing-body(WB), ala-fusoliera-piano verticale di coda o wing-body-vertical tail (WBV). In tal caso,il piano verticale di coda si comporta dal punto di vista aerodinamico esattamente comeun’ala, solo che è disposto diversamente nei confronti della corrente fluida.

Dalle considerazioni precedenti si può cominciare a pensare che nella configurazioneCaratteristiche comunialle diverse componenti

di una configurazioneaerodinamica

di un velivolo coesistono elementi aerodinamici che, dal punto di vista delle teorie ae-rodinamiche, possiedono un certo numero di caratteristiche in comune. Ciò è vero siain termini dei parametri geometrici che ne permettono la definizione e la collocazionein un dato sistema di riferimento globale sia in termini delle grandezze aerodinamicheincognite che concorrono al calcolo dell’azione aerodinamica totale agente sul velivolo.

A tal proposito si esamini la figura 1.3. La posizione dell’ala rispetto ad un sistema diriferimento globale del velivolo, detto riferimento costruttivo fOc; xc; yc; zcg (con origineOc da qualche parte nella zona prodiera) è data dal punto AW (l’apice dell’ala) e dall’an-

A. De Marco

Page 43: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.5 Programmazione orientata agli oggetti 43

xc

xc

yc

zc c?W

bW

lW

A?W

iW

AW

Figura 1.3 Tipica schematizzazione della posizione di un’ala rispetto al sistema di riferimentocostruttivo di un velivolo fxc; yc; zcg. Il punto AW è l’apice dell’ala ed è un buon candidato perrappresentare il refCenter di AerodynamicBody. L’angolo di calettamento iW coinciderà con ilvalore della variabile membro incidenceSetting.

golo di calettamento iW. La definizione geometrica dell’ala potrà essere rappresentata daalcuni parametri significativi; ad esempio: c?W è la corda di radice, bW è l’apertura, e cosìvia.

Dal punto di vista dell’astrazione dei concetti, la figura 1.4 è simile a quella prece-dente. Essa schematizza il posizionamento nel riferimento costruttivo dell’impennaggioorizzontale (horizontal tail, H) ed il suo dimensionamento con dei parametri del tutto ana-loghi a quelli utilizzati per l’ala. Ecco che si avranno, tra i possibili parametri geometricirappresentativi, la corda di radice c?H e l’apertura bH.

La posizione ed i parametri geometrici di questi corpi aerodinamici può essere sche-matizzata in maniera del tutto generale in modo da comprendere anche gli altri elementidella configurazione del velivolo come la fusoliera, il piano verticale di coda, eccetera.Basta definire:� un riferimento locale al generico elemento, fO; �; �; �g, la cui origine O è data nel

riferimento costruttivo,� tre dimensioni caratteristiche di ciascun elemento, .`� ; `�; `�/, una per ogni dire-

zione coordinata,� un orientamento rispetto alla terna costruttiva dato dalla terna di angoli di Eulero.;�;˚/.

I coefficienti aerodinamici di forza e di momento calcolati per ciascun corpo potrannoessere riferiti agli assi locali e trasformati, all’occorrenza, in modo da essere riferiti aqualsiasi altra terna, ad esempio a quella degli assi costruttivi.

Nel caso dell’ala rappresentata nella figura 1.3, ad esempio, l’origine del riferimentolocale potrà coincidere con il puntoAW, l’asse � sarà allineato con la corda di radice, l’asse

Appunti di programmazione a oggetti in C++ e Matlab

Page 44: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

44 Capitolo 1 Tecniche di programmazione supportate dal C++

xc

xc

yc

zc c?H

bH

lH

A?H

iH

.< 0/

AH

Figura 1.4 Posizione del piano di coda orizzontale rispetto al sistema di riferimento costruttivo diun velivolo fxc; yc; zcg. Il punto AH è l’apice dell’impennaggio e l’angolo iH ne è il calettamentointorno all’asse trasversale yc.

� sarà normale al piano di simmetria, orientato positivamente verso la destra del pilota,e infine l’asse � sarà orientato in modo tale da rendere la terna levogira. Inoltre, l’unicoangolo di Eulero non nullo dell’orientamento di tale terna rispetto agli assi costruttivi è� � iW.

L’astrazione di questi concetti porta alla definizione di una classe base che potremmochiamare AerodynamicBody:

class AerodynamicBody {public:

AerodynamicBody();virtual bool Init(string filename) = 0;virtual void Calculate(void) = 0;Point Where() { return refCenter; } // class Point defined elsewherevirtual void Move(Point p, bool calc = true) {

refCenter = p;/* ... */if (calc) Calculate();

}virtual void Orient(float a, float b, float c, bool calc = true) {

psi = a; theta = b; phi = c;/* ... */if (calc) Calculate();

}virtual void SetAlphaDeg(float a, bool calc = true) {

alpha = a*degtorad;/* ... */if (calc) Calculate();

A. De Marco

Page 45: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.5 Programmazione orientata agli oggetti 45

}virtual void SetBetaDeg(float b, bool calc = true) {

beta = b*degtorad;/* ... */if (calc) Calculate();

}// ...float GetCFcsi() { return cFcsi; } // w.r.t. local ref.float GetCFeta() { return cFeta; }// ...float GetCMzet() { return cMzet; }float GetCFx(); // w.r.t. global reffloat GetCFy();// ...float GetCMz();// ...class BadFormatFile { /* ... */ }; // used as ecception class// ...

protected:static const double radtodeg; // these constants are uniquestatic const double degtorad; // for all objects// ...

private:Point refCenter; // origin of local ref.float psi, theta, phi; // orientation w.r.t. global axesfloat refLcsi, refLeta, refLzet; // reference quantitiesfloat refSurface, refVolume;float mach, reynolds;float alpha, beta;Point poleMoments; // moment ref. locationfloat cFcsi, cFeta, cFzet, cMcsi, cMeta, cMzet;float cFx, cFy, cFz, cMx, cMy, cMz;// ...fromLocalToGlobal(); // transforming aerodynamic coefficients// ...

};

Si dice che la classe AerodynamicBody raggruppa, “fattorizza”, mette a fattor comune,le proprietà e le funzionalità che ci si aspetta da un generico corpo aerodinamico. Di uncorpo aerodinamico si vogliono conoscere, ad esempio, i coefficienti di forza e di mo-mento

�CF� ; CF�; : : : ; CM�

�rispetto al proprio riferimento locale oppure i corrispondenti�

CFx ; CFy ; : : : ; CMz�

rispetto ad un riferimento globale.

Un utente potrebbe voler cambiare la posizione e l’orientamento del corpo aerodina-mico rispetto al riferimento costruttivo. Per questo scopo la classe AerodynamicBody mettea disposizione le funzioni: Where(), che ritorna un oggetto di classe Point contenente l’o-rigine corrente del riferimento locale, Move(), che sposta l’origine in un punto desiderato,e Orient() che ridefinisce l’orientamento. La chiamata di ciascuna di queste funzionipresuppone una chiamata alla funzione virtuale Calculate(). Ciò sembra ragionevole,dal momento che una qualunque variazione di posizionamento del corpo aerodinamicorispetto alla corrente fluida e agli altri eventuali corpi aerodinamici compresenti dovrebbeprovocare una variazione dei coefficienti aerodinamici. Un ragionamento analogo valeper SetAlphaDeg() e SetBetaDeg(), funzioni che consentono al programmatore di im-

Appunti di programmazione a oggetti in C++ e Matlab

Page 46: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

46 Capitolo 1 Tecniche di programmazione supportate dal C++

postare nuovi angoli aerodinamici di funzionamento determinando una variazione delleforze e dei momenti risultanti.* Le definizioni di alcune funzioni membro di AerodynamicBody mostrano che in C++ è possibile as-

segnare un valore di default agli argomenti di una funzione. Ad esempio la definizione virtual void

Move(Point p, bool calc = true) prevede un secondo argomento, calc, che è di tipo bool. La sorta diassegnazione che compare nella lista di argomenti vuol dire “se il codice chiamante non specifica questoargomento, assegna ad esso un valore true”. La definizione di Move() consente all’utente di modificareuna caratteristica dell’oggetto e di scegliere se eseguire o non eseguire la funzione Calculate(). Questalogica è valida anche per altre funzioni membro e potrebbe dimostrarsi molto utile per le classi derivate daAerodynamicBody che ridefiniscono una funzione Calculate() particolarmente onerosa dal punto di vistacomputazionale.

La rappresentazione della classe AerodynamicBody è data dalle variabili definite nellaparte privata, tra le quali si riconosceranno l’origine refCenter del riferimento localeed i suoi angoli di Eulero psi, theta e psi. Tra le altre variabili che costituiscono larappresentazione, vi sono le importanti grandezze cFcsi, cFeta, : : :, cMzeta, cFx, cFy,: : :, cFz. Esse sono destinate a contenere i valori dei coefficienti aerodinamici.

1.5.2 Dalle classi concrete alle gerarchie di classi

La classe AerodynamicBody non è direttamente usabile dal programatore poiché contienele funzioni virtuali pure Calculate() e Init(). Questo significa che bisogna definire unaclasse che erediti da AerodynamicBody sia la sua rappresentazione che la sua interfaccia,cioè l’organizzazione dei dati e le funzioni previste per manipolarli.

Le funzioni dichiarate virtual nella classe base AerodynamicBody sono quelle chepossono avere una definizione specifica per ciascun tipo di corpo aerodinamico che ilprogrammatore sia disposto a concepire. Tra queste vi è certamente Calculate(), chedeve basarsi su tecniche di calcolo diverse a seconda se si tratti di un corpo affusolato,come una fusoliera o una gondola motore, o di una superficie portante principale, comel’ala. Analogamente, la funzione di interfaccia Init() troverà una definizione specificaper ciascun tipo di forma aerodinamica, dovendo leggere da un file un insieme opportunodi direttive di configurazione.

Si consideri ad esempio la fusoliera rappresentata nella figura 1.5. Il C++ permette didefinire una classe concreta Fuselage “derivandola” dalla classe astratta AerodynamicBody.Quest’ultima è la classe base. Da essa la classe Fuselage, la classe derivata, eredita l’in-terfaccia e la rappresentazione. In un apposito file di intestazione, ad esempio Fuselage.h,si potrà dichiarare:class Fuselage : public AerodynamicBody {public:

Fuselage();bool Init(string filename);void Calculate(void); // to be defined in the implementation

private:vector<float> vCsiSectionC,

vZetSectionC,vCrossSectionArea;

// ...};

Altrove, ad esempio nel file di implementazione Fuselage.cpp, si potranno definire lefunzioni:

A. De Marco

Page 47: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.5 Programmazione orientata agli oggetti 47

xc

yc

zc

lB

bf,max � bB

hf,max � hB

bf.x/

hf.x/

V1

˛B

ˇB

Figura 1.5 I principali parametri geometrici ed aerodinamici di una fusoliera (Body, B). Tipi-camente, questo corpo aerodinamico ha un riferimento locale coincidente con quello globale:.O; �; �; �/ � .Oc; xc; yc; zc/.

void Fuselage::Init(string filename) {/* ... */

}void Fuselage::Calculate(void) {

/* ... */}

La rappresentazione interna degli oggetti di tipo Fuselage è quella ereditata dallaclasse AerodynamicBody. In più, la classe derivata si specializza dotandosi nella parte pri-vata di tre contenitori di tipo vector<float>, le variabili vCsiSectionC, vZetSectionC evCrossSectionArea (vettori della libreria standard), ed implementando le proprie versionidi Init() e Calculate().

Il tipo Fuselage può essere istanziato e ciascun oggetto potrà effettivamente interagirecon le risorse di sistema:

#include "Fuselage.h"// ...Fuselage fus;if ( !fus.Init("a380_fuselage.xml") ) {

cout << "Error! Could not load config file for Fuselage object.\n"exit(-1);

}fus.SetMach(0.5,false); // Aerodynamicfus.SetAlphaDeg(2,false); // settingsfus.SetBetaDeg(0,false);fus.Calculate(); // Aerodynamic calculationcout << "Cx = " << fus.GetCFx << endl;

Appunti di programmazione a oggetti in C++ e Matlab

Page 48: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

48 Capitolo 1 Tecniche di programmazione supportate dal C++

Il passaggio dalla classe base AerodynamicBody alla classe concreta Fuselage è unesempio molto semplice di gerarchia di classi. A seconda del problema che si intendemodellare, esiste la possibilità di articolare a piacimento la catena di derivazione di nuoveclassi, a partire da superclassi a loro volta derivate da altre. Lo scopo è quello di costruiredei meccanismi che consentano la massima flessibilità nell’uso degli oggetti, separandoper quanto sia possibile l’implementazione delle funzionalità e la rappresentazione deglioggetti dalle loro interfacce. Questo è in effetti ciò che si intende per programmazioneorientata agli oggetti. Il paradigma diventa:

Decidi quali classi ti occorrano;fornisci un insieme completo di operazioni per ogni classe;rendi esplicite le parti comuni mediante l’ereditarietà.

La classe Fuselage può essere, a sua volta, la classe base di una nuova classe, che ere-dita dalla prima la rappresentazione e l’interfaccia e si specializza per qualche motivo. Adesempio, per una particolare tecnica di calcolo dei coefficienti aerodinamici oppure per-ché modella una particolare categoria di fusoliere che hanno delle caratteristiche peculiarie non fattorizzabili negli oggetti aerodinamici generici modellati da AerodynamicBody oda Fuselage.

A questo punto, dalla classe base AerodynamicBody si può pensare di derivare classianaloghe a quella che modella fusoliere, ramificando la gerarchia. È naturale derivareuna classe Wing e da essa derivarne eventualmente delle altre, ad esempio HTail e Canard

che modellano tipi particolari di superfici portanti le cui caratteristiche aerodinamichevanno valutate in modo specifico. Questo discorso porta alla costruzione di una gerarchiadi tipi che permette di istanziare oggetti dalle proprietà adeguate agli oggetti fisici cheessi rappresentano. Gli oggetti interagiranno adeguatamente tra di loro e con le risorse disistema.

Un campo applicativo in cui la programmazione orientata agli oggetti si dimostraLa programmazione aoggetti è ideale per

sviluppare delle GUIparticolarmente adatta è quello dello sviluppo di applicazioni dotate di interfacce grafiche(Graphical User Interfaces, GUI). Ma non è il solo. Esistono svariate classi di problemidi tipo ingegneristico che ben si prestano alla modellazione per classi di oggetti. Come siè visto, il calcolo aerodinamico dei velivoli ne è un esempio.

Come sostiene Herbert Schildt nella sua popolare Guida completa [4], il C++ è illinguaggio perfetto per Windows ed il modo in cui supporta la programmazione a oggettiè completamente soddisfacente per sviluppare applicazioni in tale ambiente operativo (sipotrebbe aggiungere che ciò vale anche per Mac OS X e per i vari ambienti interattividi Linux). D’altra parte, i programmi per Windows sono, per loro stessa natura, estesi ecomplessi. La quantità di codice necessario per creare anche solo la semplice strutturaComplessità intrinseca

del codice sorgente diapplicazioni basate su

GUI

di un programma per Windows — dotato di una seppur minimale interfaccia grafica —occupa dalle 50 alle 70 righe. Per scrivere un programma per Windows che sia utileper illustrare le funzionalità del C++ sono necessarie centinaia di righe di codice. Inaltre parole, Windows non è l’ambiente più appropriato per descrivere le funzionalitàdi un linguaggio di programmazione. Naturalmente è possibile utilizzare un compilatoreWindows per compilare semplici applicazioni che stampino messaggi sul canale di outputstandard ed eventualmente accettino un input da tastiera. In questi casi il compilatoreProgrammi eseguiti da

console creerà un’applicazione in grado di lanciare automaticamente una sessione a console nellaquale eseguire il programma.

A. De Marco

Page 49: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

1.6 Cosa non abbiamo detto? 49

1.6 Cosa non abbiamo detto?

Non abbiamo parlato delle classi template del C++ e della programmazione generica, enon ne parleremo approfonditamente. Questa tecnica di programmazione è alla base della Programmazione

generica e StandardTemplate Library, STL

Standard Template Library (STL), una libreria software inclusa nelle implementazionistandard del linguaggio C++. La commissione dell’ente ISO (International Organizationfor Standardization) che ha fissato ufficialmente le caratteristiche del C++ ha stabilitoche ogni compilatore che si dica standard compliant deve essere dotato di librerie cheimplementano le funzionalità della STL, tra le quali la possibilità di usare strutture datigeneriche, iteratori e algoritmi generici. Un ottimo testo che approfondisce gli aspettiprogettuali e le modalità d’uso della STL è quello di Vandevoorde e Josuttis [8]. Non tuttii programmatori sono tenuti a comprendere nei minimi dettagli le tecniche che consentonodi creare una libreria come la STL. Per molti è sufficiente capire quanto basta per poterusare le classi che essa offre.

La STL costituisce uno strato software fondamentale per chiunque voglia lavorareproduttivamente con il C++. Essa fornisce un insieme precostituito di classi che il pro-grammatore si aspetta di usare nella risoluzione della maggior parte dei problemi. Esempidi classi del genere sono i container e gli array associativi, che nella STL sono definitiin modo da poter operare con qualsiasi tipo di dato, sia primitivo che definito dall’uten-te. Nelle classi container — a proposito di funzionalità che un programmatore si aspettadi trovare già pronte all’uso — vi sono già implementate con criteri unificati le funzio-ni standard di copia, assegnamento, inserimento/rimozione, iterazione tra gli elementi(scorrimento).

Gli sviluppatori più avanzati possono anche derivare classi personalizzate da quellepresenti nella STL purché essi rispettino pochi vincoli (ad esempio, l’implementazione dioperatori o funzioni di assegnamento o confronto). In tal senso la STL, unitamente allapotenza espressiva di un linguaggio come il C++, offrono la possibilità di creare nuoveclassi e librerie complete di tutte le funzioni e operazioni elementari.

Il container vector è una delle classi più importanti messe a disposizione dalla STL. Il contenitore vector

della STLUn vector è un contenitore di elementi omogenei simile all’array, con la funzione dipermettere l’accesso ai suoi contenuti in modo rapido e ottimizzato, utilizzando indici otramite un iteratore. La definizione di questa classe si trova nel file header <vector> delnamespace std. Esso rappresenta in sostanza una versione evoluta dell’array del C. Infatti,al contrario di un array tradizionale, un vector non ha una capacità massima prefissata intempo di compilazione, ma si espande durante l’esecuzione a seconda delle necessità.

L’accesso agli elementi di un vector è di tipo casuale, e particolarmente efficaci sonole operazioni di inserimento (push_back()) e rimozione in coda (pop_back()). Ecco unesempio di costruzione e scorrimento di un vector di float:

std::vector <float> v;v.push_back(1.0);v.push_back(-2.5);v.push_back(5.0);for (int i = 0; i < v.size(); i++)

std::cout << v[i] << std::endl;

Sulla base degli esempi precedenti, si lascia al lettore l’esercizio di ragionare sulseguente frammento di codice:

Appunti di programmazione a oggetti in C++ e Matlab

Page 50: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

50 Capitolo 1 Tecniche di programmazione supportate dal C++

std::vector <AerodynamicBody *> v; // a vector of pointers

Fuselage * pF = new Fuselage(); // put in heappF->Init("fuselage.xml"); // define from filev.push_back((AerodynamicBody *)pF); // cast and put in vector

Wing * pW = new Wing();pW->Init("wing.xml");v.push_back((AerodynamicBody *)pW); // cast and put in vector

HTail * pH = new HTail();pH->Init("horizontal_tail.xml");v.push_back((AerodynamicBody *)pH); // cast and put in vector

double Cx = 0.0;

for (int i = 0; i < v.size(); i++) {v[i]->Calculate(); // call the correct member functionCx += v[i]->GetCFx(); // cumulate the coefficient Cx

}std::cout << "Aircraft total Cx = " << Cx << std::endl;

Nel prossimo capitolo continueremo ad approfondire le peculiarità della programma-zione a oggetti attraverso ulteriori esempi in linguaggio C++. Questo servirà anche alloscopo di introdurre altri dettagli sulle caratteristiche stesse del linguaggio. A tal propositovale la pena far precedere il prossimo argomento da un aforisma.

Il C++ sarebbe un liguaggio decente per insegnare la programmazione, sepotessimo insegnare la parte “++” senza dover spiegare anche la parte “C”.

– Michael B. Feldman

A. De Marco

Page 51: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Capitolo 2

Ancora sulla programmazione in C++

If you think C++ is not overly complicated, just what is a protectedabstract virtual base pure virtual private destructor and when was the

last time you needed one?

– Tom Cargill

Indice2.1 Elementi di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522.2 Il mondo delle classi e degli oggetti . . . . . . . . . . . . . . . . . . . 592.3 La libreria standard . . . . . . . . . . . . . . . . . . . . . . . . . . . 622.4 Le librerie Boost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622.5 Esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632.6 Come imparare il C++ . . . . . . . . . . . . . . . . . . . . . . . . . . 66

[capitolo incompleto]Il C++ fu “inventato” nel 1980 dal ricercatore informatico danese Bjarne Stroustrup,

che ricavò concetti già presenti in precedenti linguaggi (come il Simula67) per produrreuna versione modificata del C, che chiamò: “C con le classi”. Il nuovo linguaggio univala potenza e l’efficienza del C con la novità concettuale della programmazione a ogget-ti, allora ancora in stato “embrionale” (c’erano già le classi e l’eredità, ma mancavanol’overload, le funzioni virtuali, i riferimenti, i template, la libreria e moltre altre cose).

Il nome C++ fu introdotto per la prima volta nel 1983, per suggerire la sua naturaevolutiva dal C, nel quale ++ è l’operatore di incremento (taluni volevano chiamarlo D,ma C++ prevalse, per i motivi detti).

All’inizio, comunque, e per vari anni, il C++ restò un esercizio quasi privato del suoautore e dei suoi collaboratori, progettato e portato avanti, come egli stesso disse, “perrendere più facile e piacevole la scrittura di buoni programmi”.

Tuttavia, alla fine degli anni 80, risultò chiaro che sempre più persone apprezzavano edutilizzavano il linguaggio e che la sua standardizzazione formale era un obiettivo da per-seguire. Nel 1990 si formò un comitato per la standardizzazione del C++, cui ovviamentepartecipò lo stesso Autore. Da allora in poi, il comitato, nelle sue varie articolazioni,divenne il luogo deputato all’evoluzione e al raffinamento del linguaggio.

Finalmente l’approvazione formale dello standard si ebbe alla fine del 1997. In que-sti ultimi anni il C++ si è ulteriormente evoluto, soprattutto per quello che riguarda

Page 52: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

52 Capitolo 2 Ancora sulla programmazione in C++

l’implementazione di nuove classi nella libreria standard.Per descriverlo in sintesi si può affermare che il C++ è un linguaggio di programma-

zione general-purpose, orientato alla realizzazione di sistemi che:� può dirsi un C migliorato,� supporta l’astrazione dei dati,� supporta la programmazione agli oggetti,� supporta la programmazione generica.

2.1 Elementi di base

Il linguaggio C++ (come il C) distingue i caratteri maiuscoli da quelli minuscoli (è unCase sensitivity

linguaggio case sensitive). Ad esempio, i nomi MiaVariabile e miavariabile indicanodue variabili diverse.

In C++ (come in C) ogni modulo di programma è una funzione. Non esistono sub-Moduli funzione

routines o altri tipi di sottoprogramma. Ogni funzione è identificata da un nome. Leprocedure possono essere simulate definendo funzioni che ritornano un void e gestendoopportunamente gli argomenti attraverso variabili di tipo puntatore.

2.1.1 Interfaccia dei programmi con il sistema operativo

Quando si manda in esecuzione un programma, questo inizia sempre dalla funzione iden-La funzione main

tificata dalla parola chiave main. Questa funzione speciale viene detta in gergo “entrypoint del programma” ed è invocata dal sistema operativo, che gli può passare dei para-metri; a sua volta main può restituire al sistema un numero intero. Questo valore coincidePassaggio di parametri

da riga di comando ecodici di terminazione

dei programmi

con il valore di ritorno di main e di solito è destinato ad essere analizzato a valle dell’e-secuzione del programma come possibile codice di errore (detto in gergo return status oexit code). Ad esempio, l’esecuzione da console del programma convert.exe può essereinvocata dal prompt dei comandi (>>) in questo modo:

>> convert.exe drawing.eps --output-format=PDF hinvioiLa console attraverso la quale viene eseguito questo comando può essere: il prompt deicomandi di Windows (anche noto come prompt dei comandi DOS), una tipica finestrashell di Linux oppure una finestra dei comandi Cygwin (che rappresenta il porting supiattaforme Windows di gran parte delle funzionalità di Linux [24]). Se la console èdotata di interprete Bash [20], l’exit code è ottenibile attraverso il comando:

>> echo $? hinvioi>> 0

La particella $? è, tecnicamente, una macro destinata ad essere “espansa” (cioè trasfor-mata in una stringa) e serve ad interrogare l’interprete dei comandi sullo stato di ritornodell’ultimo comando. Questo valore è passato al comando echo di Bash che lo stampa sulprompt. Il valore 0 restituito in questo caso segnala che la funzione main implementata nelcodice eseguibile di convert.exe ha fornito un valore di ritorno nullo. Il programmatoreche ha creato questo eseguibile ha probablimente seguito la regola per cui un valore diritorno 0 corrisponde ad una condizione di terminazione normale dei programmi.

La modalità d’invocazione del programma convert.exe fa luce, a sua volta, sul per-ché la funzione main dei programmi C e C++ accetta degli argomenti. Dopo aver premuto

A. De Marco

Page 53: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.1 Elementi di base 53

il tasto di invio, l’interprete dei comandi (sia esso quello di Bash o del DOS) eseguel’analisi della stringa di caratteri costituita dall’intera riga di comando (command lineparsing). Esso riesce a separarla (interpretando gli spazi bianchi come separatori) in trestringhe: “convert.exe”, “drawing.eps” e “--output-format=PDF”; queste stringhe, in-cluso il nome stesso del programma che si esegue, vengono dette parametri della riga dicomando (command line parameters). La funzione main è detta entry point del program-ma convert.exe proprio perché, quando questo viene mandato in esecuzione, il sistematenterà di comunicarle sempre due valori: il numero di parametri della riga di comandoed un puntatore ad un array di stringhe “in stile C” (sequenza di costanti di tipo carattereterminate dal carattere di escape ’\0’, detto null terminator).

Ecco svelato il motivo per cui le funzioni main dei programmi C e C++ sono tipica-mente definite in questo modo:

int main(int argc, char *argv[]){ hcorpo della funzionei }

La parte di riga su riportata che va dal primo carattere alla parentesi tonda chiusa —int main( ... ) — viene detta in gergo function signature (la “firma” della funzione).Essa dice che la funzione in esame ha per nome main, che ritorna un valore di tipo int

e che ha due argomenti: la variabile argc, di tipo int, e la variabile argv, di tipo arraydi puntatori a caratteri (char*). Il valore di argc (che sta per argument count) è proprioil numero degli argomenti della riga di comando che è servita ad invocare il programma.Nel nostro esempio l’interprete dei comandi passa a main un argc pari a 3 e un vettoreargv pari a:

{"convert.exe\0","drawing.eps\0","--output-format=PDF\0"}

in cui l’elemento di posto 0, cioè argv[0], è sempre il nome dell’eseguibile. Nella fir-ma di main il vettore argv ha dimensioni non specificate, cioè automaticamente determi-nate a runtime (in fase di esecuzione) a seconda di come l’utente invoca il programmadal prompt. Se lo stesso programma deve essere usato per convertire l’immagine vetto-riale contenuta nel file drawing.eps in un’immagine bitmap, allora la riga di comandodovrebbe essere un qualcosa di simile:

>> convert.exe drawing.eps --output-format=JPG --resolution-dpi=72 hinvioicon un argument count pari a 4 ed un vettore argv:

{"convert.exe\0","drawing.eps\0","--output-format=JPG\0","--resolution-dpi=72\0"}

È stato qui uno dei compiti del programmatore che ha implementato l’algoritmo di par-sing della riga di comando quello di offrire all’utente di convert.exe la possibilità diutilizzare l’applicazione per eseguire questo tipo di conversione e di specificare la riso-luzione del risultato. Il buon senso dice che probabilmente l’ultimo comando produce inoutput un file drawing.jpg della risoluzione voluta.

Come si può dedurre da questi esempi, il C++ si interfaccia al sistema operativo at-traverso l’entry point dei programmi esattamente come ciò avverrebbe per applicazioniscritte in linguaggio C. Ciò è dovuto al fatto che il C++ è stato progettato anche per poteringlobare il C come una sorta di “sottolinguaggio”. Questa caratteristica permette di potercompilare gran parte del codice C esistente con un compilatori C++ (standard compliant)e di ereditare le efficienti librerie di funzioni di sistema sviluppate negli anni.

Appunti di programmazione a oggetti in C++ e Matlab

Page 54: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

54 Capitolo 2 Ancora sulla programmazione in C++

2.1.2 Le funzioni

La funzione main è una funzione speciale ma, dal punto di vista formale, è una funzioneLe tre parti di unafunzione C++ come tutte le altre. Delle funzioni C++ si distinguono tre caratteristiche principali:

la lista degli argomenti, il blocco delle sue istruzioni ed il tipo del valore di ritorno.Gli argomenti della lista di parametri di scambio passati dal programma chiamante

vanno indicati fra parentesi tonde dopo il nome della funzione; f(void) indica che lafunzione di nome f non ha argomenti.

Il blocco di delle funzioni C++ è l’ambito di azione, anche detto ambito di visibilitào scope delle istruzioni della funzione; va racchiuso fra parentesi graffe. Ogni istruzionedeve terminare con “;” (può estendersi su più righe o vi possono essere più istruzionisulla stessa riga). Un’istruzione è costituita da una successione di token: un token è il piùpiccolo elemento di codice individualmente riconosciuto dal compilatore. Sono token:gli identificatori, le parole-chiave, le costanti letterali o numeriche, gli operatori e alcunicaratteri di punteggiatura. Gli spazi bianchi e gli altri caratteri “separatori” (horizontalor vertical tabs, new lines, formfeeds) fra un token e l’altro o fra un’istruzione e l’altra,sono ignorati. In assenza di separatori il compilatore analizza l’istruzione da sinistra adestra e tende, nei casi di ambiguità, a separare il token più lungo possibile. Ad esempio,l’istruzione:

a = i+++j;

può essere interpretata come:

a = i + ++j;

oppure come:

a = i++ + j;

Secondo lo standard, il compilatore sceglie la seconda interpretazione.Il tipo del valore di ritorno di una funzione al programma chiamante va indicato prima

del nome della funzione ed è obbligatorio; se è void indica che non c’è valore di ritorno.I commenti sono brani di programma (che il compilatore ignora) inseriti al solo scopoCommenti

di documentazione, cioè per spiegare il significato delle istruzioni e così migliorare laleggibilità del codice. Sono molto utili anche allo stesso autore, per ricordargli quello cheha fatto, quando ha necessità di rivisitare il programma per esigenze di manutenzione o diaggiornamento. Un buon programma si caratterizza anche per il fatto che fa abbondanteuso di commenti. In C++ ci sono due modi possibili di inserire i commenti. Nel primo,ereditato dal linguaggio C, l’area di commento è introdotta dal doppio carattere /* e ter-mina con il doppio carattere */ (può anche estendersi su più righe). In alternativa, l’areadi commento inizia con il doppio carattere // e termina alla fine della riga.

Il programma seguente è un esempio minimale di programma in C++:

#include <cstdio>void main(void){

printf("Hello world!\n");}

Lo stesso programma è riportato con l’aggiunta di commenti che spiegano i diversi ele-menti formali previsti dal linguaggio:

A. De Marco

Page 55: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.1 Elementi di base 55

#include <cstdio> /* inserisce il file che dichiara printf,<...> indicano che il file ”cstdio” va cercatoin una cartella di default del sistema

*/void // nessun valore di ritorno

main(void) // nessun argomento accettato dall’entry point// non sono previste parametri da riga di comando

{ // inizio blocco// printf, funzione di libreria standard

printf("Hello world!\n"); // stampa una stringa sul canale// di output standard

} // fine blocco

2.1.3 Tipi nativi

Come è noto, per tipo di una variabile si intende un termine di classificazione che rag- Il C++ effettua unostretto controllo sui tipi divariabile

gruppa tutte quelle variabili che sono memorizzate nello stesso modo e a cui si applica lostesso insieme di operazioni. Nel linguaggio C++ viene esercitato (dal compilatore) unforte controllo sui tipi (strong type checking), nel senso che in fase di compilazione vieneregolata e limitata la conversione da un tipo all’altro (casting) e controllata l’interazionefra variabili di tipo diverso.

In C++ esistono solo 5 tipi, detti intrinseci o nativi: Tipi nativi del C++

int numero intero di 2 o 4 byte,char numero intero di 1 byte (interpretabile come codice ascii di un carattere),float numero in virgola mobile con 6-7 cifre significative (4 byte),double numero in virgola mobile con 15-16 cifre significative (8 byte),bool valore booleano: true o false (1 byte).In realtà il numero di tipi possibili è molto più grande, sia perché ogni tipo nativo puòessere specializzato mediante i qualificatori di tipo, sia perché il programma stesso puòcreare propri tipi personalizzati (detti “tipi astratti”).

2.1.4 Il preprocessore e le unità di traduzione dei programmi

In C++ (come in C), prima che il compilatore inizi a lavorare, viene attivato un pro-gramma, detto preprocessore, che ricerca nel file sorgente speciali istruzioni, chiamatedirettive.

Una direttiva inizia sempre con il carattere # (nella colonna 1) e occupa una sola riga Le direttive dicompilazione(non ha un terminatore, in quanto finisce alla fine della riga; riconosce però i commenti,

introdotti da // o da /*, e la continuazione alla riga successiva, definita da \).Il preprocessore crea una copia del file sorgente (da far leggere al compilatore) e, ogni

volta che incontra una direttiva, la esegue sostituendola con il risultato dell’operazione.Pertanto il preprocessore, eseguendo le direttive, non produce codice binario, ma codicesorgente per il compilatore.

Ogni file sorgente, dopo la trasformazione operata dal preprocessore, prende il nome Le translation unit

di translation unit o unità di traduzione. Ogni translation unit viene poi compilata sepa-ratamente, con la creazione del corrispondente file oggetto, in codice binario. Spetta allinker, infine, collegare tutti i files oggetto, generando un unico programma eseguibile.

Appunti di programmazione a oggetti in C++ e Matlab

Page 56: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

56 Capitolo 2 Ancora sulla programmazione in C++

Nel linguaggio C++ esistono molte direttive (alcune delle quali dipendono dal siste-ma operativo). Le più usate sono le seguenti: #include, #define, #undef e direttivecondizionali.

La direttiva #include è molto importante. Ad esempio la sequenza:La direttiva #include

#include <filename1>#include "filename2"

determina l’inserimento, nel punto in cui si trova la direttiva, dell’intero contenuto deifile filename1 e filename2. L’uso delle parentesi angolari, intende che filename1 vadacercato nel percorso (directory) di default del linguaggio (opportunamente preimpostatoo comunicato al compilatore al momento della compilazione). Se invece si usano le vir-golette, il file, per essere incluso con seuccesso, deve trovarsi nella stessa directory in cuirisiede il sorgente del programma.

La direttiva #include viene usata quasi esclusivamente per inserire gli header-files(.h) ed è particolarmente utile quando in uno stesso programma ci sono più file sorgenti(implementation-files) che includono lo stesso header-file.

Quando il preprocessore incontra la seguente direttiva:La direttiva #define diuna costante

#define hidentificatorei hvaloreidove, hidentificatorei è un nome simbolico (che segue le regole generali di specifica ditutti gli altri identificatori) e hvalorei è un’espressione qualsiasi, delimitata a sinistra daspazi bianchi (blank, ’ ’), caratteri di tabulazione (tab, \t) e a destra da dei blanks, deitab o dal carattere di andata a capo (new-line, ’\n’), l’hidentificatorei viene sostituito conhvalorei in tutto il file (da quel punto in poi). In generale la direttiva #define serve perassegnare un nome a una costante (che viene detta “costante predefinita”). Ad esempio,la direttiva:

#define M_PI 3.14159265358979323846

sostituisce (da quel punto in poi) in tutto il file la parola M_PI con 3.14159265358979323846.Ogni volta che il programma deve usare il valore numerico che approssima � , si puòspecificare in sua vece la costante M_PI.

Va osservato che che la sostituzione è assolutamente fedele e cieca, qualunque sia ilcontenuto dell’espressione che viene sostituita all’identificatore. Il compito del prepro-cessore è quello di effettuare sostituzioni di questo tipo, di includere file esterni e selezio-nare le parti di codice sorgente da compilare (escludendone eventualmente delle altre). ilcompito di “segnalare gli errori” viene lasciato al compilatore.

Esistono principalmente due vantaggi nell’uso di #define. In primo luogo, se il pro-grammatore decide di cambiare valore a una costante, è sufficiente che lo faccia in unsolo punto del programma. In secondo luogo, molto spesso i nomi sono più significativi emnemonici dei numeri (oppure più brevi delle stringhe, se rappresentano costanti stringa)e perciò l’uso delle costanti predefinite permette una maggiore leggibilità del codice e unamaggiore efficienza nella programmazione.

In pratica la direttiva #define produce gli stessi risultati dello specificatore di tipoconst, che è una parola chiave peculiare del C++. Al posto della direttiva dell’esempioprecedente si sarebbe potuto scrivere la dichiarazione:

const float M_PI = 3.14159265358979323846 ;

I vantaggi nell’uso di const sono due: il tipo della costante è dichiarato ed un even-tuale errore di dichiarazione viene segnalato immediatamente dal compilatore; inoltre, la

A. De Marco

Page 57: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.1 Elementi di base 57

costante è riconosciuta, e quindi analizzabile, nelle operazioni di debug. D’altra parte, Confronto fra la direttiva#define e lospecificatore const

una una costante predefinita mediante l’uso di un #define a volte è più comoda e imme-diata (è una questione sostanzialmente “estetica”) e può essere usata anche per altri scopi(per esempio per sostituire o mascherare nomi).

Il preprocessore dispone di un suo mini-linguaggio di controllo, che consiste nelle Le direttive condizionali

seguenti direttive condizionali:

#if hespressione 1ihblocco di direttive e/o istruzionii

#elif hespressione 2ihblocco di direttive e/o istruzionii

#elsehblocco di direttive e/o istruzionii

#endif

dove hespressionei è un’espressione logica che può contenere solo identificatori di co-stanti predefinite o costanti letterali, ma non variabili e neppure variabili dichiarate const,che il preprocessore non riconosce. In particolare hespressionei può essere del tipo:

defined(hidentificatorei)che restituisce vero se hidentificatorei è definito (cioè se è stata eseguita la direttiva:

#define hidentificatoreiAl posto di

#if defined(hidentificatorei)si può usare la forma:

#ifdef hidentificatoreiEsiste anche la possibilità di applicare l’operatore di negazione ! cosicché

!defined hidentificatoreirestituisce vero se hidentificatorei non è definito. Al posto di

#if !defined(hidentificatorei)si può usare la forma:

#ifndef hidentificatoreiNel costrutto di direttiva condizionale l’istruzione #elif sta per else if ed è opziona-

le (possono esserci più blocchi consecutivi, ciascuno introdotto da un #elif). L’istruzione#else è opzionale (se esiste, deve introdurre l’ultimo blocco prima di #endif). L’istru-zione #endif è obbligatoria e termina la sequenza iniziata con un #if. Non é necessarioracchiudere i blocchi fra parentesi graffe, perché ogni blocco è terminato da #elif, o da#else, o da #endif. Il preprocessore identifica il blocco (se esiste) che corrisponde allaprima condizione risultata vera, oppure il blocco relativo alla direttiva #else (se esiste)nel caso che tutte le condizioni precedenti siano risultate false. Tale blocco può conteneresia istruzioni di programma che altre direttive, comprese direttive condizionali (posso-no esistere più blocchi #if “innestati”): il preprocessore esegue le direttive e presenta alcompilatore le istruzioni che si trovano nel blocco selezionato, scartando sia direttive cheistruzioni contenute negli altri blocchi della sequenza #if ... #endif.

Ecco un estratto di codice reale che mostra un esempio d’uso delle direttive di compi-lazione:

Appunti di programmazione a oggetti in C++ e Matlab

Page 58: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

58 Capitolo 2 Ancora sulla programmazione in C++

// Program JSBSim.cpp// see: http://www.jsbsim.org// http://jsbsim.cvs.sourceforge.net/viewvc/jsbsim/JSBSim/// ...

#if !defined(__GNUC__) && !defined(sgi) && !defined(_MSC_VER)# include <time>#else# include <time.h>#endif

#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)# define WIN32_LEAN_AND_MEAN# include <windows.h># include <mmsystem.h># include <regstr.h># include <sys/types.h># include <sys/timeb.h>#else# include <sys/time.h>#endif

// ...

#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)double getcurrentseconds(void){struct timeb tm_ptr;ftime(&tm_ptr);return tm_ptr.time + tm_ptr.millitm*0.001;

}#elsedouble getcurrentseconds(void){struct timeval tval;struct timezone tz;

gettimeofday(&tval, &tz);return (tval.tv_sec + tval.tv_usec*1e-6);

}#endif

Questo frammento di codice deve stabilire quali header-file vanno inclusi al fine di acce-dere a delle funzioni di sistema che restituiscono l’ora corrente e permettano di gestiredei calcoli in realtime (cioè che avvengano rispettando una precisa scansione temporale).Attraverso il preprocessore, nella prima direttiva condizionale viene verificata l’esistenzadella costante __GNUC__ e la non esistenza delle costanti sgi ed _MSC_VER. La prima vie-ne definita di default dai compilatori gcc e g++, che fanno parte della distribuzione GNU[21, 24]. Le altre due sono analoghe costanti definite, rispettivamente, dal compilatoredel sistema operativo Irix, sviluppato da Silicon Graphics (SGI) [32], e dall’ambiente disviluppo Microsoft Visual C++ [27] (compilatore cl.exe). Per questioni legate alle tecno-logie dei sistemi di compilazione, è necessario in questo caso dover includere il file time

se __GNUC__ è definita; diversamente, ad esempio, se si sta compilando con Microsoft

A. De Marco

Page 59: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.2 Il mondo delle classi e degli oggetti 59

Visual Studio sarà necessario leggere il file time.h.Anche la successiva direttiva di compilazione condizionale verifica il tipo di com-

pilatore utilizzato e include gli header-file opportuni. La costante __BORLANDC__ è defi-nita automaticamente dall’ambiente di sviluppo Borland C++Builder [26] (compilatorebcc32.exe) e la costante __MINGW32__ è definita dall’ambiente di compilazione Mingw[25] (compilatore mingw32.exe).

Infine, più avanti nel codice sorgente si rende necessaria la definizione della funzio-ne getcurrentseconds che deve restituire il tempo di sistema (come numero in doppiaprecisione, inclusa una parte decimale, che esprime i secondi trascorsi a partire dallamezzanotte dell’anno 1969). Come si vede ispezionando il codice, questa funzione deveessere definita diversamente a seconda del compilatore in uso.

L’uso delle direttive di compilazione permette di architettare il codice sorgente inmaniere che possono diventare anche molto sofisticate. Uno dei vantaggi più evidentiè che in questo modo è possibile sviluppare programmi in grado di essere compilati dadiversi sistemi di sviluppo e per diversi sistemi operativi. Ciò si esprime dicendo che ilsoftware è portabile e multipiattaforma.

2.2 Il mondo delle classi e degli oggetti

Il termine “tipo astratto”, usato in contrapposizione ai tipi nativi del linguaggio, non èmolto appropriato: il C++ consente al programmatore di definire nuovi tipi, estendendocosì le capacità effettive del linguaggio; ma, una volta definiti, questi tipi sono molto“concreti” e sono trattati esattamente come i tipi nativi. Per questo motivo, la tendenzamoderna è di identificare i tipi non nativi con il termine: “tipi definiti dall’utente” (user-defined types) e di confinare l’aggettivo “astratto” a una precisa sottocategoria di questi(di cui parleremo più avanti).

In questa sezione parleremo dei tipi astratti comuni sia al C che al C++, usando peròla nomenclatura del C++ (“oggetti”, “istanze”, eccetera).

2.2.1 Tipi definiti dall’utente e terminologia

Il termine “oggetto” è sostanzialmente sinonimo del termine “variabile”. Benché questo Oggetti

termine si usi soprattutto in relazione ai tipi definiti dall’utente (come strutture o classi),si può generalizzare il concetto, definendo oggetto una variabile di qualunque tipo, nonsolo formalmente definita, ma anche già creata e operante.

È noto infatti che l’istruzione di definizione di una variabile non si limita a dichiarare Costruire oggetti

il suo tipo, ma crea fisicamente la variabile stessa, allocando la memoria necessaria (nellaterminologia C++ si dice che la variabile viene “costruita” o “istanziata”): pertanto ladefinizione di una variabile comporta la “costruzione” di un oggetto.

Il termine “istanza” è quasi simile al termine oggetto; se ne differenzia in quantosottolinea l’appartenenza dell’oggetto a un dato tipo (istanza di “qualcosa”). Per esempio,la dichiarazione/definizione:

int ivar ;

costruisce l’oggetto ivar, istanza del tipo int. Dunque, “istanziare un certo tipo” significa Creare istanzianze di untipo di datocreare un’istanza di quel tipo.

Appunti di programmazione a oggetti in C++ e Matlab

Page 60: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

60 Capitolo 2 Ancora sulla programmazione in C++

L’istruzione introdotta dalla parola-chiave typedef definisce un sinonimo di un tipoLa parola chiavetypedef esistente, cioè non crea un nuovo tipo, ma un nuovo identificatore di un tipo (nativo o

astratto) precedentemente definito. Ad esempio:

typedef unsigned long int* Pul ;

definisce il nuovo identificatore di tipo Pul, che potrà essere usato, nelle successivedichiarazioni (all’interno dello stesso ambito), per costruire oggetti di tipo puntatore aunsigned long. Ecco alcuni esempi:

unsigned long a;Pul ogg1 = &a;Pul parray[100]; // eccetera

L’uso di typedef permette di semplificare dichiarazioni lunghe di variabili dello stessotipo. Per esempio, supponiamo di dover dichiarare molti array, tutti dello stesso tipo edella stessa dimensione:

double a1[100];double a2[100];double a3[100]; // eccetera

Usando typedef la semplificazione è evidente:

typedef double MyArray[100];MyArray a1, a2, a3;

2.2.2 Le strutture

Come gli array, in C++ (e in C) le strutture sono gruppi di dati. A differenza dagli array,i singoli componenti di una struttura possono essere di tipo diverso. Ecco un esempio diLa parola chiave struct

definizione di una struttura tramite la parola chiave struct (che il C++ eredita dal C):

struct Anagrafico{

char nome[20];int anni;char indirizzo[30];

} ;

Dopo la parola-chiave struct segue l’identificatore della struttura, detto anche marcatoreo tag, e, fra parentesi graffe, l’elenco dei componenti della struttura, detti membri o campi.Ogni membro è dichiarato come una normale variabile (è una semplice dichiarazione, nonuna definizione, e pertanto non comporta la creazione dell’oggetto corrispondente) e puòessere di qualunque tipo (anche array o puntatore o una stessa struttura). Dopo la parentesigraffa di chiusura, è obbligatoria la presenza del punto e virgola (diversamente dai blocchidelle funzioni).

In C++ (e non in C) la definizione di una struttura comporta la creazione di un nuovotipo, il cui nome coincide con il tag della struttura. Pertanto, nell’esempio appena fatto,Anagrafico è a pieno titolo un tipo (come int o double), con la sola differenza che sitratta di un tipo astratto, non nativo del linguaggio.

Per questo motivo l’enunciato di una struttura è una definizione e non una semplicedichiarazione: crea un’entità (il nuovo tipo) e ne descrive il contenuto. Ma, diversamentedalle definizioni delle variabili, non alloca memoria, cioè non crea oggetti. Perchè ciò

A. De Marco

Page 61: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.2 Il mondo delle classi e degli oggetti 61

avvenga, il nuovo tipo deve essere istanziato, esattamente come succede per i tipi nativi.Riprendendo l’esempio, l’istruzione di definizione:Anagrafico davide, giovanni, cugini[30] ;

costruisce gli oggetti davide, giovanni e l’array cugini, istanze del tipo Anagrafico.Solo adesso viene allocata memoria, per ogni oggetto in quantità pari alla somma dellememorie che competono ai singoli membri della struttura* L’operatore sizeof( ... ) può essere applicato sia al tipo Anagrafico sia ad una sua istanza (ad

esempio sizeof(Anagrafico) o sizeof(davide)) e restituisce il numero dei bytes allocati ad ogni istanzadi Anagrafico).

La collocazione ideale della definizione di una struttura è in un header-file: conviene Gli header-file

infatti separarla dalle sue istanze, in quanto la definizione deve essere (di solito) acces-sibile dappertutto, mentre le istanze sono normalmente locali e quindi limitate dal loroambito di visibilità.* Potrebbe però sorgere un problema: se un programma è suddiviso in più files sorgente e tutti includono

lo stesso header-file contenente la definizione di una struttura, dopo l’azione del preprocessore risulterannodiverse translation unit con la stessa definizione e quindi sembrerebbe violata la “regola della definizio-ne unica” (o one-definition-rule, ODR). Questo problema viene tipicamente risolto creando una costantepredefinita per ciascun header-file e facendo in modo che il preprocessore non lo legga più di una volta.

Ecco come un programmatore C++ scriverebbe il file Anagrafico.h:#ifndef ANAGRAFICO_H#define ANAGRAFICO_Hstruct Anagrafico{hdefinizione dei campii

} ;#endif

Se è necessario includere questo file in diversi file sorgente, il preprocessore controlleràl’avvenuta definizione della macro ANAGRAFICO_H. La prima volta che il preprocessore sitrova a leggere Anagrafico.h sarà quella in cui resterà definita la macro ANAGRAFICO_H.Nel resto del processo di precompilazione, se dovesse essere richiesta la rilettura del fileheader, l’esito del controllo #ifndef ANAGRAFICO_H sarà falso e non ci sarà il rischio diridefinire il tipo Anagrafico più volte.

La grande utilità delle strutture consiste nel fatto che i nomi delle sue istanze posso- L’operatore . (punto)

no essere usati direttamente come operandi in molte operazioni o come argomenti nellechiamate di funzioni, consentendo un notevole risparmio, soprattutto quando il numerodi membri è elevato. In alcune operazioni, tuttavia, è necessario accedere a un mem-bro individualmente. Ciò è possibile grazie all’operatore binario . (punto) di accessoal singolo membro: questo operatore ha come left-operand il nome dell’oggetto e comeright-operand quello del campo. Ad esempio: davide.indirizzo.

Come altri operatori che svolgono compiti analoghi (per esempio l’operatore [ ] diaccesso al singolo elemento di un array), anche l’operatore . può restituire sia la lettura diun dato (un cosiddetto r-value) che l’inserimento di un dato (un cosiddetto l-value). Eccodue esempi:int a = davide.anni; // inizializza a con il valore del campo

// "anni" dell’oggetto davidegiovanni.anni = 1; // inserisce 1 nel campo anni dell’oggetto

// giovanni

Appunti di programmazione a oggetti in C++ e Matlab

Page 62: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

62 Capitolo 2 Ancora sulla programmazione in C++

2.2.3 Dalle strutture alle classi

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut,placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero,nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque.Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis ege-stas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urnafringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer sapien est,iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum.Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabi-tur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsaneleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim rutrum.

Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor loremnon justo. Nam lacus libero, pretium at, lobortis vitae, ultricies et, tellus. Donec aliquet,tortor sed accumsan bibendum, erat ligula aliquet magna, vitae ornare odio metus a mi.Morbi ac orci et nisl hendrerit mollis. Suspendisse ut massa. Cras nec ante. Pellentesquea nulla. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculusmus. Aliquam tincidunt urna. Nulla ullamcorper vestibulum turpis. Pellentesque cursusluctus mauris.

2.3 La libreria standard

Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor loremnon justo. Nam lacus libero, pretium at, lobortis vitae, ultricies et, tellus. Donec aliquet,tortor sed accumsan bibendum, erat ligula aliquet magna, vitae ornare odio metus a mi.Morbi ac orci et nisl hendrerit mollis. Suspendisse ut massa. Cras nec ante. Pellentesquea nulla. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculusmus. Aliquam tincidunt urna. Nulla ullamcorper vestibulum turpis. Pellentesque cursusluctus mauris.

Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at, tincidunttristique, libero. Vivamus viverra fermentum felis. Donec nonummy pellentesque ante.Phasellus adipiscing semper elit. Proin fermentum massa ac quam. Sed diam turpis,molestie vitae, placerat a, molestie nec, leo. Maecenas lacinia. Nam ipsum ligula, eleifendat, accumsan nec, suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc eleifendconsequat lorem. Sed lacinia nulla vitae enim. Pellentesque tincidunt purus vel magna.Integer non enim. Praesent euismod nunc eu purus. Donec bibendum quam in tellus.Nullam cursus pulvinar lectus. Donec et mi. Nam vulputate metus eu enim. Vestibulumpellentesque felis eu massa.

2.4 Le librerie Boost

Le librerie Boost per il C++ sono state create con lo scopo di estendere quelle Standard.Sono, inoltre, concepite per essere ampiamente utili ed usabili in molte applicazioni.

A. De Marco

Page 63: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.5 Esempi 63

2.5 Esempi

2.5.1 Una classe completa per la lettura dati da file

Si ha il problema di leggere delle storie temporali di alcune grandezze fisiche immagazzi-nate in un file di testo nel formato csv (comma-separated values). Per ciascun parametro,I dati sono contenuti in colonne. In ciascuna riga di testo i valori reali, di cui il primo è untempo, sono separati da virgole. Per facilitare la lettura e l’interpretazione delle colonnedi dati, la prima riga del file contiene dei nomi separati da virgole (stringhe di caratteri), innumero pari al numero delle colonne di dati. Ecco un esempio di file di nome mydata.csv

con tre colonne di dati, oltre a quella dei tempi:

Time , P (deg/s), Q (deg/s), R (deg/s), P dot (deg/s^2)0.0333332, -0.00015656, -4.292971189, 0.00002302, -0.0059369290.0833330, -0.00062498, -7.185558850, 0.00010837, -0.0106424810.1416661, 0.00000000, 0.000934767, -0.00000000, 0.0000004340.1916659, 0.00000010, 0.001996633, -0.00000001, 0.0000030590.2416657, 0.00000038, 0.000776778, -0.00000006, 0.0000069220.2916655, 0.00000088, -0.003406548, -0.00000015, 0.0000113410.3416653, 0.00000160, -0.010372289, -0.00000032, 0.0000160140.3916651, 0.00000256, -0.019579002, -0.00000055, 0.0000207640.4416649, 0.00000375, -0.030411132, -0.00000096, 0.0000255270.4916647, 0.00000519, -0.042320402, -0.00000139, 0.0000302470.5416645, 0.00000685, -0.054878723, -0.00000197, 0.0000348960.5916643, 0.00000875, -0.067782347, -0.00000266, 0.0000394670.6416641, 0.00001087, -0.080833323, -0.00000344, 0.0000439180.6916639, 0.00001321, -0.093913868, -0.00000449, 0.000048246...

Il file header della classe ADM::DataFile è il seguente:

//-------------------------------// File: DataFile.h// Author: Agostino De Marco// Date: April 2009//-------------------------------#ifndef DATAFILE_H#define DATAFILE_H

#include <fstream>#include <cstdio>#include <string>#include <vector>#include <cmath>#include <iostream>

using namespace std;

/* This class handles reading a data file containingtime histories in csv format (comma-separated values):- data are stored in columns- first row is a comma-separated list of names- first colum represents time (sec)

*/

Appunti di programmazione a oggetti in C++ e Matlab

Page 64: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

64 Capitolo 2 Ancora sulla programmazione in C++

namespace ADM {

class DataFile {public:DataFile();~DataFile();DataFile(string fname);

std::vector <string> names;string data_str;typedef std::vector <double> Row;typedef std::vector <Row> DataType;DataType Data;

int GetNumFields(void) {if (Data.size() > 0) return(Data[0].size());else return(0);

}int GetNumRecords(void) {return(Data.size());

}double GetStartTime(void) {if (Data.size() >= 2) return(Data[0][0]);else return(0);

}double GetEndTime(void) {if (Data.size() >= 2) return(Data[Data.size()-1][0]);else return(0);

}double GetMax(int column) {return(Max[column]);}double GetMin(int column) {return(Min[column]);}double GetRange(int field) {return (GetMax(field) - GetMin(field));

}void SetStartIdx(int sidx) {StartIdx = sidx;}void SetEndIdx(int eidx) {EndIdx = eidx;}int GetStartIdx(void) {return StartIdx;}int GetEndIdx(void) {return EndIdx;}bool IsOk() {return fileGood;}void NicePrintNames(void);

private:string buff_str;ifstream f;Row Max;Row Min;int StartIdx, EndIdx;bool fileGood;

string stripSpaceLE(string str);string stripSpaceTE(string str);

};} // end namespace ADM

A. De Marco

Page 65: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.5 Esempi 65

#endif

Ecco un esempio di possibile utilizzo della classe:

//-------------------------------// File: test1.cpp// Author: Agostino De Marco// Date: April 2009//-------------------------------#include "DataFile.h"

#include <iostream>#include <fstream>#include <cstdio>#include <cstdlib>

using namespace std;using namespace ADM;

int main(int argc, char *argv[]){

if (argc > 2 || argc == 1 ) {cout << endl

<< "\tUsage: test1.exe <data_file_name.csv>" << endl;exit(-1);

}

ADM::DataFile df(argv[1]);

df.NicePrintNames();

int numvars = df.GetNumFields();int numpoints = df.GetNumRecords();double starttime = df.GetStartTime();double endtime = df.GetEndTime();

cout << endl;cout << endl << "Data file contains "

<< numvars << " independent variables." << endl;cout << "Number of data points: "

<< numpoints << endl;cout << "Time goes from "

<< starttime << " to " << endtime << " seconds." << endl;return 0;

}

Se si lancia il programma test1.exe con la riga di comando:

>> test1.exe mydata.csv

si avrà in output:

File mydata.csv successfully opened.Done parsing names. Reading data ...Done Reading data.

Here are the available parameters:0) Time 1) P (deg/s)

Appunti di programmazione a oggetti in C++ e Matlab

Page 66: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

66 Capitolo 2 Ancora sulla programmazione in C++

2) Q (deg/s) 3) R (deg/s)4) P dot (deg/s^2)

Data file contains 4 independent variables.Number of data points: 320Time goes from 0.0333332 to 15.9916 seconds.

2.6 Come imparare il C++

Come è noto, un linguaggio di programmazione ha due scopi correlati: (i) fornire i mezziperché il programmatore possa specificare le azioni da eseguire, e (ii) fornire un insiemedi concetti per pensare a quello che può essere fatto. Il primo scopo richiede che il lin-guaggio sia vicino alla macchina, per permettere che tutti gli importanti aspetti legati allamacchina siano trattati in una maniera ragionevolmente ovvia per il programmatore. Illinguaggio C fu progettato con in mente questo scopo. Il secondo scopo richiede che illinguaggio sia vicino al problema da risolvere, di modo che i concetti necessari alla so-luzione siano direttamente e concisamente esprimibili. Le potenzialità aggiunte al C percreare il C++ sono state progettate pensando a questo obiettivo.

Imparare direttamente il C++, per i programmatori che non conoscono il C, dovrebbeessere la strada da seguire. Il C++ è più sicuro, più espressivo e riduce il bisogno diconcentrarsi su tecniche di basso livello. Per i programmatori che conoscono il C, ilvantaggio di imparare il C++ equivale al grande vantaggio che si ha nelle lingue naturalidi essere essere almeno bilingui.

Per imparare il C++, la cosa più importante è concentrarsi sui concetti, senza perdersinei dettagli tecnici del linguaggio. Come sostiene Bjarne Stroustrup nel suo testo C++– Linguaggio, libreria standard, principi di programmazione [1]: si impara un nuovolinguaggio di programmazione per diventare programmatori migliori; cioè per diventa-re più bravi nel progettare e realizzare nuovi sistemi e nel mantenere quelli vecchi. Perquesto motivo, arrivare a padroneggiare le tecniche di programmazione e progetto do-vrebbe essere molto più importante che comprendere subito i dettagli del linguaggio. Lacomprensione, di solito, viene col tempo e la pratica.

Si deve tener presente che il C++ supporta molti stili di programmazione. Tutti sonobasati sul controllo rigoroso dei tipi (strong type checking), e hanno lo scopo di rag-giungere un livello di astrazione piuttosto alto e la diretta rappresentazione delle ideedel programmatore. Ogni tecnica di programmazione può raggiungere i suoi obiettiviefficacemente, mantenendo efficiente l’uso delle risorse di tempo e memoria.

Chi è pratico di altri linguaggi (ad esempio il C, il Fortran o il Matlab) dovrebbeconvincersi che per sfruttare i benefici del C++ occorre spendere tempo per imparare eassimilare gli stili di programmazione e le tecniche adatte al C++ (specialmente il para-digma di programmazione a oggetti). Un programmatore abituato a lavorare col Fortran,ad esempio, potrebbe certamente scrivere programmi in C++ adottando solamente il pa-radigma di programmazione procedurale a cui è abituato. Egli deve però confrontarsi conla realtà di fatto in cui l’applicazione non meditata a un linguaggio di tecniche efficaciin un linguaggio differente porta generalmente a un codice difficile da capire, arduo damantenere e di scarsa efficienza.

A. De Marco

Page 67: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

2.6 Come imparare il C++ 67

Il C++ può essere appreso gradualmente. Il modo con cui si impara un nuovo linguag-gio dipende da ciò che già si conosce e dagli scopi che ci si prefigge. Probabilmente lospirito migliore con cui un programmatore può cimentarsi con il C++ non è tanto quellodi acquisire una nuova sintassi con cui realizzare le stesse cose di prima, ma, piuttosto,quello di apprendere modi nuovi e migliori di costruire sistemi. Ciò equivale a cercaredi diventare un programmatore e un progettista migliore. Questo deve essere, per forzadi cose, un processo graduale, perché l’acquisizione di nuove capacità richiede tempo epratica: basti pensare quanto tempo occorre per apprendere bene una nuova lingua o im-parare a suonare un nuovo strumento musicale. Migliorare come programmatore e comeprogettista di programmi è senz’altro più semplice e veloce, ma non così semplice comesi vorrebbe.

Appunti di programmazione a oggetti in C++ e Matlab

Page 68: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Page 69: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Capitolo 3

Strumenti di sviluppo

I quickly found out that C++ programmers are thesmartest programmers in the world, as each one I met

would quickly point out to me.

– Don Box

Indice3.1 Il Compilatore gcc in ambiente GNU/Linux o Cygwin . . . . . . . . 693.2 Ambienti integrati di sviluppo (IDE) . . . . . . . . . . . . . . . . . . 71

[capitolo incompleto]

3.1 Il Compilatore gcc in ambiente GNU/Linux o Cygwin

Per GNU/Linux [22] e nelle finestre Cygwin [24] in ambiente Windows è disponibile uncompilatore integrato C/C++ che si invoca con i comandi gcc e g++, rispettivamente. Inrealta g++ è uno script che chiama gcc con opzioni specifiche per riconoscere il C++.

La schermata di una finestra di Cygwin è mostrata nella figura 3.1, nella quale si vedel’output del comando gcc -v che ottiene la versione del compilatore gcc in uso.

3.1.1 Il progetto GNU

Il comando gcc, che sta per GNU Compiler Collection, fa parte del progetto GNU [21].Il progetto GNU fu lanciato nel 1984 da Richard Stallman con lo scopo di sviluppare unsistema operativo di tipo Unix che fosse un software completamente liberoi free software.

È ormai famoso il gioco di parole “Cosa è GNU? Gnu Non è Unix!”, che contiene unasottile ricorsione. Riporto un estratto dal manifesto del progetto GNU http://www.gnu.

org/gnu/manifesto.html, scritto da Richard Stallman:

GNU, che sta per “Gnu’s Not Unix” (Gnu Non è Unix), è il nome del siste-ma software completo e Unix-compatibile che sto scrivendo per distribuirloliberamente a chiunque lo possa utilizzare. Molti altri volontari mi stannoaiutando. Abbiamo gran necessità di contributi in tempo, denaro, programmie macchine.

Page 70: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

70 Capitolo 3 Strumenti di sviluppo

3.1.2 I passi della compilazione

Sia gcc che g++ processano file di input attraverso uno o più dei seguenti passi:1. preprocessing, cioè

– la rimozione dei commenti, e– l’interpretazione di speciali direttive per il preprocessore denotate da #, come:

#include, che include il contenuto di un determinato file, #define, che definisceun nome simbolico o una variabile, eccetera;

2. compilation, cioè la traduzione del codice sorgente ricevuto dal preprocessore incodice assembly;

3. assembly, cioè la creazione del codice oggetto;4. linking, ovvero la combinazione delle funzioni definite in altri file sorgenti o definite

in librerie con la funzione main() per creare il file eseguibile.

Figura 3.1 Schermata di una finestra dei comandi Cygwin [24]. È mostrato l’output del comandogcc -v che ottiene la versione del compilatore gcc in uso.

3.1.3 L’utilità make

Il programma make è una utility usata con i sistemi operativi della famiglia UNIX cheautomatizza il processo di conversione dei file da una forma ad un’altra, risolvendo ledipendenze e invocando altri programmi per il lavoro necessario alle diverse operazioni.

Molto frequentemente make è usato per la compilazione di codice sorgente in codiceoggetto, unendo e poi collegando il codice oggetto in una forma finale corrispondente adun esegubile o ad una libreria. Il comando make usa file chiamati makefiles per deter-minare il grafico delle dipendenze per un particolare output, e gli script necessari per lacompilazione da passare alla shell dei comandi (ad esempio una shell Bash). Il termine“makefile” proviene dal nome di default makefile o Makefile che make va a cercare seinvocato senza parametri aggiuntivi.

Ecco un semplice esempio di Makefile che serve a creare l’eseguibile myfgfsclient.exea partire dalla compilazione dei file myfgfsclient.cpp e datafile.cpp

# Makefile for the program myfgfsclientVERSION = 0.1

A. De Marco

Page 71: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

3.2 Ambienti integrati di sviluppo (IDE) 71

CC = g++OPTIMIZE = -g -WallCFLAGS = $(DEFINES) $(OPTIMIZE)LFLAGS = -lstdc++ -lmPROGS = myfgfsclient.exePROGS_O = myfgfsclient.o datafile.oLIBS =all: objs progs

progs:$(CC) $(CFLAGS) $(LFLAGS) -o $(PROGS) $(PROGS_O) $(LIBS)

objs: $(PROGS_O)

.cpp.o:$(CC) $(CFLAGS) -c -o $*.o $<

.o:$(CC) $(CFLAGS) $(LFLAGS) -o $* $(PROGS_O) $(LIBS)

clean: cleanbinrm -f *.o *~

cleanbin:rm -f $(PROGS)

dep:rm -f .dependmake .depend

tar:tar czvf myfgfsclient.tgz Makefile \myfgfsclient.cpp datadile.h datafile.cpp README TODO

Posizionandosi nella cartella in cui risiede il Makefile ed i sorgenti del programmal’utente potrà lanciare il comando:

>> make

ottenendo la creazione del file mtfgfsclient.exe se questo era assente o possiede unadata di creazione precedente a uno qualsiasi dei file da cui dipende (sorgenti o oggetto).

Per approfondimenti sulle funzionalità avanzate della utility make si rimanda il lettorealla consultazione del manuale online di GNU make [23].

3.2 Ambienti integrati di sviluppo (IDE)

Un Integrated Development Environment (IDE) è un’applicazione interattiva che aiuta losviluppatore di software (cioè il programmatore) a costruire un progetto. Un progetto è uninsieme di file, contenenti codice sorgente, che vengono letti ed elaborati dal compilatoreseparatamente e poi collegati insieme (tramite il linker) per costruire un unico file incodice binario, contenente il programma eseguibile, che può essere a sua volta lanciatodallo stesso IDE o autonomamente da sistema operativo.

Appunti di programmazione a oggetti in C++ e Matlab

Page 72: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

72 Capitolo 3 Strumenti di sviluppo

Figura 3.2 Schermata di una sessione di lavoro con Microsoft Visual C++ 2008 Express [27].

Lo sviluppatore interagisce con l’ambiente di svilutto tramite menu di tipo pop-up (atendina); in genere le voci di menu più significative sono selezionabili anche tramite tool-bars (gruppi di icone) o tramite i cosiddetti acceleratori (tasti della keyboard che eseguonola stessa funzione della corrispondente voce di menu).

Un IDE può aprire sullo schermo e usare parecchie finestre contemporaneamente,contenenti i files sorgente (uno per ogni finestra), l’output del programma, le informazio-ni acquisite in fase di debug, eccetera. Possono esistere anche finestre che contengonol’elenco dei file, delle funzioni, o anche delle singole variabili utilizzate; “cliccando” suqueste voci si può raggiungere rapidamente la parte di programma che interessa esaminareo modificare.

3.2.1 L’ambiente di sviluppo Microsoft Visual Studio

Qui illustreremo brevemente l’utilizzo di Microsoft Visual C++, disponibile per il siste-ma operativo Windows (http://www.microsoft.com/express/vc/). Il Visual C++ non èsoltanto un IDE, ma un linguaggio vero e proprio, essendo dotato di funzionalità e librerieche vanno ben oltre lo standard C++. Ci limiteremo, però, ad illustrare il suo ambiente disviluppo, nella versione “ridotta” per applicazioni che utilizzano solo codice standard.

3.2.2 L’ambiente di sviluppo Code::Blocks

L’ambiente di sviluppo Code::Blocks è un IDE libero, open source e multipiattaforma(http://www.codeblocks.org/). È scritto in C++ usando le librerie del toolkit graficowxWidgets [31]. L’ambiente utilizza un’architettura basata su plugin, le sue capacitàe caratteristiche sono estese proprio dai plugin installati dall’utente a seconda delle sueesigenze. Attualmente, Code::Blocks è orientato verso il C/C++.

Code::Blocks è disponibile per Windows, GNU/Linux e Mac OS X.

A. De Marco

Page 73: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

3.2 Ambienti integrati di sviluppo (IDE) 73

Figura 3.3 La finestra di esplorazione della solution in Microsoft Visual C++ 2008 Express.

Appunti di programmazione a oggetti in C++ e Matlab

Page 74: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

74 Capitolo 3 Strumenti di sviluppo

Figura 3.4 La finestra di configurazione delle proprietà di un progetto in Microsoft Visual C++2008 Express (Menu Project, Properties; oppure clic con pulsante destro sulla voce del progettonella finestra di esplorazione, Properties dal menu a tendina, come nella figura 3.4). I parametridel del processo di compilazione e collegamento possono essere impostati per tutte le possibiliconfigurazioni (Debug, Release) o resi specifici per ciascuna di esse.

Figura 3.5 Particolare della configurazione delle proprietà di compilazione (C/C++, General). Inquesto esempio l’utente ha impostato un percorso aggiuntivo, oltre a quello di default del compi-latore Microsoft, per la ricerca degli header file (Additional Include Direcoties).

A. De Marco

Page 75: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

3.2 Ambienti integrati di sviluppo (IDE) 75

Figura 3.6 Particolare della configurazione delle proprietà di collegamento (Linker, General). Inquesto esempio l’utente ha impostato un percorso personalizzato per il file eseguibile. Nella casellaOutput File si ha la macro $(ProjectDir)..\test\$(ProjectName).exe, che Visual Studio espanderàsostituendo dei percorsi concreti ai simboli $(ProjectDir) e $(ProjectName).

Figura 3.7 Finestra di dialogo attraverso la quale è possibile modificare il percorso dell’OutputFile (figura 3.6). Visual Studio mostra i risultati dell’espansione di un nutrito numero di simbolipredefiniti, tra cui i percorsi di sistema $(FrameworkDir) e $(FrameworkSDKDir).

Appunti di programmazione a oggetti in C++ e Matlab

Page 76: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

76 Capitolo 3 Strumenti di sviluppo

Figura 3.8 La finestra di output (o di log) della compilazione e del collegamento (Menu Project,Build hnome progettoi).

Figura 3.9 Schermata di una sessione di lavoro con Code::Blocks [28].

A. De Marco

Page 77: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Parte II

Programmazione a oggetticon Matlab

Page 78: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Acquisisci nuove conoscenze mentre rifletti sulle vecchie,e forse potrai insegnare ad altri.

– Confucio

Page 79: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Capitolo 4

Una panoramica su Matlab

Jesce sole, jesce sole, nun ce fa’ cchiù suspirà!

– Gatta Cenerentola

Indice4.1 Elementi di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794.2 Toolboxes e Simulink . . . . . . . . . . . . . . . . . . . . . . . . . . 804.3 Sessioni di lavoro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814.4 Usare l’help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.5 Nozioni e notazioni fondamentali . . . . . . . . . . . . . . . . . . . . 844.6 Operazioni di Input / Output . . . . . . . . . . . . . . . . . . . . . . 91

4.1 Elementi di base

Matlab è un linguaggio di programmazione di alto livello nato per il calcolo tecnico-scientifico. Le funzionalità di Matlab in quanto applicazione rispecchiano la filosofia concui essa è stata progettata e sviluppata via via negli anni. L’ambiente di lavoro è struttu-rato in modo da risultare particolarmente utile nei seguenti campi applicativi: (i) Analisinumerica e calcolo, (ii) sviluppo di codice e scripting, (iii) modellistica, simulazionee prototyping, (iv) analisi di dati, esplorazione e visualizzazione, (v) disegno industria-le e scientifico, (vi) sviluppo di applicazioni stand-alone corredate di interfaccia utente(Graphical User Interface, GUI).

Matlab, il cui nome deriva da Matrix Laboratory, inteso come ambiente di sviluppo,fornisce un linguaggio per il calcolo che ha come struttura di base la matrice. Gli scalarisono matrici 1 � 1, i vettori riga sono matrici 1 � n ed i vettori colonna sono matricim � 1. Le due dimensioni principali di questi array vengono dedotte dal contesto delleistruzioni di assegnamento. In momenti successivi è sempre possibile un reshaping, cioèun adattamento di una data matrice m � n a delle nuove dimensioni m0 � n0 attraverso ilriposizionamento, l’aggiunta o la sottrazione di elementi.

Esiste anche la possibilità, come accade per altri linguaggi di programmazione, didefinire ed utilizzare array multidimensionali. Questi sono delle generalizzazioni dellematrici e costituiscono delle collezioni di dati accessibili mediante tre o più indici.

Page 80: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

80 Capitolo 4 Una panoramica su Matlab

Matlab esegue tutti i calcoli numerici con numeri complessi in doppia precisione e lagrande maggioranza delle operazioni e delle funzioni predefinite sono implementate inmodo da lavorare nativamente su entità matriciali. Ciò è particolarmente vantaggioso nel-la risoluzione di molti problemi di calcolo dell’ingegneria, in particolare quelli formulatiteoricamente nei testi con agevoli notazioni vettorali e matriciali. Tali problemi posso-no essere implementati in linguaggio Matlab e risolti efficientemente attraverso comandisemplici, con un minimo utilizzo di cicli. Ad esempio, per la soluzione dei tipici proble-mi dell’algebra lineare è possibile, con poche righe di codice e senza un appesantimentodel carico di lavoro del programmatore, richiamare un numero di algoritmi ben collaudatibasati sulle funzionalità di librerie come LINPACK, LAPACK o EISPACK.

I codici di calcolo in linguaggio Matlab sono generalmente più snelli rispetto a quelliche sarebbe necessario sviluppare con un linguaggio scalare come il C o il Fortran 77.Anche se linguaggi di programmazione più evoluti come il C++, con il paradigma di pro-grammazione a oggetti, e come il Fortran 90/95, con l’uso avanzato dei moduli, permetto-no ormai una implementazione snella ed efficiente di una vasta categoria di algoritmi, lapopolarità di Matlab, con il suo linguaggio intuitivamente più semplice da imparare e conla sua ben riuscita integrazione tra lo strumento di sviluppo codice, il debugger e l’outputgrafico, rende il “laboratorio della matrice” uno strumento più attraente per chi si accostaal mondo della programmazione o per chi ha in mente tempi di sviluppo ridotti.

L’ambiente Matlab si è evoluto durante gli anni grazie al feedback ed al contributo deimolti utenti sparsi per il mondo. In ambienti universitari è ormai uno strumento didatticostandard per corsi introduttivi e corsi avanzati, nella matematica, nell’ingegneria e nellescienze.

4.2 Toolboxes e Simulink

L’ambiente possiede dei gruppi tematici di funzioni, denominate toolboxes (cassette degliattrezzi), pensati ed implementati ad hoc per classi particolari di problemi. Essi risultanomolto utili per la maggior parte degli utenti di Matlab e sono pensati per fornire all’uten-te degli strumenti di calcolo preconfezionati, efficienti e specializzati. I toolboxes sonocollezioni complete di funzioni Matlab che estendono l’ambiente di lavoro e permettonodi risolvere particolari categorie di problemi. Le aree scientifiche per le quali sono di-sponibili dei toolboxes specifici sono numerose. Alcuni esempi sono: l’elaborazione deisegnali, i sistemi di controllo, le reti neurali, le wavelets, la simulazione in generale, ilcalcolo simbolico, la realtà virtuale.

Di particolare importanza è il pacchetto software Simulink, utilizzabile come modulodell’ambiente Matlab, e concepito per la modellazione e l’analisi di sistemi dinamici.Simulink supporta sia modelli lineari che non lineari, a tempo continuo e discreto. Sipossono modellare sistemi a vettore di stato di dimensione qualsiasi e di tipo multirate, incui diversi sottogruppi di variabili di stato sono aggiornate con frequenze differenti.

Per la modellazione Simulink fornisce un’interfaccia a finestre, che si avvia digitandoil comando simulink nella finestra dei comandi di Matlab, figura 4.4, o con l’appositotasto di avvio nell’interfaccia principale. L’uso della GUI di Simulink permette la co-struzione di un modello a partire dal disegno, dalla collezione ed dalla interconnessionedi blocchi funzionali, proprio come si farebbe in una fase di analisi preliminare di un si-stema (prototyping) con l’uso di carta e penna. Simulink è dotato di un’ampia libreria

A. De Marco

Page 81: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

4.3 Sessioni di lavoro 81

di blocchi e di tipi di connessioni preconfezionati. L’utente può ovviamente personaliz-zare delle entità già presenti nelle librerie di default o crearne delle proprie. Si rimandaall’help di Matlab per approfondimenti sulle modalità di implementazione delle cosiddetteS-functions.

Un pacchetto di funzioni Simulink di notevole utilità nel campo aerospaziale ed inparticolare nella dinamica del volo è costituito dal toolbox Aerospace Blockset (nelle ver-sioni di Matlab non inferiori alla 6.5) per l’analisi e l’integrazione di sistemi dinamici chemodellano il funzionamento di velivoli di vario genere e di sistemi propulsivi.

4.3 Sessioni di lavoro

Di solito Matlab viene lanciato selezionando l’applicazione da un ambiente a finestre co-me Windows o fornendo il comando matlab in una delle shell di comandi Unix/Linux.Matlab è a sua volta un programma con una riga dei commandi ed un suo prompt >>.Appena lanciato compare per qualche istante, prima dell’avvio vero e proprio dell’appli-cazione e durante il caricamento di tutti i moduli software necessari al suo funzionamento,una finestra (splash screen) con il logo di Matlab, la versione ed il tipo di licenza. Se ciòaccade significa che tutto è stato configurato correttamente, in caso contrario è necessariocontrollare la validità dell’installazione o della licenza.

Figura 4.1 Il layout di default della finestra principale di Matlab: in alto a sinistra il workspacecon le variabili definite al momento dell’ultimo comando; in basso a sinistra la storia dei comandipiù recenti; a destra la finestra con il prompt dei comandi.

Una volta avviata l’applicazione, il layout di default della finestra principale di Matlab,come si vede dalla figura 4.1, si presenta come l’insieme di più sotto-finestre: la finestracon il prompt dei comandi, la finestra del workspace con le variabili definite al momentodell’ultimo comando ed una finestra con la storia dei comandi più recenti. La command

Appunti di programmazione a oggetti in C++ e Matlab

Page 82: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

82 Capitolo 4 Una panoramica su Matlab

Figura 4.2 L’editor di M-files di Matlab in grado di aprire più di un file di script alla volta ecorredato di tasti per l’avvio e la gestione del debug.

window svolge anche il ruolo di finestra di log dei messaggi all’utente. In questo senso sipresenta come estensione di una shell come la finestra DOS in Windows o della consolein Unix/Linux. Per accedere ad uno dei comandi della shell del sistema operativo o an-che lanciare un eseguibile esterno basta digitare il comando stesso preceduto dal carattere‘!’, detto shell escape command. Ad esempio per conoscere velocemente il contenutodella directory di lavoro corrente basta dare il comando !dir in Windows o !ls -l inUnix/Linux (o anche in Windows se è installato Cygwin).

Un numero di comandi di Matlab può essere collezionato in un file, di estensione“.m”, ed interpretato dal kernel, che è il nucleo e motore numerico del programma. Ingergo informatico tali files, detti M-files, sono degli script di comandi perché eseguiti inmaniera sequenziale.

Un comando corrispondente al nome (estensione esclusa) di un M-file è noto all’am-biente di lavoro se il file si trova nel percorso di ricerca predefinito. La ricerca da partedell’interprete dei comandi avviene in alcune sottocartelle della cartella in cui è instal-lato il programma e nella cartella di lavoro (current directory), che l’utente può definirearbitrariamente a seconda delle sue esigenze.

Oltre alla finestra principale con il prompt dei comandi, fanno parte dell’ambientedi lavoro: (i) l’editor degli script di comandi (M-file editor), si veda la figura 4.2, che siavvia dal menu File!New!M-file, e (ii) le finestre dei grafici che l’utente produce nellasua sessione di lavoro, ad esempio con il comando plot.

Se si digita plot(0:0.1:1) appare la finestra riportata nella figura 4.3. Essa contieneun grafico in cui le ordinate corrispondono ai numeri ottenuti a partire da 0 con incrementidi 0:1 fino ad arrivare a 1 e le ascisse corrispondono agli indici interi che vanno da 1 finoad 11. La sequenza di coppie di coordinate viene rappresentata per default unendo i punticon una linea continua. Come vedremo tra breve, l’operatore “:” consente di ottenererapidamente un vettore di numeri.

A. De Marco

Page 83: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

4.3 Sessioni di lavoro 83

Figura 4.3 Una finestra grafica di Matlab ottenuta con il semplice comando plot(0:0.1:1).

Figura 4.4 L’interfaccia grafica di Simulink per la modellazione di sistemi dinamici.

Appunti di programmazione a oggetti in C++ e Matlab

Page 84: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

84 Capitolo 4 Una panoramica su Matlab

4.4 Usare l’help

Se si vogliono avere informazioni su Matlab si può ovviamente ricorrere ai manuali op-pure utilizzare Matlab stesso attraverso il suo sistema di help. Ad esempio, se si vuolesapere a cosa serve il comando plot si può scrivere help plot nella stessa finestra deicomandi. Comparirà una descrizione accurata di tale comando, sullo stile del comandoman della shell di Linux.

In generale, il comando help <nome-comando> restituisce (se il nome del comandoesiste) l’help del comando in questione. Un’altro comando che talvolta si dimostra utileè lookfor <parola-chiave> che controlla se è disponibile l’help per la parola chiaveindicata tra tutti i comandi disponibili in Matlab.

In alternativa alla richiesta di help da riga di comando, utile per una consultazioneveloce ma a volte poco ricca di esempi, è possibile cercare aiuto nella preziosa finestra dihelp dell’applicazione, figura 4.5.

Figura 4.5 La finestra di help di Matlab.

4.5 Nozioni e notazioni fondamentali

4.5.1 Le variabili

Come in tutti gli ambienti di programmazione interattivi in Matlab è possibile definiredelle variabili, alle quali assegnare determinati valori, ed utilizzarle in calcoli successivi.I nomi delle variabili Matlab possono essere qualsiasi, ma non devono cominciare con uncarattere che sia un numero o uno dei caratteri speciali (come quelli di punteggiatura).Se una variabile ha lo stesso nome di un comando Matlab, quest’ultimo non sarà più

A. De Marco

Page 85: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

4.5 Nozioni e notazioni fondamentali 85

disponibile a meno che la variabile non venga cancellata con il comando clear <nome-

variabile>. Per assegnare una variabile si usa l’operatore di assegnamento “=”. Il tipodella variabile viene automaticamente costruito in base alla quantità che si assegna.

Negli esempi seguenti si riportano delle sequenze di comandi digitati al prompt diMatlab, ma che potrebbero anche essere contenuti in un M-file. Le righe in cui il prompt“>>” non compare costituiscono ciò che invece la command window restituisce all’utente,detto in gergo message log. Ad esempio l’assegnazione di una data variabile non terminatadal carattere “;” viene sempre seguita dal messaggio che mostra all’utente il valore dellavariabile e le dimensioni della matrice. Ciò si verifica anche solo digitando il nome diuna variabile ed è utile per conoscerne velocemente il valore o sapere se ne esiste una ose esiste una funzione con quel nome.

Maggiori dettagli sulla gestione delle variabili si evincono dagli esempi riportati inquanto segue. Si osservi che il carattere “%” è quello che inizia un commento al codiceMatlab.

Per cominciare si prenda in esame la sequenza di comandi:>> a=1 % assegna alla variabile a il valore 1a =

1

>> b=’pippo’ % assegna alla variabile b la stringa pippob =

pippo

>> c=23; % con il carattere ; a fine comando non viene mostrato% il valore di c

>> 12.5 % 12.5, viene assegnato alla variabile di default ans(wer)ans =

12.5000

>> whos % interroga il sistema sulle variabili dichiarateName Size Bytes Class

a 1x1 8 double arrayans 1x1 8 double arrayb 1x5 10 char arrayc 1x1 8 double array

Grand total is 8 elements using 34 bytes

Il significato dei comandi e delle operazioni riportate è spiegato dai commenti di cuisono corredati. Gli esempi di comandi che seguono illustrano ulteriori aspetti dell’am-biente di programmazione interattivo.>> a=’pluto’; % se si riassegna una variabile questa viene riallocata>> whos

Name Size Bytes Class

a 1x5 10 char arrayans 1x1 8 double arrayb 1x5 10 char arrayc 1x1 8 double array

>> clear a % si cancella a

>> who % le variabili dichiarate (senza tipo) ora sonoYour variables are:

ans b cGrand total is 12 elements using 36 bytes

>> clear all % si cancellano tutte le variabili>> who % nessuna risposta, nessuna variabile definita

Appunti di programmazione a oggetti in C++ e Matlab

Page 86: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

86 Capitolo 4 Una panoramica su Matlab

4.5.2 Matrici e vettori

Una matrice viene delimitata da parantesi quadre. Ogni riga termina con un punto evirgola e deve avere lo stesso numero di elementi (separati da spazi bianchi o da unavirgola). Ad esempio, i comandi seguenti:

>> A=[-1 2 3; 4 5 6]A =

-1 2 34 5 6

>> A=[-1, 2, 3;4, 5, 6] % il comando termina alla seconda riga con la ]

A =-1 2 34 5 6

>> A=[-1 2 3; 4 ... % i 3 punti indicano continuazione su riga successiva5 6];

rappresentano modi equivalenti di introdurre la stessa matrice 2 � 3. Un vettore riga didimensione n è una matrice 1 � n, un vettore colonna di dimensione m è una matricem � 1.

Matrici con dimensioni compatibili possono essere sommate o moltiplicate con glioperatori “+”, “-” e “*”. Si osservi che il carattere “’” (apice) che segue il nome di unavariabile equivale all’operatore di trasposizione applicato alla matrice che tale variabilerappresenta. A tal riguardo si prendano in esame i comandi che seguono:

>> A=[1 2 3; 4 5 6]; B=[7 8 9; 10 11 12];>> A+B % somma di due matrici 2x3ans =

8 10 1214 16 18

>> A=[1 2 3; 4 5 6]; B=[7 8 9; 10 11 12]’;>> A*B % prodotto di una matrice 2x3 con una 3x2ans =

50 68122 167

Se le matrici che compaiono in un’operazione di prodotto non hanno dimensionicompatibili, viene segnalato un messaggio di errore. Ad esempio:

>> A=[1 2 3; 4 5 6]; B=[7 8 9; 10 11 12];>> A*B % prodotto di una matrice 2x3 con una 2x3??? Error using ==> *Inner matrix dimensions must agree.

Se invece si prova ad usare l’operatore “.*” al posto del solo “*” si ottiene:

>> A.*Bans =

7 16 2740 55 72

In questa circostanza Matlab non segnala alcun errore perché ora il prodotto è stato statoeseguito “elemento per elemento” (element-wise). Facendo precedere il carattere “.” alleoperazioni elementari queste vengono eseguite elemento per elemento. Questa è unaproprietà importante ed utile, ad esempio, nella produzione di grafici di funzioni.

Quando si opera con matrici quadrate possono effettuarsi su di esse diverse operazioniparticolari che restituiscono le seguenti quantità:

A. De Marco

Page 87: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

4.5 Nozioni e notazioni fondamentali 87

>> A=[1 2; 3 4];>> inv(A) % l’inversa di Aans =

-2.0000 1.00001.5000 -0.5000

>> det(A) % il determinanteans =

-2>> eig(A) % gli autovalorians =

-0.37235.3723

>> cond(A) % il numero di condizionamento in norma 2ans =

14.9330>> norm(A) % la norma 2ans =

5.4650>> norm(A,inf) % la norma infinitoans =

7

A questo punto si sperimenti una prima operazione su un’intera matrice. Il comandoA+1 applicato alla matrice precedentemente definita fornisce:

>> A+1ans =

2 34 5

cioè tutti gli elementi di A sono stati aumentati di 1. Quindi in questo senso si puòsommare un numero ed una matrice.

Per accedere all’elemento (i,j) di una matrice A, basta scrivere A(i,j), mentre peraccedere all’elemento i-mo di un vettore v (riga o colonna che sia) basta scrivere v(i).Per accedere ad un’intera colonna o ad un’intera riga gli indici corrispondenti possonoessere rimpiazzati dai due punti “:” come negli esempi seguenti:

>> A(2,1)ans =

4

>> A(:,2) % estrae la seconda colonnaans =

35

>> A(1,:) % estrae la prima rigaans =

2 3

4.5.3 Altri tipi di dati

Una variabile può contenere anche valori non numerici. Un esempio comune è dato daicaratteri e dalle stringhe di caratteri. Le costanti stringhe di caratteri come, ad esempio’pippo’, vengono delimitate con degli apici, e con l’assegnazione seguente:

>> str = ’pippo’str =pippo

si definirà una variabile str da intendersi come un vettore i cui elementi sono i singolicaratteri della stringa. Ad esempio il comando str(3) restituirà il carattere ‘p’.

Appunti di programmazione a oggetti in C++ e Matlab

Page 88: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

88 Capitolo 4 Una panoramica su Matlab

Le recenti versioni di Matlab si sono arricchite di nuovi tipi di dati. Un esempioè costituito dai cell arrays, cioè delle variabili costruite con una notazione basata sulleparentesi graffe. Un primo esempio è dato dall’assegnazione: M = {a b c}. Un’assegna-zione equivalente si ha mediante l’uso del costruttore cell. L’esempio precedente puòriscriversi come:

>> M = cell(1,3); % crea un cell array di valori nulliM{1} = a; M{2} = b; M{3} = c; % riempie le celle

Le matrici a, b, e c possono essere oggetti qualunque. Ad esempio l’istruzione M = {A,

det(A), [det(A);det(B)]} è perfettamente valida.È possibile inoltre definire delle strutture simili alle struct del linguaggio C, ai cui

campi si accede con l’operatore “.” (punto). Un esempio di definizione di una variabilestruttura S è il seguente:

>> S.name = ’Ed Plum’;>> S.score = 83;>> SS =

name: ’Ed Plum’score: 83

e naturalmente è possibile maneggiare interi array di strutture sfruttando i vantaggi offertidal linguaggio.

4.5.4 Le funzioni in Matlab

Matlab, è sia un linguaggio di programmazione che un ambiente computazionale interat-tivo. Come già detto, i files che contengono comandi, cioè righe di codice Matlab, sonochiamati M-files. Dopo aver creato un M-file usando un qualsiasi editor di testo, salvando-lo in un appropriato percorso l’utente può disporre di un nuovo comando personalizzatoo di una nuova funzionalità, che arricchisce quelle predefinite dell’ambiente Matlab. Inparticolare esistono due tipi di M-file:� scripts, cioè comandi che non hanno argomenti di input o argomenti di output ed

operano su dati già presenti nel workspace e/o dati creati contestualmente,� functions, che possono accettare anche un numero variabile di argomenti di input

(come le funzioni C++) ed hanno uno o più argomenti di output.I programmatori in linguaggio Matlab creano in genere i propri M-files nella cartella

di lavoro o in una delle sue sottocartelle. Eventualmente gli M-file potranno essere orga-nizzati in toolboxes e salvati in cartelle che l’utente può aggiungere al percorso di ricercadi Matlab. Se si duplicano nomi di funzioni, cioè si hanno nomi di files identici in piùpunti del percorso di ricerca, Matlab esegue quello che trova per primo. Per editare i con-tenuti di un M-file nella cartella di lavoro è possibile selezionare ed esplorare la finestra“Current directory”, cioè una delle tabbed window mostrata nella figura 4.6, ed aprirecon un doppio click l’M-file desiderato. Si avvierà anche in questo caso l’M-file editor diMatlab.

Quando si richiama uno script dalla riga di comando, Matlab esegue semplicementei comandi presenti nel file. Gli script possono operare su dati esistenti nel workspace,o possono essi stessi contenere comandi che allocano ed assegnano dati su cui operare.Sebbene gli script non forniscono dati di output, qualsiasi variabile da essi creata rimane

A. De Marco

Page 89: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

4.5 Nozioni e notazioni fondamentali 89

Figura 4.6 La finestra “Current directory”per l’esplorazione della cartella di lavoro.

nel workspace, per essere usata in calcoli successivi. Inoltre, gli script possono produrredei grafici, usando funzioni come plot.

Per esempio, se si crea un file chiamato myrmatrix.m contenente i seguenti comandi:

% Calcoli varii su matricir = zeros(1,32);for n = 3:32 % determinanti di

r(n) = det(rand(7)); % matrici 7x7 aend % elementi randomrbar(r)

con il comando >> myrmatrix si chiede a Matlab di eseguire le istruzioni contenute nel fileuna dopo l’altra: verrà calcolato il determinante di 30 matrici 7� 7 con elementi random,comando det(random(7)), e tracciato il grafico del risultato, bar(r). Dopo l’esecuzionedel comando, la variabile r rimane nel workspace.

I comandi eig, det, inv e così via, sono esempi di funzioni Matlab. Esse possonoessere richiamate in molti modi diversi. La sintassi più generale è la seguente:

>>[<out1>, ... , <outn>] = <nome-funzione>(<in1>, ... , <inm>);

dove <out1>, ... , <outn> sono i parametri di output, mentre <in1>, ... , <inm> so-no i parametri di input. Il loro numero può variare e per lanciare correttamente una fun-zione è necessario consultare attentamente l’help. Se la funzione ha un solo parametro dioutput, le parentesi quadre possono essere omesse.

Le funzioni possono accettare argomenti in input e forniscono argomenti in uscita.Il nome dell’M-file e della funzione deve essere lo stesso e deve trovarsi nel percorso diricerca corrente. Le variabili definite all’interno di una funzione, dette variabili locali,hanno visibilità (scope) locale alla funzione quando non sono dichiarate con attributoglobal. È come se le variabili locali di una funzione fossero residenti in un workspaceproprio, separato dal workspace a cui si accede dal prompt dei comandi di Matlab, cheviene cancellato dopo la chiamata.

Un semplice esempio è fornito dalla funzione rank. L’M-file rank.m è disponibilenella cartella <matlab root>/toolbox/matlab/matfun. La funzione può essere chiamata

Appunti di programmazione a oggetti in C++ e Matlab

Page 90: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

90 Capitolo 4 Una panoramica su Matlab

dopo aver definito una matrice A, digitando al prompt dei comandi >> rank(A). L’M-filein questione è qui di seguito riportato:

% File: rank.mfunction r = rank(A,tol)% RANK Matrix rank.% RANK(A) provides an estimate of the number of linearly% independent rows or columns of a matrix A.% RANK(A,tol) is the number of singular values of A% that are larger than tol.% RANK(A) uses the default tol = max(size(A)) * norm(A) * eps.s = svd(A);if nargin==1tol = max(size(A)) * max(s) * eps;endr = sum(s > tol);

La prima linea non commentata di un M-file contenente una funzione comincia con laparola chiave function seguita dalla lista degli argomenti di output, in questo caso la solar, dal nome alla funzione, rank, e dalla lista di argomenti di input racchiusi tra parentesitonde, (A,tol). Le righe seguenti la definizione iniziano col carattere di commento “%”e rappresentano dei commenti di aiuto che verranno visualizzati al prompt dei comandiquando si digita >>help rank. La prima linea del testo di aiuto è la cosiddetta “H1 line”che Matlab espone quando si ricerca aiuto da riga di comando. Il resto del file rappresentail codice interpretato da Matlab per rendere disponibile la funzione agli utenti.

Nell’esempio appena riportato la variabile s presente nel corpo della funzione, cosìcome le variabili che compaiono nella definizione, r, A e tol, sono locali alla funzio-ne e rimangono indipendenti e separate da qualsiasi variabile nel workspace di Matlab.Anche se in quest’ultimo fosse definita una variabile con lo stesso nome non vi sarebbepossibilità di conflitto.

L’esempio illustra un aspetto delle funzioni di Matlab che si trova anche in altri lin-guaggi di programmazione come il C++ o il Fortran 90/95 cioè la possibilità di definirefunzioni che possano essere chiamate con un numero variabile di argomenti. Il numerodi argomenti effettivamente passato alla funzione nel momento della chiamata viene me-morizzato di volta in volta nella variabile riservata nargin. Una funzione come rank puòdunque essere usata in modi diversi come si vede dall’esempio seguente:

>> A = rand(10); % genera una matrice 10x10 ad elementi random>> rank(A);>> r = rank(A);>> r = rank(A,1.e-6);

Rispetto alla gestione del numero di parametri di input e di output, molte funzioni chefanno parte del linguaggio Matlab sono definite in maniera simile. Se nessun argomentodi output compare nella chiamata, il risultato è assegnato alla variabile di default ans.Tipicamente il primo argomento di input è sempre richiesto e non può essere omessonella chiamata. Se il secondo argomento di input non è presente, la funzione lo poneuguale ad un valore di default. Tipicamente nel corpo di una funzione sono interrogatele due variabili riservate nargin e nargout, che contengono il numero di argomenti diinput e di output effettivamente utilizzati nelle chiamate. L’effettivo comportamento dellafunzione ed eventualmente l’incorrere in una condizione di errore di chiamata dipenderàdi volta in volta dal valore di queste due variabili.

A. De Marco

Page 91: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

4.6 Operazioni di Input / Output 91

4.6 Operazioni di Input /Output

L’ambiente di lavoro offre la possibilità di analizzare dati raccolti eventualmente con altriprogrammi ed immagazzinati in files di testo (formato ASCII). Ad esempio, si potrebbeavere a disposizione l’insieme di dati seguente:

1 2.000 -5.02 0.2500 -9.13 0.0740 -23.04 0.0310 -53.25 0.0160 -105.16 0.0090 -185.57 0.0050 -299.48 0.0030 -453.79 0.0020 -653.010 0.0020 -905.3

Questi dati possono essere salvati su un file, per esempio ’aerodata.dat’, e caricatiin Matlab con il comando load. In questo esempio, in Matlab viene creata una matriceaerodata di dimensioni 10 � 3:

>> load aerodata.dat>> whos

Name Size Bytes Classaerodata 10x3 30 double array

Grand total is 30 elements using 240 bytes

Il salvataggio di dati è possibile specificando un formato con il comando save. Unfile di dati come ’aerodata.dat’ potrebbe essere stato prodotto a valle di una sessione dilavoro con la sequenza di comandi:

>> id = 1:10;>> x = [2.000 0.2500 0.0740 0.0310 0.0160 ...

0.0090 0.0050 0.0030 0.0020 0.0020];>> y = [-5.0 -9.1 -23.0 -53.2 -105.1 ...

-185.5 -299.4 -453.7 -653.0 -905.3];>> dati = [id’ x’ y’];>> save aerodata.dat dati -ascii % salva in forma ascii 8 bit

I possibili usi del comando di salvataggio sono i seguenti:

>> save aerodata.dat dati % salva in forma binaria>> save aerodata.dat x y % salva le matrici riga x e y>> save aerodata.dat dati -ascii % salva in forma ascii 8 bit>> save aerodata.dat dati -double % salva in forma ascii 16 bit>> save aerodata.dat dati -ascii -tabs % salva in forma ascii

% con tabulatori

Se il nome del file è stdio l’output è inviato allo standard output device, generalmentelo schermo.

Esistono comandi di input/output alternativi e di più basso livello rispetto a quelli ap-pena richiamati. Ad esempio i comandi dlmread e dlmwrite lavorano su files ASCII indui i dati vengono separati da cartteri particolari detti delimiters. Non è raro dover ma-nipolare ad esempio files contenenti comma separated values, valori separati da virgole,

Appunti di programmazione a oggetti in C++ e Matlab

Page 92: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

92 Capitolo 4 Una panoramica su Matlab

tipicamente di estensione “.csv”. Un simile file potrà essere letto ed immagazzinato inuna matrice con il comando:

>> A = dlmread(’dati.dat’,’,’) % legge il file delimitato da ’,’

Utilizzatori esperti possono a volte preferire metodi di lettura e scrittura che utilizzanotutta una serie di comandi derivati e simili a quelli del linguaggio C. Questi comandi sonoriportati nella Tabella 4.1 e si rimanda all’help per approfondimenti ed esempi praticisull’argomento.

Tabella 4.1 Comandi di Input/Output di basso livello. Si consulti l’help di Matlab permaggiori dettagli sulla sintassi e per degli esempi d’uso.

fopen, fclose apertura e chiusura di un file

fread, fwrite I/O per dati non formattati

fscanf, fprintf I/O per dati formattati(formattazione con i comandi simili al C)

fgetl, fgets I/O dati formattati

ferror, fseek, ftell, frewind Come i corrispondenti comandi in C

sprintf, sscanf Conversione di stringhe

Qui si riporta un semplice esempio in cui si scrivono in un file di testo una riga diintestazione e due colonne di valori, una contenente quelli della variabile indipendente ted una contenente quelli della funzione y.t/ D 2 sin.t/ cos.t/:

t = linspace(0,2*pi,40); % 40 punti in Œ0; 2��y = 2*sin(t).*cos(t); % genera y.t/ D 2 sin.t/ cos.t/data = [t ; y]; % matrice 2x40fid = fopen(’valori-funzione.txt’,’w’); % "apre" il canale del file

% in scritturafprintf(fid,’Valori della funzione sin(t)*cos(t) tra 0 e 2*pi\n\n’);fprintf(fid,’%4.2f %10.6f\n’,data); % tipica formattazione C% N.B.: questa formattazione permette di ottenere% un file con i dati su due colonnefclose(fid) % "chiude" il canale del file

Noto il metodo ed il formato con cui i dati sono stati scritti nel file valori-funzione.txt,sarà possibile rileggerne il contenuto con comandi analoghi di e con l’uso di fscanf.

Per finire si ricorda che le Matlab dispone di uno strumento di alto livello per l’impor-tazione dei dati chiamato Import Wizard al quale si accede dal menu File|Import Data.Si tratta di una interfaccia grafica che permette di selezionare il file che contiene i dati, dianalizzarne il contenuto, selezionare il carattere di delimitazione dei dati, escludere even-tualmente un certo numero de righe iniziali ed infine di stabilire in quante e quali variabilicaricare i dati nel workspace.

A. De Marco

Page 93: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Capitolo 5

Programmazione a oggetti in Matlab

I have always wished that my computer would be as easy to use as my telephone.My wish has come true. I no longer know how to use my telephone!

– Bjarne Stroustrup

Indice5.1 Strutture dati di Matlab . . . . . . . . . . . . . . . . . . . . . . . . . 935.2 Classi e oggetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 945.3 Esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

[capitolo incompleto]Questa seconda parte di documento, seppur già concepita, è ancora in via di scrittura.

Lo scopo fondamentale è quello di presentare le caratteristiche del linguaggio introdot-te a partire dalla versione “2008a” che permettono ai programmatori di definire nuoveclassi e di derivare tipi da alcune classi predefinite. Il vantaggio di poter programmare aoggetti in Matlab è ovvio: si possono progettare programmi, dai più semplici ai più com-plessi, seguendo il paradigma di programmazione a oggetti servendosi, allo stesso tempo,dell’enorme patrimonio di funzioni e toolbox disponibili.

5.1 Strutture dati di Matlab

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut,placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero,nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque.Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis ege-stas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urnafringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer sapien est,iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum.Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabi-tur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsaneleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim rutrum.

Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor loremnon justo. Nam lacus libero, pretium at, lobortis vitae, ultricies et, tellus. Donec aliquet,tortor sed accumsan bibendum, erat ligula aliquet magna, vitae ornare odio metus a mi.

Page 94: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

94 Capitolo 5 Programmazione a oggetti in Matlab

Morbi ac orci et nisl hendrerit mollis. Suspendisse ut massa. Cras nec ante. Pellentesquea nulla. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculusmus. Aliquam tincidunt urna. Nulla ullamcorper vestibulum turpis. Pellentesque cursusluctus mauris.

5.2 Classi e oggetti (in Matlab � 2008a )

Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at, tincidunt tri-stique, libero. Vivamus viverra fermentum felis. Donec nonummy pellentesque ante.Phasellus adipiscing semper elit. Proin fermentum massa ac quam. Sed diam turpis, mo-lestie vitae, placerat a, molestie nec, leo. Maecenas lacinia. Nam ipsum ligula, eleifendat, accumsan nec, suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc eleifendconsequat lorem. Sed lacinia nulla vitae enim. Pellentesque tincidunt purus vel magna.Integer non enim. Praesent euismod nunc eu purus. Donec bibendum quam in tellus.Nullam cursus pulvinar lectus. Donec et mi. Nam vulputate metus eu enim. Vestibulumpellentesque felis eu massa.

Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vitae lacus tinciduntultrices. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In hac habitasse plateadictumst. Integer tempus convallis augue. Etiam facilisis. Nunc elementum fermentumwisi. Aenean placerat. Ut imperdiet, enim sed gravida sollicitudin, felis odio placeratquam, ac pulvinar elit purus eget enim. Nunc vitae tortor. Proin tempus nibh sit amet nisl.Vivamus quis tortor vitae risus porta vehicula.

5.3 Esempi

Fusce mauris. Vestibulum luctus nibh at lectus. Sed bibendum, nulla a faucibus semper,leo velit ultricies tellus, ac venenatis arcu wisi vel nisl. Vestibulum diam. Aliquam pellen-tesque, augue quis sagittis posuere, turpis lacus congue quam, in hendrerit risus eros egetfelis. Maecenas eget erat in sapien mattis porttitor. Vestibulum porttitor. Nulla facilisi.Sed a turpis eu lacus commodo facilisis. Morbi fringilla, wisi in dignissim interdum, justolectus sagittis dui, et vehicula libero dui cursus dui. Mauris tempor ligula sed lacus. Duiscursus enim ut augue. Cras ac magna. Cras nulla. Nulla egestas. Curabitur a leo. Quisqueegestas wisi eget nunc. Nam feugiat lacus vel est. Curabitur consectetuer.

Suspendisse vel felis. Ut lorem lorem, interdum eu, tincidunt sit amet, laoreet vitae,arcu. Aenean faucibus pede eu ante. Praesent enim elit, rutrum at, molestie non, nonum-my vel, nisl. Ut lectus eros, malesuada sit amet, fermentum eu, sodales cursus, magna.Donec eu purus. Quisque vehicula, urna sed ultricies auctor, pede lorem egestas dui, etconvallis elit erat sed nulla. Donec luctus. Curabitur et nunc. Aliquam dolor odio, com-modo pretium, ultricies non, pharetra in, velit. Integer arcu est, nonummy in, fermentumfaucibus, egestas vel, odio.

A. De Marco

Page 95: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

Bibliografia e sitografia

[1] B. Stroustrup, C++. Linguaggio, libreria standard, principi di programmazione.Addison-Wesley, Pearson Education Italia (collana Professionale), Terza edizione,2000.

[2] B. Stroustrup, The C++ Programming Language . Addison-Wesley, Special 3rd

Edition, 2000.

[3] A. Koenig, B. E. Moo, Accelerated C++. Addison-Wesley, 2000.

[4] H. Schildt, C++. La guida completa. McGraw-Hill, 2003.

[5] H. Schildt, Herb Schildt’s C++ Programming Cookbook. McGraw-Hill, 2008.

[6] B. Stroustrup, Sito internet di Bjarne Stroustrup,http://www.research.att.com/~bs/

[7] N. M. Josuttis, Object-Oriented Programming in C++. John Wiley, 2003.Sito internet: http://www.josuttis.com/cppbook/cppbook.html

[8] D. Vandevoorde, N. M. Josuttis, C++ Templates. Addison-Wesley, 2003.

[9] N. M. Josuttis, The C++ Standard Library – A Tutorial and Reference, Self publi-shed, 1999.Sito internet: http://www.josuttis.com/libbook/

[10] Autori anonimi, Dal C al C++, Wikibook.Sito internet: http://it.wikibooks.org/wiki/C%2B%2B

[11] A. Ficarra, M. Murgia, Il linguaggio C++ standard, Corso di formazione ISAC,CNR, Bologna 2003.Sito internet:http://www.bo.cnr.it/corsi-di-informatica/corsoCstandard/Lezioni/01Indice.html

[12] C. Olson, sito internet di FlightGear Flight Simulator,http://www.flightgear.org

[13] C. Olson, sito internet di ispezione interattiva del codice sorgente di FlightGearFlight Simulator (Interactive CVS log browser),http://cvs.flightgear.org/viewvc/source/

[14] J. S. Berndt, sito internet di JSBSim, Flight Dynamics Model,http://www.jsbsim.org

Page 96: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

96 Capitolo 5 Bibliografia e sitografia

[15] J. S. Berndt, sito internet di ispezione interattiva del codice sorgente di JSBSimFlight Dynamics Model (Interactive CVS log browser),http://jsbsim.cvs.sourceforge.net/viewvc/jsbsim/JSBSim/

[16] J. S. Berndt, “JSBSim: An Open Source Flight Dynamics Model in C++.” AIAAModeling and Simulation Technology Conference, Providence, Rhode Island, 16-19August 16, 2004.

[17] A. De Marco, E. L. Duke, J. S. Berndt, “A General Solution to the Aircraft TrimProblem.” AIAA Paper 2007-6703, AIAA Modeling and Simulation TechnologyConference, Hilton Head, South Carolina, USA, 20-23 August 2007.

[18] D. P. Coiro, A. De Marco, F. Nicolosi, “A 6DOF Flight Simulation Environment forGeneral Aviation Aircraft with Control Loading Reproduction.” AIAA Paper 2007-6364, AIAA Modeling and Simulation Technology Conference, Hilton Head, SouthCarolina, USA, 20-23 August 2007.

[19] D. P. Coiro, A. De Marco, F. Nicolosi, “The Flight Simulation Environment ofThe University of Naples.” Proceedings of ISC 2006 (International SimulationConference), July 2006, Palermo, Italy.

[20] M. Cooper, Advanced Bash-Scripting Guide. An in-depth exploration of the art ofshell scripting. Disponibile all’indirizzo: http://tldp.org/LDP/abs/html/

[21] Sito internet della distibuzione di software libero GNU: http://www.gnu.org

[22] Sito internet del progetto GNU/Linux:http://www.gnu.org/gnu/linux-and-gnu.it.html

[23] Sito internet del manuale online di GNU make:http://www.gnu.org/software/make/manual/

[24] Sito internet della distibuzione di software libero Cygwin: http://www.cygwin.com

[25] Sito internet del sistema MinGW (Minimalist GNU for Windows):http://www.mingw.org

[26] Sito internet di Borland, produttore del sistema di sviluppo Borland C++Builder:http://www.borland.com

[27] Sito internet dell’ambiente di sviluppo integrato Microsoft Visual C++ Express:http://www.microsoft.com/express/vc/

[28] Sito internet dell’ambiente di sviluppo integrato Code::Blocks (The open source,cross platform, free C++ IDE): http://www.codeblocks.org

[29] Sito internet della Bloodshed Software e dell’ambiente di sviluppo integratoDev-C++: http://www.bloodshed.net/devcpp.html

[30] Sito internet dell’ambiente di sviluppo integrato wxDev-C++ (estensione diDev-C++ preconfigurata per lo sviluppo di applicazioni ad interfaccia graficabasata sulla libreria wxWidgets): http://wxdsgn.sourceforge.net

A. De Marco

Page 97: Appunti OOP Cpp Matlab v2009d

DR

AFT

ver.2009.d

Cop

yrig

ht©

A.D

eM

arco

97

[31] Sito internet del toolkit grafico wxWidgets (The cross-platform GUI library):http://wxwidgets.org

[32] Sito internet di Silicon Graphics Inc., produttore del sistema operativo Irix:http://www.sgi.com

[33] Sito internet del sistema di compilazione multipiattaforma CMake:http://www.cmake.org

[34] Sito internet dell’editore di testi gratuito Notepad++:http://notepad-plus.sourceforge.net

[35] Sito internet dell’editore di testi gratuito Vim (Vi Improved): http://www.vim.org

[36] The Mathworks, Matlab online documentation: http://www.mathworks.com/access/helpdesk/help/techdoc/index.html?/access/

(versioni 2008b e 2009a).

[37] A. H. Register, A Guide to MATLAB Object-Oriented Programming. Chapman &Hall/CRC, SciTech Publishing Inc., 2007.

[38] B. W. McCormick, Aerodynamics, Aeronautics, and Flight Mechanics. John Wiley& Sons, New York, 1979.

[39] J. Katz, A. Plotkin, Low-Speed Aerodynamics. Cambridge University Press, 2ndedition, Cambridge, England, U.K., 2001.

Appunti di programmazione a oggetti in C++ e Matlab