1 / 97

Introduzione al linguaggio C++ 5 lezioni Lunedì, Giovedì ore 12.00-13.30 Alessandro Lonardo

Introduzione al linguaggio C++ 5 lezioni Lunedì, Giovedì ore 12.00-13.30 Alessandro Lonardo alessandro.lonardo@roma1.infn.it Davide Rossetti davide.rossetti@roma1.infn.it Pagina WEB http://apegate.roma1.infn.it/ ~lonardo Testi base: -Bjarne Stroustrup, Il Linguaggio C++,

hedva
Download Presentation

Introduzione al linguaggio C++ 5 lezioni Lunedì, Giovedì ore 12.00-13.30 Alessandro Lonardo

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Introduzione al linguaggio C++ 5 lezioni Lunedì, Giovedì ore 12.00-13.30 Alessandro Lonardo alessandro.lonardo@roma1.infn.it Davide Rossetti davide.rossetti@roma1.infn.it Pagina WEB http://apegate.roma1.infn.it/~lonardo Testi base: -Bjarne Stroustrup, Il Linguaggio C++, Addison-Wesley. -Brian W. Kernighan, Dennis M. Ritchie, Il Linguaggio C, Jackson libri.

  2. Programma del corso • Lezione 1 • Paradigmi di programmazione • Dichiarazioni • Tipi • Costanti • Lezione 2 • Operatori • Istruzioni • Funzioni • Header File • Il Preprocessore • Le librerie • Lezione 3 • Classi • Interfacce ed implementazioni • Caratteristiche delle classi • Costruttori e distruttori • Lezione 4 • Classi derivate • Classi astratte • Ereditarietà multipla • Controllo dell’accesso • Memoria dinamica

  3. Lezione 5 • Overload di Operatori • Template • La Standard Template Library • argomenti non trattati a lezione

  4. Paradigmi di Programmazione Programmazione Procedurale Si definiscano le procedure desiderate; Si utilizzino gli algoritmi migliori. -Programmatore concentrato sull’algoritmo -Supporto fornito dai linguaggi: funzioni, procedure. (Fortran, Pascal, C...) -Il programma viene suddiviso in funzioni, ogni funzione realizza un algoritmo o una parte di esso. Es. double sqrt(double arg) { //codice per il calcolo della radice quadrata } void some_function() { double root2 = sqrt(2.0); //... }

  5. Programmazione Modulare Modulo = Dati + Procedure; Si decida quali sono i moduli necessari; Si suddivida il programma in modo che i dati siano nascosti nei Moduli. -Dati nascosti: nomi delle variabili, delle costanti e dei tipi sono resi locali al modulo. -Il linguaggio C consente l’impiego di questo paradigma attraverso Il concetto di unità di compilazione. Es. File stack.h: //dichiarazione della interfaccia per //il modulo stack di caratteri void push(char); char pop(); const int stack_size = 100;

  6. File stack.cc (implementazione de modulo): #include “stack.h” //usa l’interfaccia stack //static significa: simbolo locale //a questo modulo (file) static char v[stack_size]; //lo stack viene inizializzato vuoto static char* p = v; void push(char c) { //implementazione } char pop() { //implementazione }

  7. Uso del modulo stack di caratteri: File bubu.cc: #include “stack.h” //usa il modulo stack void some_function() { push(‘y’); char c = pop(); assert(c == ‘y’); } -in questo file non si ha accesso alla struttura interna dello stack, è possibile utilizzare lo stack solo per mezzo delle funzioni esposte nell’interfaccia del modulo. -Il linguaggio C++ estende il supporto del C alla programmazione modulare attraverso l’uso delle classi.

  8. Astrazione dei dati Si decida quali tipi si desiderano; si fornisca un insieme completo di operazioni per ogni tipo. -estende il concetto di modulo al caso in cui siano necessari più oggetti di un certo tipo (come avrei fatto a dichiarare 2 stack?) -I linguaggi che supportano la programmazione modulare permettono l’astrazione dei dati. -Linguaggi come Ada, Java, C++... supportano il paradigma della astrazione dei dati. File complex.h: //dichiarazione del tipo numero complesso class Complex { double re, im; public: Complex(double r, double i) {re = r; im = i;} Complex(double r) {re = r; im = 0;} friend complex operator+(Complex, Complex); friend Complex operator-(Complex, Complex); friend Complex operator-(Complex);//unario friend Complex operator*(Complex, Complex); friend Complex operator/(Complex, Complex); };

  9. File complex.cc: //implementazione del tipo complex //... Complex operator+(Complex a1, Complex a2) { return Complex(a1.re+a2.re, a1.im+a2.im); } //... File bubu.cc: //uso del tipo complex void some_function() { Complex a(2.0, 1.0), b(3.14), i(0.0, 1.0), c; c = a*i+b; //... } -L’uso del tipo complex definito dall’utente è del tutto analogo a quello dei tipi predefiniti. -Il tipo di dato astratto è una scatola nera. Il suo comportamento non può essere cambiato, se non ridefinendo il tipo. Questa è una limitazione significativa.

  10. Esempio: un sistema grafico che gestisce cerchi, triangoli e quadrati. -Esistono i seguenti tipi astratti: class Point {//...}; class Color {//...}; enum Kind {circle, triangle, square}; //rappresentazione di una forma class Shape { Point center; Color col; Kind k; public: point where() {return center;} void move(point to) {center = to; draw(); } void draw(); void rotate(int); }; -k è un “campo tipo” utile alle funzioni per determinare il tipo di forma su cui si lavora: void Shape::draw() { switch(k) { case circle: //disegna un cerchio case triangle: //disegna un triangolo case square: //disegna un quadrato } }

  11. -Problemi: • draw() (come le altre operazioni) deve conoscere tuttti i tipi • di forme su cui si lavora. Se si introduce una nuova forma il • codice di draw() dovrà essere modificato. • 2. Non è possibile aggiungere nel sistema la gestione di una • nuova forma se non si ha accesso al codice sorgente di ogni • operazione. • 3. Ogni modifica espone il sistema alla introduzione di bug su • codice già sviluppato. • -La sorgente di tutti questi problemi è la mancata espressione della • distinzione tra le proprietà generali di una forma(ha un colore, • ha una posizione, si può disegnare...) e le proprietà di una • forma particolare (il cerchio ha un raggio, si disegna come un • cerchio (!), ...). • -L’espressione di questa distinzione in modo utile per la scrittura del • codice rappresenta la • Programmazione Orientata agli Oggetti • -Il supporto che il linguaggio C++ offre a questo paradigma è il • meccanismo della ereditarietà.

  12. -Il concetto di forma più generale: class Shape { Point center; Color col; //è sparito il fastidioso Kind public: point where() {return center;} void move(point to) {center = to; draw(); } virtual void draw(); //ora è virtual virtual void rotate(int); //ora è virtual }; -“virtual”: può essere ridefinito in una classe derivata -Una forma particolare: class Circle : public Shape { int radius; public: void draw() {//disegna un cerchio!}; void rotate(int) {}//facile implementazione }; -La classe Circle è derivata (sottoclasse) dalla classe Shape. -La classe Shape è di base (superclasse) per la classe Circle.

  13. Esempio di uso: funzione che prende un vettore di size forme e le ruota di angle gradi. void rotate_all(Shape v[], int size, int angle) { int i = 0; while (i<size) { v[i].rotate(angle); i = i+1; } } -l’elemento v[i]è in principio una forma qualsiasi, l’operazione di rotazione sarà quella che gli compete. -Nella fase di progettazione del software è necessario individuare la massima quantità di elementi in comune tra i tipi del sistema e rappresentare queste similitudini utilizzando classi di base comuni. Paradigma di programmazione orientata agli oggetti Si determini quali classi si desiderano; Si fornisca un insieme completo delle operazioni di ogni classe; Si espliciti ciò che hanno in comune per mezzo della ereditarietà

  14. Dichiarazioni -Identificatore C++: sequenza di lettere e cifre, il primo carattere deve essere una lettera (o “underscore”, ‘_’). Non si possono usare keyword. Case sensitive. Buoni identificatori: Hello hello _bubu_ ApeMaia un_identificatore_molto_lungo var1 var2 Non sono accettati: 1var $pippo for lunghezza.massima -Dichiarazione di un identificatore: Prima dell’uso di qualsiasi identificatore bisogna specificare il Suo tipo: Char c; int count = 1; char* name = “ciccio”; Const double pi=3.1415926535897932385 float minus(float arg) { return -arg; } -Queste sono anche definizioni di identificatori: definiscono l’entità alla quale il nome si riferisce. Per le variabiliè la quantità di memoria allocata, per le funzioni la loro implementazione, per le costanti il loro valore.

  15. -le seguenti sono solo dichiarazioni: extern float sqrt(float arg); extern int err_num; struct user; -Una dichiarazione ha effetto in generale in un sottoinsieme del programma (visibilità). int x; // x globale, visibile in tutto il pr. void f() { int x; //x locale, nasconde x globale x = 1; { int x; //locale, nasconde la prec. Locale x = 2; } x = 3; } int* p = &x;

  16. Oggetto : zona di memoria lvalue: espressione che fa riferimento ad un oggetto -Un oggetto viene creato all’atto della sua definizione e distrutto quando non è più visibile (anche i locali definiti static) int a = 1; void f() { int b = 1; //inizializzato ad ogni chiamata static int c = a; //ini. una sola volta cout << “ a = “ << a++ << “ b = “ << b++ << “ c = “ << c++ << endl; } int main() { while ( a < 4 ) f(); } Output: a = 1 b = 1 c = 1 a = 2 b = 1 c = 2 a = 3 b = 1 c = 3

  17. Tipi il tipo specifica le operazioni che si possono compire sul dato e la loro semantica Tipi fondamentali: void Tipi interi: bool char short int int long int Tipi floating point (reali): float double long double Tipi interi senza segno, valori logici, vettori di bit: unsigned char unsigned short int unsigned int unsigned long int Per esplicitare i tipi interi con segno: signed char signed short int signed int signed long int -se il tipo è omesso si assume int

  18. -tipi interi e floating point diversi, diversa occupazione di memoria, velocità di esecuzione... -Il linguaggio definisce solo queste restrizioni: 1==sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long) sizeof(float)<=sizeof(double)<=sizeof(long double) sizeof(I)==sizeof(signed I) == sizeof(unsigned I) Ad esempio, architettura IA32: bool 8 bit char 8 bit short 16 bit int 32 bit long int 32 bit float 32 bit double 64 bit long double 80 bit

  19. Conversione tra i tipi -implicita: in generale si possono mescolare liberamente variabili di tipo diverso in una espressione.(non è un bello stile...) int i = 2; float f, g = 2.0; f = i * g - 4; -esplicita: float r = (float) 2; //cast float r = float(2); -promozioni Tipi derivati -definiti a partire da quelli base o user-defined per mezzo degli operatori di dichiarazione: * puntatore & reference [] array Esempio: int* pi; //tipo = puntatore ad int double& d; //tipo = reference a double float v[10]; //tipo = vettore di 10 float

  20. -Un altro modo di introdurre un tipo derivato è la definizione di una struttura: struct Point { int x; int y; }; Point a,b,c;

  21. Puntatori puntatore: variabile che contiene l'indirizzo di un'altra variabile -In C++ i puntatori hanno un tipo associato (eccezione void *). c char c = 'y'; char* p; p = &c; char c2 = *p; 'y' p c 'y' null c p &c 'y' c p c2 &c 'y' 'y' &c: indirizzo di c. *p: dereferenziazione di p, accesso all'oggetto puntato. -avrei potuto scrivere: char *p = &'y'?

  22. no! ottengo: non-lvalue in unary '&'. Naturalmente posso dichiarare un puntatore a puntatore: p c2 c char** pp = &p; &c 'y' 'y' pp &p **pp = 'z'; p c c2 &c 'z' 'y' pp &p cout << c << '\t' << c2 << endl; in output: z y

  23. -se p è un puntatore di tipo T* allora *p può comparire ovunque ci si aspetti un oggetto di tipo T: int i = 4; int* pi = &i; int* pi2; *pi = *pi + 1; //i=5 pi2 = pi; *pi2 = i * 2; //i=10 Quanto vale i? -void*: è il tipo che corrisponde ai puntatori generici, qualsiasi puntatore può essere convertito a void* e poi riconvertito nel suo tipo originale senza perdita di informazione. Questo tipo è utilissimo come parametro di funzioni.

  24. -In realtà esistono anche puntatori a funzione int (*funp) (int, int); è la dichiarazione di un puntatore di nome funp ad una funzione che accetta due parametri di tipo int e restituendo un tipo int come risultato. La dereferenziazione di funp restituisce una funzione. Esempio: //restituisce il massimo tra arg1 e arg2 int max(int arg1, int arg2) {//...} //restituisce il minimo tra arg1 e arg2 int min(int arg1, arg2) {//...} int (*funp) (int, int); int i = 1, j = 2, k, l; funp = &max; k = (*funp)(i, j); funp = &min; l = (*funp)(i, j); Quanto valgono k ed l?

  25. array tipo T, T[size] è un vettore di size elementi di tipo T. -L'indice è compreso tra 0 e size-1. -size deve essere una costante intera; alcune implementazioni del compilatore (ad es. GNU) permettono l'uso di variabili o espressioni intere. float v[3]; //v[0], v[1], v[2] int m[2][3];//2 vettori di 3 interi char* vpc[10];//vettore di 10 punt. a char -Inizializzazione: //v[] ha 6 elementi int v[] = {137, -12, 53, 12943, 21, -20}; float vf[] = {12.2, 0.1, -22.1}; double id[3][3] ={ {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0} }; char vc[] = {'c', 'i', 'a', 'o', '\0'};

  26. -solo per i vettori di char si può utilizzare una notazione più comoda: char vocali[] = "aeiou"; //in questo caso il carattere di fine stringa //viene aggiunto automaticamente -boundary checking: no! Il compilatore non controlla la correttezza degli indici degli elementi di array. Si può facilmente ottenere un errore. Puntatori ed array -Il nome di un array può anche essere usato come puntatore al suo primo elemento: int v[10]; int* pi = v; *pi = 0;//equivale a v[0] = 0 pi++; //ora pi punta a v[1] *pi = 1;//v[1] = 1 pi--; //ora pi punta a v[0] pi = pi +5 ; //ora pi punta a v[5] int offset = pi - v; //numero di el. tra i 2 p. aritmetica dei puntatori +, -, ++, --. Da usare con grande cautela, è facile puntare ad aree di memoria sbagliate uscita dal programma con errore, il famigerato segmentation fault

  27. Strutture • Meccanismo per introdurre tipi di dato costituiti da un insieme di • elementi di tipi (anche) diversi. • struct Particle { • double p[3]; • double v[3]; • int charge; • }; • -si possono dichiarare variabili di questo nuovo tipo: • Particle p1, p2, p3; • -si può accedere ai campi del tipo usando l'operatore . • p1.p[0] = p1.p[1] = p1.p[2] = 0.0; • p1.v[0] = p1.v[1] = p1.v[2] = 0.0; • p1.charge = -1; • //poi vedremo che risulta più comodo • //utilizzare il costruttore • //... • p2 = p1; • //...

  28. -il nome del tipo risulta utilizzabile anche nella definizione del tipo stesso: struct Link { Link* prev; Link* succ; }; -ma ciò non significa che si possono dichiarare oggetti del nuovo tipo durante la sua dichiarazione! struct NewType { NewType x; //ERRORE IN COMPILAZIONE //... }; -Come si gestiscono i riferimenti incrociati durante le dichiarazioni? Meccanismo della forward declaration.

  29. Esempio: struct List; //dichiarazione non definizione struct Link { Link* prev; Link* succ; List* member_of; }; struct List { Link* head; }; -In generale il nome della struct può essere utilizzato prima della sua definizione quando non è necessario conoscere la sua dimensione. struct Astruct; void f(Astruct); //no problem Astruct a; //Errore! f(a); //Errore!

  30. typedef • -introduce un nuovo nome per un tipo • -comodo per costruire convenzioni proprie: • typedef double Mass; • typedef double Distance; • Mass m1, m2, m3; • Distance d1, d2, d3; • -esempi abbastanza comuni: • typedef unsigned char uchar; • typedef unsigned short ushort; • typedef unsigned int uint; • -è utile per abbreviare tipi complicati (come i puntatori a funzione): • typedef void (*calc_func)(float); • calc_func func_table[10]; • è certamente più espressivo di: • void (* func_table[10])(float);

  31. reference nome alternativo di un oggetto -tipo T, T& significa riferimento a T. int i = 1; int& r = i; //r ed i si rif. allo stesso int int x = r; // x = 1 r = 2; // i = 2 -Una reference deve essere sempre inizializzato (a cosa riferirebbe?) -Inizializzazione reference != assegnamento di variabile -Gli operatori applicati ad una reference non agiscono su di essa, ma sull'oggetto a cui si riferisce: int ii = 0; int& rr = ii; rr++; //è ii che viene incrementato, non rr -una reference non può essere modificata dopo l'inizializzazione. -Come vedremo sono utili come parametri di funzioni e nella definizione degli operatori definiti dall'utente.

  32. costanti senza nome -costanti intere: decimali 0 137 12 3 1 ottali 0 064 0237 esadecimali 0x0 0x3 0x7fff 0xfefe -suffissi U, L, LL: void f(int); void f(unsigned int); void f(long int); void f(long long int); f(3); f(3U); f(3L); f(3LL); -costanti floating point: 0.0 1.37 2. 1.3e10 1.6e-15 -costanti carattere (ASCII, EBCDIC, UNICODE...) 'a' '2' '\n' '\t' si può, ma è meglio evitare (portabilità del codice): '\137' '\x05f' 95 codice ASCII di '_'

  33. costanti con nome la keyword const premessa alla dichiarazione di un oggetto lo rende una costante invece di una variabile (deve essere inizializzato): const int bu = 20; bu++; //ERRORE const char* pippo = "abcde"; -Chi è costante il puntatore o l'oggetto puntato? pippo[2] = 'z'; //ERRORE pippo = "ciccio"; ovvero ho dichiarato un puntatore a costante. -Per rendere costante il puntatore si usa l'operatore *const char *const bubu = "yogi"; bubu[3] = 'a'; bubu = "napo"; //ERRORE ovvero ho dichiarato un puntatore costante. -infine: const char *const cp = "fred"; -notare che non si può: const int x = 10; int* pi = &x; //ERRORE, potrei modificare x const int* pic = &x; //no problem -vantaggi per il compilatore usando const (e ovviamente per l'utente).

  34. enum -un nome simbolico per ogni costante: enum { PICCOLO, MEDIO, GRANDE }; equivale a: const int PICCOLO = 0; const int MEDIO = 1; const int GRANDE = 2; -è possibile assegnare un nome, facendo diventare l'enum un nuovo tipo: enum Verdure { RAPE, BROCCOLI, CIPOLLE }; //... Verdure cose_da_comprare; cose_da_comprare = RAPE; int j = BROCCOLI; Verdure da_preparare = 2; //ERRORE!! Verdure da_preparare = Verdure(2); //OK

  35. -in realtà gli enumeratori si possono inizializzare a piacere: enum Colors { red = 2, green, blue = green + 1, grey = blue * 2 }; //... cout << grey << ' ' << blue << ' ' << green << ' ' << red << endl;; Cosa ottengo in uscita? enum <---> switch

  36. union -definisce piu` modi di vedere lo stesso oggetto: // nell’ipotesi sizeof(int)==4 union MultipleAccess { int word_value; unsigned short halfword_values[2]; unsigned char byte_values[4]; }; -come si usa ? MultipleAccess value; value.word_value = 0xA3458543; //cosi` accedo ai bytes: unsigned char first_byte = value.byte_values[0]; //cosi` alle parole di 16 bit (half word): unsigned short second_halfword = value.halfword_values[1]; cout << hex << value.word_value << ' ' << (int) first_byte << ' ' << second_halfword << endl; -cosa ottengo in uscita?

  37. word = a3458543 byte[0] = 43 halfword[1] = a345 -E' utilissimo quando si abbia necessita di risparmiare memoria (lo stesso spazio occupa oggetti diversi in momenti diversi): enum EntryType { STRING, INT}; union EntryValue { char* string_val; int int_val; }; struct Entry { char* name; EntryType type; EntryValue value; }; //... Entry a[10]; a[0].name = "Pippo"; a[0].type = STRING; a[0].value.string_val = "Amico di Topolino"; a[1].name = "Targa di Paperino"; a[1].type = INT; a[1].value.int_val = 313;

  38. campi di bit -modo per inserire oggetti di dimensioni ridotte in una sola word (economizzando lo spazio occupato). struct { unsigned int sign : 1; unsigned int exponent: 8; unsigned int fraction0: 7; unsigned int fraction1: 16; } number; -i campi si comportano come degli interi (di dimensione ridotta) -Tutti i dettagli (come avviene l'allocazione dei campi in memoria...) dipendono dalla macchina. -Tipo di dato con cui è facile scrivere codice non portabile

  39. operatori • -aritmetici (tipi interi e floating point): • + - * / • % resto della div. int (modulo) • ++ -- pre e post incremento/decremento • - + unari • -esempio: • int i, j, inc_i, j_inc; • i = j = 3; • inc_i = ++i; • j_inc = j++; • cout << i << '\t' << j << '\t' • << inc_i << '\t' << j_inc << endl; • ottengo: • 4 4 4 3

  40. -relazionali: > >= < <= == != -logici: && AND || OR ! NOT le espressioni formate con questi operatori vengono valutate da sin. a destra, bloccandosi non appena si determina il risultato. Attenzione! int ciao() { cout << "Ciao" << endl; return 1; } //... int i = 10; unsigned booleano = (i == 10) || (ciao() == 1); Verremo salutati?

  41. -bit a bit (tipi interi), utili per lavorare con vettori di bit: & AND | OR ^ XOR << shift a sinistra >> shift a destra (logico/aritmetico) ~ complemento ad uno -mascherare (azzerare) insiemi di bit: AND n = n & 0xF0 //11110000 -accendere insiemi di bit: OR n = n | 0x1; //dispari -moltiplicare per potenze di 2 (x = y * 2 z) x = y << z; -dividere per potenze di 2 (x = y / 2 z) x = y >> z; - mascherare il bit meno significativo: n = n & (~0x1);

  42. -assegnamento (semplice e composto): = assegnamento *= /= %= += -= <<= >>= &= |= ^= es: a *= 2; ---> a = a * 2; -vari: . selezione elemento object.member -> selezione elemento pointer->member es: struct Color { int r,g,b; }; //... Color c; Color* pc = &c; //... c.r = pc->r;

  43. [] indicizzazione pointer[expr] • () chiamata di funzione expr(expr_list) • () costruzione valore type(expr_list) • & indirizzo di &lvalue • * dereferenziazione *expr • new crea un oggetto new type • delete distrugge un oggetto delete pointer • sizeof dimensioni del tipo sizeof type • sizeof dimensioni oggetto sizeof expr • :: scope resolution class_name::member • ?: espressione condiz. expr?expr:expr • , virgola expr, expr

  44. associatività • -unari e assegnamento associativi a destra: • a = b = c ---> a = ( b = c ) • *p++ ---> *(p++) //non (*p)++ • -tutti gli altri sono associativi a sinistra • precedenza degli operatori: manuale di riferimento! • -esiste la forma funzionale di quasi tutti gli operatori visti: • double n1 = 1.33; • double n2 = .3E-2; • double result; • result = operator+(n1,n2); • -e` come se il compilatore avesse predefinite e utilizzato le • funzioni speciali: • double operator +(const double &d1, • const double &d2); • idem per: • int operator <(const int &n1, const int &n2); • int operator ~(const int &n1); • int operator >>=(const int &n1, • const int &n2); • -nessuno usa questa forma, di solito, ma servono per l’overloading • nei tipi definiti dall'utente

  45. costrutti if-else permette di esprimere una decisione if(espressione) istruzione_1 else istruzione_2 -per istruzione si intende anche un blocco di istruzioni (sequenza di dichiarazioni ed istruzioni tra parentesi graffe), che a sua volta può contenere altri blocchi... es. if( a > b ) max = a; else max = b;

  46. switch-case permette di operare delle scelte multiple controllando se una espressione assume un certo valore in un insieme di costanti intere switch (espressione) { case const_expr1 : istruzioni case const_expr2 : istruzioni ... default : istruzioni } -Risulta conveniente (e migliora la leggibilità del codice) usare degli enum come valori possibili per i case.

  47. es. enum Animale {CANE, GATTO, TOPO}; Animale bu; //... switch(bu) { case CANE: cout << “BAU!" << endl; break; case GATTO: cout << “MIAO!” << endl; break; case TOPO: cout << “SQUIT!” << endl; break; default: cout << “Un minollo?” << endl; break; }

  48. while permette di eseguire iterativamente una istruzione (o blocco) while (espressione) istruzione espressione viene valutata, se il suo valore != 0 allora viene eseguita istruzione ed espressione viene valutata di nuovo. Il ciclo si interrompe quando espressione diventa falsa (uguale a 0). -istruzione a seconda del valore di espressione puo` anche non esser mai eseguita. es. while(i == 0 && j < 100) { //... if (ww) break; //esci dal while if (kk) continue;//riparti dalla iterazione succ. v1[j] = v2[j] + v3[j++];//attenzione }

  49. do-while • controlla la condizione di uscita al termine • di ogni iterazione • do • istruzione • while (espressione); • -e` eseguito almeno una volta : • int k = 0; • ... • do • { • … • k++; • } while(k < 100);

  50. for struttura iterativa alternativa allo while for (espr1; espr2; espr3) istruzione equivale a: espr1; while (espr2) { istruzione espr3; } -in molti casi è piu' comodo da usare for( solo_la_prima_volta; all_inizio_di_ogni_ciclo; alla_fine_di_ogni_ciclo) { // in qualunque momento posso: // uscire dal ciclo conbreak // oppure andare direttamente // alla iterazione succ. con continue }

More Related