1 / 203

Introduzione

Introduzione al C++ e alla programmazione ad oggetti Corso Specialistico CNTC Bologna, 19-23 febbraio 2001 Andrea Dell’Acqua e Claudio Grandi. Introduzione. Le due componenti principali dei programmi: Algoritmi : l’insieme delle istruzioni che svolgono un particolare compito

jereni
Download Presentation

Introduzione

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 C++ e alla programmazione ad oggettiCorso Specialistico CNTCBologna, 19-23 febbraio 2001Andrea Dell’Acqua e Claudio Grandi

  2. Introduzione • Le due componenti principali dei programmi: • Algoritmi: l’insieme delle istruzioni che svolgono un particolare compito • Dati: ciò su cui gli algoritmi agiscono per produrre una soluzione unica • La relazione fra queste componenti definisce il paradigma di programmazione • Programmazione procedurale: problemi modellati dagli algoritmi. Dati immagazzinati in aree comuni o passate agli algoritmi • Programmazione ad oggetti: problemi modellati dalle relazioni fra tipi di dati astratti (ADT, Abstract Data Types), chiamati generalmente oggetti

  3. Il rapporto Dato-Algoritmo Programmazione Dati Algoritmi Linguaggio Bits Bits macchina Assemblers Symbolic Op-code Words Livello di astrazione Compilatori Variables & Statements Types Linguaggi Data Subroutines strutturati structures Ada (Modula) Abstract Packages Data Types (Modules) Object Oriented Objects Objects

  4. Cos’è un oggetto? • Né più né meno di quello che potreste trovare scritto in un vocabolario… • Un oggetto è un’entità che si possa immaginare dotata di determinate caratteristiche e funzionalità. • Lo stato di un oggetto è rappresentato da dati che ne descrivono le caratteristiche in un certo istante • Le funzionalità di un oggetto sono le operazioni che può svolgere quando glie lo si richiede (cioè quando riceve un messaggio) • Nella nostra vita quotidiana siamo molto più abituati a ragionare per oggetti che non in modo strutturato!

  5. Un esempio...

  6. Soldato

  7. … cos’è un oggetto: Funzione Codice funzione Funzione Codice funzione Dato Dato Dato Codice funzione Funzione Un insieme di dati e funzioni:

  8. Incapsulazione • Netta divisione fra interfaccia e implementazione • Da fuori si vede solo l’interfaccia che definisce i messaggi accettati dall’oggetto • I dettagli dell’implementazione (dati e codice delle funzioni) sono invisibili dall’esterno • Ogni oggetto ha in se tutto ciò che gli serve per rispondere alle chiamate (o deve sapere a chi chiedere…) • Il confinamento di informazioni e funzionalità in oggetti permette livelli maggiori di astrazione e semplifica la gestione di sistemi complessi.

  9. Approccio OO • Sono le strutture di dati che svolgono le azioni, non le subroutines • Il lavoro è svolto dal server, non dal client • “Cos’ è?” “Com’ è fatto?”  Data Oriented • “Cosa può fare per me?”  Object Oriented

  10. Perché programmare per oggetti? • Programmare per oggetti non velocizza l’esecuzione dei programmi... • Programmare per oggetti non ottimizza l’uso della memoria... E allora perchè programmare per oggetti? • Programmare per oggetti facilita la progettazione e il mantenimento di sistemi software molto complessi!

  11. Caratteristiche del software non mantenibile • Rigidità • non può essere cambiato con faciltà • non può essere stimato l’impatto di una modifica • Fragilità • una modifica singola causa una cascata di modifiche successive • i bachi sorgono in aree concettualmente separate dalle aree dove sono avvenute le modifiche • Non riusabilità • esistono molte interdipendenze, quindi non è possibile estrarre parti che potrebbero essere comuni

  12. Programmazione ad oggetti • La programmazione ad oggetti, attraverso l’incapsulazione, consente di: • ridurre la dipendenza del codice di alto livello dalla rappresentazione dei dati • riutilizzare del codice di alto livello • sviluppare moduli indipendenti l’uno dall’altro • avere codice utente che dipende dalle interfacce ma non dall’implementazione

  13. C++ e Object Orientation • Il C++ può essere usato come linguaggio procedurale o per programmazione ad oggetti • Object Orientation implementata attraverso il concetto di classe • Prima di affrontare il problema della programmazione OO con C++ dobbiamo: • capire dove la programmazione procedurale fallisce • affrontare la sintassi del C++

  14. Programmazione procedurale Idea: perché non usare una function? • Esempio: cinematica relativistica COMMON /MYDATA/ P1(4), P2(4), + P3(4), P4(4) REAL P1(4), P2(4), P3(4), P4(4) COSTHETA12 = (P1(1)*P2(1) + P1(2)*P2(2) + + P1(3)*P2(3))/... COSTHETA13 = (P1(1)*P3(1) + P1(2)*P3(2) + + P1(3)*P3(3))/... COSTHETA14 = (P1(1)*P4(1) + P1(2)*P4(2) + + P1(3)*P4(3))/... FUNCTION COSTHETA(P1, P2) REAL P1(4), P2(4) COSTHETA = (P1(1)*P2(1) + P1(2)*P2(2) + + P1(3)*P2(3))/... END COMMON /MYDATA/ P1(4), P2(4), + P3(4), P4(4) REAL P1(4), P2(4), P3(4), P4(4) COSTHETA12 = COSTHETA(P1, P2) COSTHETA13 = COSTHETA(P1, P3) COSTHETA14 = COSTHETA(P1, P4)

  15. Evoluzione del codice • Se cambia il formato del common block? COMMON /MYDATA/ P1(4), P2(4), P3(4), P4(4) COMMON /MYDATA/ P(4), E(4), THETA(4), PHI(4) • Bisogna cambiare la funzione (gli argomenti sono diversi) FUNCTION COSTHETA1(THETA1, THETA2, + PHI1, PHI2) COSTHETA1 = SIN(THETA1)*SIN(THETA2) * + COS(PHI1-PHI2) + COS(THETA1)*COS(THETA2) END • ...e il codice! COMMON /MYDATA/ P(4), E(4), + THETA(4), PHI(4) COSTHETA12 = COSTHETA1(THETA(1),THETA(2), + PHI(1), PHI(2)) COSTHETA13 = COSTHETA1(THETA(1),THETA(3), + PHI(1), PHI(3)) COSTHETA14 = COSTHETA1(THETA(1),THETA(4), + PHI(1), PHI(4))

  16. Il concetto di dipendenza • Nell’esempio precedente il codice di analisi (“alto livello”) dipende dai dettagli della struttura dati (“basso livello”). FUNCTION COSTHETA(P1, P2) REAL P1(4), P2(4) COSTHETA = (P1(1)*P2(1) + P1(2)*P2(2) + + P1(3)*P2(3))/... END COSTHETAdipende dalla struttura dei datiP1e P2 COMMON /MYDATA/ P1(4), P2(4), + P3(4), P4(4) COSTHETA12 = COSTHETA(P1, P2) COSTHETA13 = COSTHETA(P1, P3) COSTHETA14 = COSTHETA(P1, P4) Il codice di analisi dipende dalla struttura del common blockMYDATA

  17. OO riduce le dipendenze! • Riduce la dipendenza del codice di alto livello dalla rappresentazione dei datiPermette il riutilizzo del codice di alto livello • Nasconde i dettagli di implementazioneSupporta tipi di dati astratti (vedere seguito ...)

  18. Sintassi: FORTRANvsC/C++ • Struttura del programma In C/C++ non è necessario un particolare formato il codice PROGRAM TESTC esempio di programma ... END int main() {// esempio di programma ... return 0; // fine} spazi... IlC/C++è case sensitive Istruzioni separate da “;” INTEGER I INTEGER*4 J REAL X REAL*8 D int i;long j;float x;double d;

  19. Il main program • Ogni programma in C++, per essere eseguibile, deve contenere una funzione main() da cui l’esecuzione comincerà • main() deve avere un tipo (decidere quale è compito del programmatore). Regola generale è che main() ritorni un intero, a significare il return code dell’applicazione int main() { // il piu` semplice programma in C++ return 0; }

  20. I/O: lettura e scrittura • Non esiste nel C++ nativo. Si usa: iostream • Gli operatori << e >> sono usati per definire la direzione del flusso • cin, cout e cerr rappresentano lo standard input, output e error del programma #include <iostream> int main(){ return 0;} #include <iostream> cout << “Hello, world !” << endl; direttiva al preprocessore end of line

  21. Commenti • Esistono due tipi di commento in C++ • inline: • multiline (come in C): • I due tipi possono essere usati indifferentemente, ma si raccomanda di usare l’inline (più semplice e meno ambiguo) const int Ntries; // questo e` un commento inline // il resto della linea e’ trattato come un commento const int Ntries; /* questo e` un commento multiline: tutto viene trattato come un commento fino a quando il commento stesso non viene chiuso con uno */

  22. Tipi predefiniti in C++ • Sono definiti una serie di tipi numerici che permettono di rappresentare numeri interi, reali e caratteri • char (un solo byte) viene normalmente usato per rappresentare interi inferiori a 256 • stringhe e numeri complessi sono implementati come tipi derivati int intero in singola precisione long intero in doppia precisione float reale in singola precisione double reale in doppia precisione long double reale in precisione estesa unsigned int intero senza segno unsigned double reale senza segno in doppia precisione char carattere singolo bool variabili logiche

  23. Tipi predefiniti in C++ (2) Costanti carattere Esempi di costanti ‘\a’ alert ‘\\’ backslash ‘\b’ backspace ‘\r’ carriage return ‘\”’ double quote ‘\f’ form feed ‘\t’ tab ‘\n’ newline ‘\0’ carattere nullo ‘\’’ single quote ‘\v’ vertical tab ‘\101’ 101 ottale, ‘A’ ‘\x041’ esadecimale, ‘A’ 123 123 0x123 interi costanti, decimale, ottale, esadecimale 123l 123u interi, long, unsigned ‘A’ ‘1’ ‘\t’ caratteri, tab 3.14f 3.1415 3.1415L float, double, long double 300e-2 .03e2 30e-1 double, notazione esponenziale “Nome” stringa costante true false boolean Stringhe costanti “” stringa nulla (‘\0’) “nome” ‘n’ ‘o’ ‘m’ ‘e’ ‘\0’ “una \”stringa\”” stampa: una “stringa” “una stringa \ un \ alla fine della linea su piu` linee” per continuare la stringa

  24. Tipi predefiniti in C++ (3) OS 16 bit OS 32 bit OS 64 bit char[1] 8 8 8 int[1] 16 32 32 bool 16 32 32 short[1] 16 16 16 long[1] 32 32 64 float 32 32 32 double 64 64 64 long double 64 128 128 [1] Può essere unsigned

  25. Identificatori • Un identificatore è composto da uno o più caratteri • Il primo carattere deve essere una lettera o un underscore. Caratteri successivi possono essere lettere, numeri o underscore • Non c’ è un limite in lunghezza, anche se alcuni sistemi si limitano a considerare i primi 31 caratteri • Gli identificatori che iniziano con un doppio underscore o con un underscore e una lettera maiuscola sono riservati ad usi di sistema • C++ e` case sensitive! const int Ntries; double _attempts; double 2A; // errore!

  26. Keywords • Alcuni identificatori sono esplicitamente riservati al sistema (hanno un preciso significato in C++) e non possono essere usati asm else operator throw auto enum private true bool explicit protected try break extern public typedef case false register typeid catch float reinterpret_cast typename char for return union class friend short unsigned const goto signed using const_cast if sizeof virtual continue inline static void default int static_cast volatile delete long struct wchar_t do mutable switch while double namespace template dynamic_cast new this keyword

  27. const const int N=100; N non puo` essere cambiato double w[N]; N usato come per dimensionare un vettore const int vect[5]= le componenti di vect non {10,20,30,40,50}; possono essere cambiate Esempi di const • La keyword const viene utilizzata per dichiarare un oggetto costante • In C le costanti vengono normalmente dichiarate usando il preprocessore • in questo caso N e` una costante senza tipo ed il preprocessore sostituisce N ovunque lo trovi nel programma, senza rispettare le regole di scope(da evitare) #define N 100

  28. Dichiarazione • Le dichiarazioni associano un significato ad un identificatore • in C++ ogni cosa deve essere dichiarata per poter essere usata • Una dichiarazione è spesso anche una definizione. Per variabili semplici questo consiste nell’associare un valore alla variabile al momento della dichiarazione const int i; // la variabile i double max(double r1,double r2); // la funzione max const double pi=3.1415926; // definizione double max(double r1, double r2) { // dichiarazione return (r1>r2) ? r1: r2; // definizione di max }

  29. typedef • L’istruzione typedef viene utilizzata per creare un alias per tipi esistenti • typedef NON può essere usato per implementare nuovi tipi, ma solo per definire un alias typedef int INTEGER; // per i nostalgici del fortran typedef int BOOLEAN; // usato prima che bool venisse // implementato typedef void (*ptr_f)(); // ptr_f e` un puntatore ad una // procedura (subroutine) typedef mela frutto; // compila soltanto se mela // e` gia` stata definita

  30. Enumeratori • In C++ sono supportati tipi definiti dall’utente enum Color{ red, green, blue};Color screenColor = blue;Color windorColor = red;int n = blue; // validoColor c = 1;// errore enum Seme{ cuori, picche, quadri, fiori};

  31. Scope • Le variabili possono essere dichiarate e definite quasi ovunque in un programma in C++ • la visibilità (scope) di una variabile dipende da dove la variabile è stata dichiarata int func() { … const int n=50; // function scope for (int i=0;i<100;i++) // i e` locale { double r; // r e` locale ... } cout<<“n “<< n <<endl; // OK cout<<“i “<< i <<endl; // errore! Ma... cout<<“r “<< r <<endl; // errore! … }

  32. Scope (2) Scope resolution operator • Attenzione! La stessa variabile può essere ri-dichiarata (con visibilità diversa). Questo è da evitare (se possibile) per non rendere il programma oscuro e a rischio di errore! int i; // file (global) scope int func() { int i=50; // function scope, nasconde // la i a file scope for (int i=0;i<100;i++) // block scope. Nasconde // la i a function scope { int i; // questo e` un errore... ... } cout<<“i “<< i <<“ “<< ::i <<endl; ... }

  33. namespace • Funzioni e variabili definite a global scope sono visibili dappertutto in un programma in C++ • Per evitare che funzioni diverse (definite in librerie diverse) con lo stesso nome possano interferire (name clash), C++ implementa il concetto di namespace, che introduce un ulteriore, più alto livello di scope namespace mynames { int i; // la mia dichiarazione di i float max(float, float); // la mia dichiarazione di max } float mynames::max(float a, float b) // implementazione della { // funzione max appartenente return (a>b) ? a : b; // al namespace mynames }

  34. namespace (2) • Per utilizzare variabili e funzioni racchiuse in un namespace si può: • o accedere all’intero namespace • oppure accedere alla singola variabile o funzione • oppure dichiarare la singola funzione using namespace mynames; ... float r = max (2.1f, 5.3f); float r = mynames::max (2.1f, 5.3f); using mynames::max; ... float r = max (2.1f, 5.3f);

  35. Operatori Espressioni Aritmetiche Commento -i +w piu` e meno unari a*b a/b i%2 moltiplicazione, divisione, modulo a+b a-b addizione e sottrazione binarie a=3; assegnazione Operatori relazionali Fortran < minore di .LT. > maggiore di .GT. <= minore o uguale .LE. >= maggiore o uguale .GE. == uguale .EQ. != diverso .NE. ! Negazione unaria .NOT. && and logico .AND. || or logico .OR. bit-wise significato Auto-incremento Espressione e decremento ~i; Complemento bit a bit i&j; AND bit a bit i|j OR bit a bit i^j XOR bit a bit i<<n shift a sinistra di n pos. i>>n shift a destra di n pos. k = ++j; j=j+1; k=j; k = j++; k=j; j=j+1; k = --j; j=j-1; k=j; k = j--; k=j; j=j-1;

  36. Espressioni di assegnazione • Le espressioni di assegnazione sono valutate da destra a sinistra • Le assegnazioni multiple sono permesse • alcuni operatori di assegnazione combinano assegnazione ed altri operatori • Assegnazioni possono essere fatte all’interno di espressioni aritmetiche a = j++; j viene incrementato ed il risultato assegnato ad a a = b = c = d = 100; a *= b; // equivale ad a = a*b; a -= b; // equivale ad a = a-b; a = b + ( c = 3 ); // equivale a c=3; a=b+c;

  37. Statements Statement C++ commenti vuoto ; espressione j=j+k; composto { . . . . } usato in funzioni, if.. Costituisce un blocco goto goto label; da non usarsi if if (p==0) cerr<<“error”; un solo branch if-else if (x==y) cout<<“the same”; else cout<<“different”; due branch for for (j=0;j<n;j++) le dichiarazioni sono a[j]=0; permesse while while (i != j) 0 o piu` iterazioni i++; do-while do y=y-1; 1 o piu` iterazioni while (y>0); break break; esce dal blocco continue continue; prossima iterazione

  38. Statements (2) Statement C++ commenti switch switch (s) { case 1: si deve usare break per ++i; evitare di cadere nei case 2: casi successivi e --i; aggiungere un caso di default: default alla fine della ++j; lista }; dichiarazione int i=7; in un blocco, file o namespace try try {. . . .} usato per trattare le eccezioni label error: cerr<<“Error!”; usato con goto return return x*x*x; valore di ritorno di una funzione

  39. Statement composti • Uno statement composto in è costituito da una serie di statement contenuti fra parentesi graffe • Usato normalmente per raggruppare istruzioni in un blocco (if, for, while, do-while, etc.) • Il corpo di una funzione è sempre uno statement composto • La dichiarazione di una variabile può avvenire ovunque all’interno di un blocco, in questo caso lo scope della variabile sarà il blocco stesso • Ovunque si possa usare uno statement singolo si può definire un blocco

  40. if • Attenzione all’uso di = e == • Nel dubbio, usare sempre un blocco… • Attenzione agli else! if (i=1) // questo e` sempre vero!!! {. . . .} if (i != 0) // possibile divisione per 0 a++; // mancano delle {}? a/=i; if (i == 0) // possibile divisione per 0 if (a<0) { cerr<<“a e` negativo!”; } else b=a/i;

  41. while e do-while • La forma generale di un while è : • Lo statement verrà eseguito fino a quando la condizione verrà verificata (true). A seconda del volore della condizione, lo statement verrà eseguito zero o più volte • la sintassi di un do-while è invece: • Lo statement verrà quindi eseguito almeno una volta while (condizione) statement; do statement; while (condizione);

  42. break e continue • break e continue sono utilizzati nei loop per saltare alla fine del loop o fuori dal loop stesso • break e continue possono solamente essere utilizzati nel corpo di un for, while o do-while. break e` anche usato negli switch int i,n=0; int a[100]; cin>>i; // leggo il valore di i while (1) // loop infinito { if (i<0) break; if (n>=100) continue; a[n]=i; n++; // continue salta qui } // break salta qui

  43. switch • Lo switch è uno statement condizionale che generalizza lo if-else • lo statement è generalmente composito e consiste di diversi casee, opzionalmente, di un default switch (condizione) (statement); switch (n) { case 0: cout<<“ n e` nullo”<<endl; break; case 1: case 3: case 5: case 7: case 9: cout<<“ n e` dispari”<<endl; break; case 2: case 4: case 6: case 8: case 10: cout<<“ n e` pari”<<endl; break; default: cout<<“ n non e` compreso tra 0 e 10”<<endl; }

  44. switch (2) • Non si puo` dichiarare una variabile in uno dei case • … ma si puo` creare una variabile locale definendo uno statement composto... switch (k) { case 0: int j=0; // Illegale! Errore! . . . case 1: . . . } switch (k) { case 0: { int j=0; // OK, questo compila . . . } case 1: . . . }

  45. L’operatore ? • L’operatore ? e` l’unico esempio di operatore ternario in C++ • Equivale a: • Esempio: expr1 ? expr2 : expr3; if(expr1) expr2; else expr3; double max(double a, double b) { double max = (a>b) ? a : b; return max; }

  46. Sintassi: FORTRANvsC/C++ • Controllo di flusso del programma DO I = 1, 10 . . . ENDDO IF (I.EQ.10 .AND. J.GT.4 .OR. X) THEN . . . ENDIF DO WHILE(X .NE. 5) . . . ENDDO for (i = 1; i <= 10; i++) { . . .} if (i == 10 && j > 4 || x) { . . .} while( x != 5 ){ . . .}

  47. Funzioni matematiche • In C++ non esistono funzioni predefinite int main(){ return 0;} { double r, theta, phi; #include <iostream>cin >> r >> theta >> phi ; #include <cmath> double x = r * sin( theta ) * sin( phi ); double y = r * sin( theta ) * cos( phi ); double z = r * cos( theta ); cout << x << “, “ << y << “, “ << z << endl; cmath.hdefinisce sin, cos, ... • Potenze: pow(b,exp) (non si può usare ** )

  48. Array • Sono supportati gli array di dimensione fissa int main(){ int x[10]; for ( int i = 0; i < 10, i++ ) x[i] = 0; double m[5][5]; for ( int i = 0; i < 5; i++ ) for ( int j = 0; j < 5; j++ ) m[i][j] = i * j; return 0;} • Inizializzazione: int x[] = { 1, 2, 3, 4 };char[] t = { ‘C’, ‘i’, ‘a’, ‘o’, ‘\0’ };char[] s = “Ciao”;int m[2][3] = { {11, 12, 13}, {21, 22, 23} }; • L’indice va da 0 a n-1. Usare un indice maggiore di n-1 può causare un crash.

  49. Esempio con gli arrays • Moltiplicazione fra matrici: int main() { const int DIM=3; float m[DIM][DIM], m1[DIM][DIM], m2[DIM][DIM]; // Assumiamo che m1 ed m2 vengano riempiti qui... // Moltiplicazione: for (int i=0; i<DIM; i++) { for (int j=0; j<DIM; j++) { float sum=0; for (int k=0; k<DIM; k++) sum += m1[i][k] * m2[k][j]; m[i][j] = sum; } } return 0;}

  50. Puntatori j ptr 12 24 • Riferimento ad una locazione di memoria int main(){ int j = 12; return 0;} int *ptr = &j; #include <iostream> cout << *ptr << endl; j = 24; cout << *ptr << endl; cout << ptr << endl; 24 0x7b03a928 12 indirizzo di memoria

More Related