Elementi di programmazione ad oggetti a. a. 2009/2010

Preview:

DESCRIPTION

Elementi di programmazione ad oggetti a. a. 2009/2010. Corso di Laurea Magistrale in Ingegneria Elettronica Docente: Mauro Mazzieri, Dipartimento di Ingegneria Informatica, Gestionale e dell’Automazione. Programma del corso. - PowerPoint PPT Presentation

Citation preview

Elementi di programmazione

ad oggetti

a. a. 2009/2010

Corso di Laurea Magistrale in Ingegneria ElettronicaDocente: Mauro Mazzieri, Dipartimento di Ingegneria Informatica, Gestionale e dell’Automazione

Programma del corso1. Introduzione al linguaggio C++ e alla libreria

standard; richiami di programmazione procedurale.2. Regole di visibilità e ciclo di vita.3. Funzioni e sovraccaricamento.4. Introduzione alla progettazione e programmazione

ad oggetti: classi ed oggetti, notazione UML.5. Sovraccaricamento degli operatori.6. Ereditarietà. Funzioni virtuali e polimorfismo.7. Template.8. Gestione delle eccezioni.9. Input/output e stream.10. La libreria standard: i contenitori; cenni su oggetti

funzione, algoritmi, iteratori, allocatori, stringhe, calcolo numerico.

11. Unit testing e test-driven programming.

Testi di riferimento Lippman, Lajoie, "C++ Corso di

Programmazione", Addison-Welsey consigliato

Stroustrup, "C++ Linguaggio, libreria standard, principi di programmazione", Addison-Wesley La bibbia del C++, consigliato a chi sa già

programmare (in altri linguaggi) e desidera la fonte più autorevole sul C++

… o qualsiasi altro libro di C++ Aguilar, “Fondamenti di programmazione in C+

+”, McGraw-Hill Schildt, "Guida Completa al C++", Mc Graw-Hill Deitel, Deitel, "C++ Fondamenti di

Programmazione", Apogeo

Alcune note Le slides del corso saranno messe

al più presto a disposizione sul portale del DIIGA Le slides non sono dispense, occorre

seguire le lezioni e/o leggere uno dei libri di riferimento, ed esercitarsi all’elaboratore

Quale ambiente di sviluppo per C++? Windows: DevC++, Visual C++

Express Mac: XCode Linux: KDevelop

Lezione 1Introduzione al linguaggio C++ ed alla libreria standardRichiami di programmazione procedurale

Introduzione al C++

Bjarne Stroustrup ha inventato il C++ Eredita dal C le caratteristiche di

basso livello Altre fonti di ispirazione: Simula67,

Algol68, Ada, Clu Il primo “C con le classi” è del

1980, i primi usi fuori dagli ambienti di ricerca sono del 1983

Standard ISO nel 1998

Cos’è il C++?

Il C++ è un linguaggio di programmazione general-purpose orientato alla realizzazione di sistemi È un C migliorato Supporta l’astrazione dei dati Supporta la programmazione

orientata agli oggetti Supporta la programmazione

generica

Programmazione procedurale La programmazione procedurale si

basa sull’individuazione delle procedure che occorrono e utilizzo dei migliori algoritmi possibili Decomposizione successiva del

sistema da implementare in funzionalità più semplici

Ci si ferma quando le funzionalità sono sufficientemente semplici da essere implementabili come funzioni

Esempio di programmazione procedurale#include <iostream>

using namespace std;

void scambia(int& n1, int& n2) {int temp = n1;n1 = n2;n2 = temp;

}

int main(){

int a, b;cout << "a=";cin >> a;cout << "b=";cin >> b;scambia(a, b);cout << "a=" << a << ", b=" << b << endl;system("pause");return 0;

}

Alcune note sul programma#include <iostream> Direttiva per il preprocessore, indica che il

programma ha la necessità di usare le funzioni della libreria predefinita per la gestione dell’I/O

using namespace std; Gli identificatori possono avere un prefisso

(“spazio dei nomi”); tramite questa direttiva è possibile usare le funzioni di libreria omettendo il prefisso std

cout << "a="; Output di una stringa sullo standard outputcin >> a; Input di una stringa dallo standard input

Programmazione modulare Un insieme di procedure

correlate e di dati da esse manipolati costituisce un modulo

La programmazione modulare si basa sulla suddivisione del programma in moduli, in modo che i dati siano nascosti all’interno dei moduli

namespace Dati, funzioni ed altre entità correlate possono essere

correlati in spazi di nomi (namespace) separati

// interfaccianamespace stack { void push(int); int pop();}

// implementazionenamespace stack { const int MaxSize = 100; int data[MaxSize]; int top = 0; void push(int i) { // controlla che la pila non sia piena ed inserisce i in cima }

int pop() { // controlla che la pila non sia vuota e restituisce l’elemento

in cima }}

Compilazione separata stack.hnamespace stack { void push(int); int pop();} stack.cpp#include “stack.h”

namespace stack { const int MaxSize = 100; int data[MaxSize]; int top = 0;}

void stack::push(int i) { // controlla che la pila non sia piena ed inserisce i in cima }

int stack::pop() { // controlla che la pila non sia vuota e restituisce l’elemento

in cima }

Progettazione orientata agli oggetti Si individuano le classi di oggetti

che caratterizzano il dominio applicativo Entità reali o astratte

Si individuano le modalità secondo cui gli oggetti devono interagire per realizzare le funzionalità dell’applicazione

Ogni classe è descritta da un’interfaccia che specifica il comportamento degli oggetti della classe

Classi e oggetti Un oggetto è una istanza di una classe di oggetti che condividono lo stesso comportamento Lo stato di un’istanza è indipendente

dallo stato delle altre istanze Un oggetto rappresenta un’entità del

mondo reale o astratta Un oggetto è caratterizzato da un nome,

da dati (variabili locale che ne descrivono lo stato) e metodi (funzioni che ne descrivono i comportamento)

Gli oggetti dialogano tra loro scambiandosi messaggi

Programmazione generica La programmazione generica

consente di parametrizzare gli algoritmi che occorrono in modo che funzionino per un’adeguata varietà di tipi e strutture dati Contenitori Algoritmi generici

Richiami di programmazione procedurale

Tipi di dato Tipi di dato primitivi:

int char float, double bool enum

Tipi composti a partire dai tipi primitivi: struct Puntatori Vettori

Variabili Per memorizzare ed utilizzare un dato

è necessario dichiararne il tipo ed il nome

Le locazioni di memoria dell’elaboratore contengono un dato La locazione di memoria è indentificata

da un indirizzo Il contenuto della locazione di memoria è

il valore

int a = 2; dichiara il tipo ed inizializza il valore

char b; Dichiara il tipo ma non inizializza il valore

Operatore di assegnamento L’operatore di assegnamento: =

All’elemento a sinistra dell’operatore (Lvalue) deve poter essere cambiato il valore

Solitamente, variabili Dell’elemento a destra (Rvalue) è

importante solo il contenuto Variabili, numeri, output di funzioni

Un Lvalue può fungere da Rvalue ma non viceversa

Operatore di uguaglianza: ==

Operatori Aritmetici

+ addizione - sottrazione * moltiplicazione / divisione % resto (modulo)

Logici && AND || OR ! NOT

Relazionali > maggiore < minore >= maggiore o

uguale <= minore o

uguale == uguale != diverso

Identificatori

Gli identificatori sono i nomi usati per rappresentare variabili, costanti, tipi, funzioni

Un identificatore viene dichiarato specificandolo della dichiarazione Sequenza di caratteri (lettere,

numeri, _), il primo deve essere una lettera o _

Parole chiave Non possono essere usate come

identificatori!asm, auto, bool, break, case, catch, char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, thwows, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volative, wchar_t, while

Strutture di controllo: if

if (espressione) {// codice che viene eseguito solo se l’espressione è true

} else {// codice che viene eseguito solo se l’epsressione è false

}

Strutture di controllo: while e dowhile (espressione) {

// istruzioni che vengono eseguite fintanto che l’espressione è true

}

do {// istruzioni che vengono eseguite almeno una volta e fintanto che l’espressione è true

} while (espressione)

Strutture di controllo: for

for (espr1; espr2; espr3) {// istruzioni eseguite fintanto che espr2 è true

}

Espr1 viene valutata una volta sola, prima di iniziare

Espr2 si valuta prima delle istruzioni

Espr3 si valuta dopo le istruzioni

Puntatore

Il puntatore è un tipo di dato derivato, che contiene l’indirizzo di una locazione di memoria capace di contenere valori di un certo tipo

int *a;*a = 3; * è l’operatore di deferenziazione int *a si legge “il contenuto della

locazione di memoria è un intero” (dunque, a è un puntatore)

Riferimenti Un riferimento fornisce un nome

alternativo ad un elementoint a=5;

int &b = a; Un riferimento deve essere

inizializzato contestualmente alla sua dichiarazione

L’operatore & fornisce l’indirizzo di una variabile:int *c;

c = &a;

Array

int a[5] = { 5, 10, 15, 20, 25 }

int *p; Il nome di un array è un

puntatore al primo elemento:p = a; oppurep = &a[0]

Puntatori const Il qualificatore const indica che un

elemento non può essere cambiatoconst int a = 5;

È obbligatorio inizializzare una costante nel momento in cui viene definita

Un puntatore const punta sempre alla stessa locazione di memoria

int a = 5;const int b =6;const int* c = &a;const int* d = &b;int* d = &b;

Allocazione della memoria L’operatore new alloca a run-time

della memoria La memoria allocata a run-time risiede in

un’area apposita chiamata heapint *a = new int;

a contiene un indirizzo corrispondante ad una locazione dell’heap

a viene solo allocata, non inizializzata int *a = new int(2); // a viene anche inizializzata

int *b = new int[2]; // allocazione di un vettore

b[0] = 3;b[1] = 4;

Rilascio della memoria L’operatore delete libera della memoria

dinamica allocata con newint *a = new int;…delete a;

la memoria all’indirizzo a può essere riallocata la memoria non viene cancellata a non cambia valore

Dopo il delete, a è un puntatore dangling (punta ad una locazione di memoria non valida)

Errori comuni Memory leak: non rilasciare con delete memoria

allocata con new Applicare due volte delete alla stessa locazione di

memoria Usare l’oggetto dopo il delete

Allocazione dinamica di arrayint *p1 = new int(24); // alloca un solo

intero, inizializzandolo a 24int * p2 = new int[24]; // alloca un vettore di

24 interi, non inizializzatiint (*p3)[1024] = new int[4][1024]; //alloca

una matrice di 4 x 1024 interi Non si possono inizializzare gli elementi di

un array alla loro allocazione, occorre un ciclo for

int a = 1024;int *p = new int[a];for (int i = 0; i < a; i++)

p[i] = 1; Un array si rilascia con delete[]delete[] p;

Allocazione dinamica const Una variabile const una volta

inizializzata non può essere modificata, anche se creata sull’heap

const int *a = new const int(23);

Una variabile allocata dinamicamente const Deve essere sempre inizializzata L’indirizzo di memoria restituito deve

essere assegnato a un puntatore const

Funzioni Operazione definita dall’utente

Gli operandi sono i parametri Il risultato è il valore di ritorno

Il tipo del valore di ritorno è il tipo di ritorno della funzione

void se non restituisce nulla

Le azione svolte sono contenute nel blocco della funzione

Tipo di ritorno, nome della funzione e lista dei parametri costituiscono la definizione della funzione

Parametri e variabili locali Le variabili definite nel corpo di

una funzione sono note solo all’interno della funzione

I parametri sono variabili locali istanziate alla chiamate della funzione

Prototipo

Il prototipo di una funzione è costituito dalla dichiarazione di tipo di ritorno, nome e parametri (senza il corpo)

int middle(int, int, int); E’ necessario definire il prototipo

solo quando la definizione avviene dopo la chiamata della funzione

Passaggio di parametri Il C++ è fortemente tipizzato: il tipo

degli argomenti è controllato dal compilatore

La maniera predefinita di passare gli argomenti è per valore vengono copiati nello spazio di memoria

dei parametri è un problema passare argomenti molto grandi

la funzione manipola solo delle copie locali

non possono essere modificati i valori degli argomenti

Introduzione alla libreria standard

Uso delle funzioni della libreria standard Per utilizzare una funzione della

libreria standard, bisogna includere l’intestazione in cui sono definite:#include <iostream>

using namespace std;

[…]

cout << “hello!”;

Flussi di input/output

#include <iostream>Using namespace std;[…]cout << “a=”;int a;cin >> a;cout << a;cout << endl;cout << “Ripeto: il valore di a è” << a << “!”;

Stringhe

string s1 = “benvenuto”;string s2 = s1 + “!\n”;bool affermativo(const string &risposta) {return risposta == “sì”;

}string s3 = s1.substr(5, 4); // nuto

string s4 = s1.replace(0, 5, “mal”); // malvenuto

La stringa sostituita può non avere la stessa lunghezza del sostituto!

Input di stringhe

string s;

cin >> s; // inserendo “Mauro”..

cout << “Ciao “ << s; // si ottiene “ciao Mauro”

Per leggere una riga intera:getline(cin, s);

Contenitori: vector Un array ha dimensione fissaint numeri1[100]; Un vettore ha dimensione variabilevector<int> numeri2(100);cout << numeri2.size(); \\ 100cout << numeri2[40]; \\ si accede ad un elemento come ad un array

numeri2.resize(200);cout << numeri2.size(); \\ 200vector numeri3[300]; \\ 300 vettori vuoti!!

Contenitori: list Una lista è adatta quando inserimenti e cancellazioni sono

frequentilist<double> valori; Di solito non si accede alla lista con un indice, ma si

scorrono i suoi elementifor (list<int>::const_iterator i = valori.begin(); i

!= valori.end(); i++)cout << *i;

for (list<int>::iterator i = valori.begin(); i != valori.end(); i++)*i = 1.0; Un iteratore non è un semplice puntatore, però

Con ++ si punta all’elemento successivo Con * si accede al contenuto

Aggiungere elementi ad una lista:valori.push_front(2.0); // inserimento in testavalori.push_back(3.0); // inserimento in codavalori.insert(i, 4.0); // inserimento prima

dell’elemento a cui i si riferisce

Altri contenitori map: array associativo (dizionario)

map<string, int> rubrica[…]cout << rubrica[“Mauro”];

queue: coda stack: pila deque: coda bidirezionale priority_queue: coda ordinata set: insieme multiset: insieme con valori ripetuti multimap: array associativo con valori

ripetuti

Algoritmi La libreria standard fornisce gli algoritmi più comuni

che operano su elementi dei contenitori standard Gli algoritmi operano su sequenze, determinate da

coppie di iteratorivector<int> v;list<int> l;[…]sort(v.begin(), v.end()); // ordinamentocopy(v.begin(), v.end(), l.begin()); // copiacopy(v.begin(), v.end(), back_inserter(l)); //

copia in coda, estendendo la lista quanto serve

int::const_iterator i = find(l.begin(), l.end(), 2); // restituisce un iteratore che punta all’elemento trovato

int c = count(v.begin(), v.end(), 3); // conta i 3 nel vettore

Algoritmi della libreria standardfor_each() Invoca una funzione per

ogni elemento

find_if() Trova il primo elemento che soddisfa la condizione

count_if() Conta gli elementi che soddisfano la condizione

replace_if() Sostituisce un elemento che soddisfa una condizione

unique_copy()

Copia elementi non duplicati

merge() Combina sequenze ordinate

Recommended