C/C++/JAVA Refresh rapido
Cominciamo col C
Struttura di un programma C /* This is  a comment */ // This is a one-line comment # include <stdio.h> /* includes header ...
Tipi <ul><li>int - stores integers (-32767 to +32768) </li></ul><ul><li>unsigned int – 0 to 65535 </li></ul><ul><li>char –...
printf <ul><li>printf (“%d”,i); </li></ul><ul><li>Usual variable type  Display </li></ul><ul><ul><li>%c  char  single char...
Operatori <ul><li>+  addition </li></ul><ul><li>- subtraction </li></ul><ul><li>*  multiplication </li></ul><ul><li>/  div...
Incremento e decremento <ul><li>++  Increment operator </li></ul><ul><li>-- Decrement Operator </li></ul><ul><li>k++ or k-...
Funzioni e prototipi #include <stdio.h> int add1(int); void main() { int x; x=5; x=add1(x); printf(&quot;%d“,x); } int add...
Operatori sui bit <ul><li><<  left shift </li></ul><ul><li>>>  right shift </li></ul><ul><li>|  bitwise OR </li></ul><ul><...
Tabella di “verità”
Esempio shifting
Condizionali <ul><li>if  (expression)  statement </li></ul><ul><li>else   statement </li></ul><ul><li>while (expression) s...
Array int x[10]; double y[15]; x[10]=10; char c[15];
Puntatori!!! int a, *b, c; // b is a pointer b = &a; // Store in b the address of a c = *b; // Store in c the value at  //...
Puntatori a caratteri e array char *y; char x[100]; y = &x[0]; y = x; // Does the same as the line above *(y+1) gives x[1]...
Ancora puntatori int x,y; int *p1,*p2; 1000 1004 1008 1012 x y p1 p2
Ancora puntatori(2) x=-42; y=163 1000 1004 1008 1012 x y p1 p2 -42 163
Ancora puntatori(3) p1=&x; p2=&y; 1000 1004 1008 1012 x y p1 p2 -42 163 1000 1004
Ancora puntatori(4) *p1=17; 1000 1004 1008 1012 x y p1 p2 17 163 1000 1004
Ancora puntatori(5) p1=p2; 1000 1004 1008 1012 x y p1 p2 17 163 1000 1004
Ancora puntatori(6) <ul><li>Passaggio di parametri per riferimento </li></ul><ul><li>Aritmetica dei puntatori </li></ul><u...
Strutture struct emprec { char name[25]; int age; int pay; }; struct emprec employee; employee.age=32;
C++ extend C <ul><li>Le classi, con funzioni virtuali ed ereditarietà multipla </li></ul><ul><li>Le eccezioni </li></ul><u...
Introduzione al C++ e alla programmazione ad oggetti
Introduzione <ul><li>Le due componenti principali dei programmi: </li></ul><ul><ul><li>Algoritmi : l’insieme delle istruzi...
Il rapporto Dato-Algoritmo Linguaggio  Bits  Bits macchina Programmazione  Dati  Algoritmi   Livello di astrazione Assembl...
Cos’è un  oggetto ? <ul><li>Né più né meno di quello che potreste trovare scritto in un vocabolario… </li></ul><ul><ul><li...
Un esempio...
Soldato
…  cos’è un  oggetto : <ul><li>Un insieme di dati e funzioni: </li></ul>Funzione Funzione Funzione Codice funzione Codice ...
Incapsulazione <ul><li>Netta divisione fra  interfaccia  e  implementazione </li></ul><ul><li>Da fuori si vede solo l’inte...
Approccio OO <ul><li>Sono le strutture di dati che svolgono le azioni, non le  subroutines </li></ul><ul><li>Il lavoro è s...
Perché programmare  per oggetti ? <ul><li>Programmare  per oggetti  non velocizza l’esecuzione dei programmi... </li></ul>...
Caratteristiche del software  non mantenibile   <ul><li>Rigidità </li></ul><ul><ul><li>non può essere cambiato con faciltà...
Programmazione ad oggetti <ul><li>La programmazione ad oggetti, attraverso l’ incapsulazione , consente di: </li></ul><ul>...
C++  e Object Orientation <ul><li>Il  C++  può essere usato come linguaggio procedurale o per programmazione ad oggetti </...
Programmazione procedurale <ul><li>Esempio: cinematica relativistica </li></ul>COMMON /MYDATA/ P1(4), P2(4),  +  P3(4), P4...
Evoluzione del codice <ul><li>Se cambia il formato del common block? </li></ul>COMMON /MYDATA/ P1(4), P2(4), P3(4), P4(4) ...
Il concetto di dipendenza <ul><li>Nell’esempio precedente il codice di analisi (“ alto livello ”) dipende dai dettagli del...
OO riduce le dipendenze! <ul><li>Riduce la dipendenza del codice di alto livello dalla rappresentazione dei dati Permette ...
Sintassi:  FORTRAN   vs   C / C++ <ul><li>Struttura del programma </li></ul>PROGRAM  TEST C esempio di programma ...   END...
Il main program <ul><li>Ogni programma in  C++ , per essere eseguibile, deve contenere una funzione  main()  da cui l’esec...
I/O: lettura e scrittura <ul><li>Non esiste nel  C++  nativo. Si usa:  iostream </li></ul><ul><ul><li>Gli operatori  <<  e...
Commenti <ul><li>Esistono due tipi di commento in  C++ </li></ul><ul><ul><li>inline: </li></ul></ul><ul><ul><li>multiline ...
Tipi predefiniti in  C++ <ul><li>Sono definiti una serie di tipi numerici che permettono di rappresentare numeri interi, r...
Tipi predefiniti in  C++  (2) 123  123  0x123  interi costanti , decimale, ottale,  esadecimale 123l  123u interi, long,  ...
Tipi predefiniti in  C++  (3) char [1] int [1] bool short [1] long [1] float double long double 8 16 16 16 32 32 64 64 8 3...
Identificatori <ul><li>Un identificatore è composto da uno o più caratteri </li></ul><ul><li>Il primo carattere  deve  ess...
Keywords <ul><li>Alcuni identificatori sono esplicitamente riservati al sistema (hanno un preciso significato in  C++ ) e ...
const <ul><li>La keyword  const  viene utilizzata per dichiarare un oggetto costante  </li></ul><ul><li>In  C  le costanti...
Dichiarazione <ul><li>Le dichiarazioni associano un significato ad un identificatore </li></ul><ul><li>in  C++  ogni cosa ...
typedef <ul><li>L’istruzione  typedef  viene utilizzata per creare un  alias  per tipi esistenti </li></ul><ul><li>typedef...
Enumeratori <ul><li>In  C++  sono supportati tipi definiti dall’utente </li></ul>enum Color {   red, green, blue }; Color ...
Scope <ul><li>Le variabili possono essere dichiarate e definite quasi ovunque in un programma in  C++ </li></ul><ul><li>la...
Scope (2) <ul><li>Attenzione! La stessa variabile può essere ri-dichiarata (con visibilità diversa). Questo è da  evitare ...
namespace <ul><li>Funzioni e variabili definite a  global scope  sono visibili dappertutto in un programma in  C++ </li></...
namespace (2) <ul><li>Per utilizzare variabili e funzioni racchiuse in un namespace si può: </li></ul><ul><ul><li>o accede...
Operatori -i +w piu` e meno unari a*b a/b i%2 moltiplicazione, divisione, modulo a+b a-b addizione e  sottrazione binarie ...
Espressioni di assegnazione <ul><li>Le espressioni di assegnazione sono valutate da destra a sinistra </li></ul><ul><li>Le...
Statements vuoto ; espressione j=j+k; composto { . . . . } usato in funzioni, if.. Costituisce un blocco goto  goto label;...
Statements (2) switch switch (s) { case 1: si deve usare break per ++i; evitare di cadere nei  case 2: casi successivi e  ...
Statement composti <ul><li>Uno statement composto in è costituito da una serie di statement contenuti fra parentesi graffe...
if <ul><li>Attenzione all’uso di  =  e  == </li></ul><ul><li>Nel dubbio, usare sempre un blocco… </li></ul><ul><li>Attenzi...
while  e  do-while <ul><li>La forma generale di un  while  è : </li></ul><ul><li>Lo statement verrà eseguito fino a quando...
break  e  continue <ul><li>break  e  continue  sono utilizzati nei loop per saltare alla fine del loop o fuori dal loop st...
switch <ul><li>Lo  switch  è uno statement condizionale che generalizza lo  if-else   </li></ul><ul><li>lo statement è gen...
switch  (2) <ul><li>Non si puo` dichiarare una variabile in uno dei  case </li></ul><ul><li>…  ma si puo` creare una varia...
L’operatore  ? <ul><li>L’operatore  ?  e` l’unico esempio di operatore ternario in  C++ </li></ul><ul><ul><li>Equivale a: ...
Sintassi:  FORTRAN   vs   C / C++ <ul><li>Controllo di flusso del programma </li></ul>DO I = 1, 10   . . .   ENDDO   IF (I...
Funzioni matematiche <ul><li>In  C++  non esistono funzioni predefinite  </li></ul>int main() {   return 0; } cmath.h   de...
Array <ul><li>Sono supportati gli array di dimensione fissa </li></ul>int main() {   int x [ 10 ] ;   for ( int i = 0; i <...
Esempio con gli arrays <ul><li>Moltiplicazione fra matrici: </li></ul>int main() { const int DIM=3; float m[DIM][DIM], m1[...
Puntatori <ul><li>Riferimento ad una locazione di memoria </li></ul>12 24 0x7b03a928 int main() {   int j = 12; return 0; ...
Puntatori <ul><li>Puntatore nullo </li></ul>#include <iostream> int main() {   int j = 12;   int *ptr = 0;   cout << *ptr ...
Puntatori e  array <ul><li>In  C  gli array sono trattati come puntatori </li></ul>int main() {   float x[5];   int j;   f...
Puntatori: allocazione dinamica <ul><li>Riferimento ad una locazione di memoria </li></ul>#include <iostream> int main() {...
Puntatori: allocazione dinamica <ul><li>Riferimento a più locazioni di memoria </li></ul>#include <iostream> int main() { ...
new  e  delete <ul><li>Gli operatori  new   and  delete   vengono utilizzati per allocazione/deallocazione di memoria dina...
new  e  delete  (2) <ul><li>L’operatore  delete  è usato per restituire una certa area di memoria (allocata con  new ) all...
new  e  delete  (3) <ul><li>Attenzione </li></ul><ul><ul><li>la dimensione dello  heap  non e` infinita </li></ul></ul><ul...
Regole di conversione e  cast <ul><li>In  C++  esistono conversioni esplicite ed implicite.  </li></ul><ul><ul><li>Le conv...
Regole di conversione e  cast  (2) <ul><li>Ogni genere di puntatore può essere convertito in un puntatore generico a void ...
Casting in  ANSI C++ <ul><li>Data la complessità delle operazioni di casting in  C++  nuovi operatori di casting sono stat...
Funzioni <ul><li>In  C++  le funzioni sono caratterizzate da un nome, dal tipo della variabile ritornata e da una lista di...
Funzioni (2) funzione   double cube(double x)   parametri passati   {  return x*x*x; }   “by value” procedura   void pr_sq...
Prototipi delle funzioni <ul><li>Prima di essere usata, una funzione deve essere dichiarata (nel file che la usa) </li></u...
Call-by-Reference <ul><li>L’uso dei  riferimenti  permette ad una funzione di modificare il valore dei suoi argomenti </li...
Funzioni  inline <ul><li>La keyword  inline  suggerisce al compilatore che ogni chiamata alla funzione deve essere convert...
Argomenti di default <ul><li>Ad ogni parametro di una funzione può essere assegnato un  valore di default . Questo permett...
Overloading <ul><li>Funzioni diverse possono avere lo stesso nome </li></ul><ul><li>La funzione che viene chiamata è scelt...
Overloading  (2) <ul><li>La lista dei tipi degli argomenti di una funzione è chiamata  signature </li></ul><ul><li>Il tipo...
L’algoritmo di selezione  <ul><li>L’utente può sempre utilizzare una conversione forzata ( type cast ) per ottenere una co...
Funzioni esterne <ul><li>Si possono chiamare funzioni FORTRAN da C++: </li></ul><ul><li>SUBROUTINE HBOOK1(ID, TITLE, NBIN,...
Parametri del programma <ul><li>Dotando  main()  di una lista di argomenti, è possibile avere accesso ai parametri passati...
Parametri del programma (2) <ul><li>Lanciato con il comando </li></ul><ul><ul><li>prompt> mytest questo e un test </li></u...
Organizzazione dei files <ul><li>Normalmente, le dichiarazioni delle interfacce e le specifiche sono separate dall’impleme...
Organizzazione dei files (2) <ul><ul><li>Files sorgente ( .C , .cxx , .cpp , .cc ) </li></ul></ul><ul><ul><ul><li>contengo...
C++  e  Object Orientation <ul><li>Definizione di nuovi tipi (oltre a  int ,  float ,  double)  come: </li></ul><ul><ul><u...
… C++  e  Object Orientation <ul><li>Object Orientation  implementata in  C++  attraverso il concetto di  classe : </li></...
Una classe  C++ Messaggio Messaggio Messaggio Metodo Metodo Metodo Attributo Attributo  Attributo
Classe  Vector2D <ul><li>Un esempio: un vettore bidimensionale </li></ul>costruttore funzioni o metodi dati o attributi Pu...
Interfaccia e implementazione <ul><li>Gli attributi  privati  non sono accessibili al di fuori della classe </li></ul><ul>...
Costruttori e distruttori <ul><li>Un  costruttore  è un metodo il cui nome è quello della classe a cui appartiene </li></u...
Costruttori e distruttori (2) <ul><li>Un costruttore del tipo che ha come argomento un riferimento ad un oggetto della ste...
Costruttori e distruttori (3) <ul><li>Gli attributi di una classe possono essere inizializzati nel costruttore per mezzo d...
Costruttori e distruttori (4) <ul><li>Il distruttore è un metodo il cui nome è quello della classe a cui appartiene preced...
Costruttori e distruttori (5) <ul><li>I costruttori con un solo parametro sono automaticamente trattati come operatori di ...
Classe  Vector2D <ul><li>Come usare  Vector2D : </li></ul>invoca il constructor #include <iostream.h> #include “Vector2D.h...
Classe  Vector2D <ul><li>…  oppure attraverso un puntatore... </li></ul>Allocazione sullo heap Attenzione! #include <iostr...
Interfaccia e implementazione <ul><li>La struttura interna dei dati  ( x_ ,  y_ )  che rappresentano l’oggetto della class...
<ul><li>Protezione dell’accesso ai dati: </li></ul><ul><li>I metodi di una classe hanno libero accesso ai dati privati e p...
<ul><li>Selettore : metodo che non modifica lo stato (attributi) della classe. E’ dichiarato  const </li></ul><ul><li>Modi...
friend  <ul><li>La keyword  friend  puo` essere usata perche` una funzione (o una classe) abbia libero accesso ai dati pri...
friend (2) <ul><li>friend  (nonostante il nome) e` nemico dell’ incapsulamento   e quindi  dell’Object Orientation </li></...
static <ul><li>Attributi dichiarati  static   in una classe sono condivisi da tutti gli oggetti di quella classe </li></ul...
Un contatore Class MyClass { private: static  int counter; static  void increment_counter() { counter++; } static  void de...
Un singleton <ul><li>Un  singleton   è una classe di cui, ad ogni momento nel corso del programma, non può esistere più di...
Operatori <ul><li>E’ possibile ridefinire  + ,  - ,  * ,  [] ,  ++ ,  == , . . . </li></ul>class Vector2D { public: Vector...
Operatori (2) <ul><li>Esempio: </li></ul>ridefinizione di   << #include <iostream> #include “Vector2D.h” int main() { Vect...
Operatori (3) <ul><li>Esempio: </li></ul>   greco #include <iostream> #include <cmath> #include “Vector3D.h” #include “Ma...
this <ul><li>In una classe è automaticamente definito un attributo particolare:  this </li></ul><ul><ul><li>this  è un pun...
Overloading  di operatori <ul><li>possono esistere funzioni con lo stesso nome ma  con argomenti diversi </li></ul><ul><li...
Overloading  di operatori  (2) <ul><li>Permette di utilizzare tipi definiti dall’utente come se fossero tipi fondamentali ...
Programmazione generica <ul><li>Il C++ fornisce un metodo per creare un  polimorfismo parametrico.  E’ possibile utilizzar...
Sintassi <ul><li>Ogni volta che nella definizione della funzione o della classe appare  identifier  questo viene sostituit...
<ul><li>Parametri interi possono essere inclusi nella dichiarazione del template  </li></ul><ul><li>I parametri di default...
Templates di templates <ul><li>L’argomento di un template puo` essere esso stesso un template </li></ul><ul><li>questo per...
Funzioni template e parametri <ul><li>Una buona parte dei compilatori accetta una sintassi ristretta per quel che riguarda...
Membri statici <ul><li>Per le classi template, gli attributi statici non sono universali ma specifici di ogni istanza </li...
Un esempio: lo stack di interi ... Lo stack vuoto class Contenuto { ... private: Contenuto* next; int  val;  }; class Stac...
Un esempio: lo stack di interi class Stack { public: Stack() {top = 0;} ~Stack() {} void push (  int  i ) { Contenuto* tmp...
Lo stack “templato” template <class  T > class Stack { public: Stack() {top = NULL;} ~Stack() {;} void push (  T  i ) { Co...
La Standard Template Library <ul><li>La libreria standard STL e’ una libreria di classi di contenitori, algoritmi ed itera...
<ul><li>Gli iteratori sono dei puntatori agli elementi di un contenitore e ci permettono di muoverci all’interno di esso: ...
<ul><li>Un contenitore è un oggetto capace di immagazzinare altri oggetti e che possiede metodi per accedere ai suoi eleme...
Sequenze <ul><li>vector </li></ul><ul><ul><li>Tempo costante di inserimento e cancellazione di elementi all’inizio e alla ...
vector <ul><li>Le locazioni di memoria sono contigue </li></ul><ul><ul><li>Accesso casuale, veloce l’accesso agli elementi...
list <ul><li>Simile allo stack, ma consente di muoversi in due direzioni </li></ul><ul><li>Le locazioni di memoria non son...
Contenitori associativi <ul><li>Sono contenitore di coppie  ( key, value )  e possiedono un iteratore bidirezionale </li><...
Algoritmi <ul><li>Gli algoritmi sono delle funzioni globali capaci di agire su contenitori differenti </li></ul><ul><li>So...
Esempio uso sequenze #include <  > #include <algorithm> #include <iostream> int main() { <int> container; int val; for (in...
Esempio uso contenitori associativi #include <map> #include <algorithm> #include <iostream> #include <string> int main() {...
Assegnazione di un metodo ad un messaggio <ul><li>I  metodi pubblici  di una classe costituiscono l’ interfaccia  della cl...
Controllo dei  tipi <ul><li>Controllare i tipi significa verificare che ad un oggetto vengano inviati solo  messaggi  che ...
Typing & Binding Typing Definizione dei messaggi e degli  argomenti Binding Assegnazione di un metodo ad un  messaggio Str...
Esempio: i soldati <ul><li>Tutti i soldati devono capire il messaggio  attacca.  Il messaggio ha conseguenze diverse a sec...
<ul><li>list<Soldato> lista; </li></ul><ul><li>riempiLista(lista); </li></ul><ul><li>Posizione unaPosizione=...; </li></ul...
Polimorfismo <ul><li>Polimorfismo con tipi controllati dal compilatore ( Strong typing & late binding ). </li></ul><ul><li...
Ereditarietà <ul><li>Una classe può essere derivata da una classe esistente usando la sintassi: </li></ul><ul><ul><li>publ...
Ereditarietà (2) <ul><li>Una classe derivata pubblicamente è  a tutti gli effetti un sottotipo della classe base.  </li></...
Ereditarietà (3) <ul><li>La definizione dell’interfaccia (metodi pubblici) della classe base è estremamente importante per...
Classi base astratte <ul><li>Una funzione puramente virtuale è un metodo virtuale non definito. E` dichiarato come:  </li>...
<ul><li>class Soldato { </li></ul><ul><li>virtual void attacca()=0 ; </li></ul><ul><li>}; </li></ul><ul><li>class Arcere :...
Erediarietà multipla <ul><li>L’ereditarietà multipla permette di derivare una classe da due o più classi base. La sintassi...
dynamic_cast <ul><li>dynamic_cast  opera una conversione, se è possibile, fra due tipi. Il puntatore ritornato NON è nullo...
Ereditarietà (4) <ul><li>Una classe derivata estende la classe base e ne eredita tutti i metodi e gli attributi </li></ul>...
Esempio: shape <ul><li>Tutti gli oggetti nella finestra  hanno comportamenti  comuni che  possono essere  considerati in  ...
Cerchi e quadrati Quadrato Cerchio
Cerchio public: Circle (Point2d center, double radius); ~Circle (); void  moveAt (const Point2d & p); void  moveBy (const ...
Cerchio (2) # include “Circle.h” void  Circle :: draw () const  { const int numberOfPoints = 100; float x[numberOfPoints],...
Quadrato  upperCorner loweCorner centerToUpperCorner _ class  Square   { public: Square (const Point2d&, const Point2d&,  ...
Codice Applicativo (Client) Come gestire cerchi  e quadrati insieme? Costruisce un vettore di puntatori a cerchi, crea ogg...
Polimorfismo Tutte le  Shape s hanno la stessa interfaccia: draw, pick, move, fillColor... , ma ogni  sottotipo  diverso p...
Interfaccia astratta Interfaccia di metodi  puramente virtuali class  Shape  { public: Shape () { } virtual   ~Shape () { ...
Ereditarietà e riuso del codice Non si possono chiamare metodi virtuali in costruttori e distruttori  (troppo presto, trop...
Attenzione alle generalizzazioni... <ul><li>Attenzione : scegliere le relazioni di ereditarietà può essere non banale. </l...
Ereditarietà multipla <ul><li>Una classe può ereditare da più classi  </li></ul>class  DrawableObj { public: virtual  void...
Strategie di sviluppo di un progetto <ul><li>Requisiti :  cosa l’utente vuole </li></ul><ul><li>Analisi :  la visione dell...
Modello  a cascata Analisi Disegno Produzione Testing Requisiti
Modello  evoluzionario Requisiti Analisi Disegno Produzione Testing
Confronto fra i modelli di sviluppo <ul><li>A cascata </li></ul><ul><li>Processo lineare (si torna al passo precedente sol...
Requisiti <ul><li>Definizione delle richieste da parte dell’utente del programma (o di una sua parte) sul sistema </li></u...
Analisi <ul><li>Comprensione e  razionalizzazione  delle richieste dell’utente </li></ul><ul><li>Costruzione di un modello...
Disegno Definizione delle  interfacce Definizione di oggetti  e classi Definizione degli stati  e dell’implementazione Def...
Disegno (2) <ul><li>Dopo ogni ciclo bisogna analizzare i rischi, la stabilità del disegno e la complessità delle classi </...
Codifica <ul><li>C’è poco da dire…  </li></ul><ul><li>Non sopravvalutate questa fase: </li></ul>
Testing <ul><li>Debugging :   è ovvio… il codice non deve dare errori. </li></ul><ul><li>Use cases :  specificano il compo...
Metodi di sviluppo del software <ul><li>Un  metodo   comprende: </li></ul><ul><li>Una  notazione </li></ul><ul><ul><li>mez...
Metodi Object Oriented <ul><ul><li>Booch Method by  Grady Booch </li></ul></ul><ul><ul><li>OMT  by  Jim Rumbaugh </li></ul...
UML per l’analisi e il disegno <ul><li>Class Diagrams :  aspetto statico del sistema. Classi con attributi e metodi e rela...
Concetti delle classi rivisitati <ul><li>Relazioni tra oggetti </li></ul><ul><li>Decomposizione funzionale all’interno di ...
Rappresentazione delle classi operatori attibuti pubblico protetto privato Nome + metodo(arg) # metodo(arg) -  metodo(arg)...
Rappresentazione di una classe C++ in UML class  Nome   { private: Tipo1   variabile1 ; Tipo2   variabile2 ; Tipo3   varia...
Attributi e metodi Notazione di  Rational Rose Publico ( + ) Privato ( - ) Protetto ( # )
Principali relazioni fra classi <ul><li>associazione </li></ul><ul><li>aggregazione  by reference </li></ul><ul><ul><li>(i...
Aggregazione (contenimento) <ul><li>By reference  (condivisa) </li></ul><ul><li>un  autista  guida più  automobili </li></...
Cardinalità e direzionalità <ul><li>Il punto non  conosce </li></ul><ul><li>i poligoni </li></ul><ul><li>Il poligono è cos...
Dipendenza <ul><li>Non c’è nessuna associazione </li></ul><ul><li>C’è comunque relazione di uso </li></ul><ul><li>Il CD no...
Generalizzazione (ereditarietà) Ereditariet à virtuale!
Class Diagram di “Shape”
Class Diagram
Class Diagram
Object Sequence Diagram
Object Collaboration Diagram
CRC Classi, Responsabilità, Collaborazioni C D E F B A x y z s f q p w
Assegnare Responsabilità <ul><li>Identificare i protagonisti </li></ul><ul><li>Analizzare il  ruolo  dei vari oggetti </li...
Collaborazione tra classi <ul><li>Le responsabilità vanno suddivise tra i vari oggetti del sistema </li></ul><ul><li>non d...
Identificare Relazioni <ul><li>Cercare  collaborazioni </li></ul><ul><li>Cercare  aggregazioni </li></ul><ul><li>Cercare  ...
Relazioni <ul><li>Logiche </li></ul><ul><li>Generalizazione:  Is-a </li></ul><ul><li>Aggregazione:  Has </li></ul><ul><li>...
Avere o essere? <ul><li>Uno dei punti critici è distinguere se il rapporto fra due oggetti è del tipo  avere  o  essere : ...
Principio di Liskov <ul><li>Gli oggetti  figli  possono essere usati ovunque l’oggetto  genitore  è richiesto </li></ul><u...
Composizione  by value  o  by refrence <ul><li>In C++ la scelta fra aggregazione  by value  o  by refrence  può  seguire q...
Approccio  Outside-in <ul><li>Il corretto approccio è quello di guardare il sistema dall’esterno. </li></ul><ul><li>Identi...
CRC Workshop <ul><li>Metodo per la definizione si una architettura  bilanciata </li></ul><ul><li>Ogni partecipante svolge ...
Regole per il CRC workshop <ul><li>Tentate di rifuutare le responsabilità </li></ul><ul><ul><li>Dovrei? (Non sono io che l...
Design Patterns <ul><li>Sono  elementi di software OO riutilizzabile </li></ul><ul><li>Piccoli insiemi di classi che colla...
Factory I client possono richiedere la creazione di un prodotto senza dipendervi La   Factory   dipende dai prodotti concr...
Proxy Una richiesta da un client a un server, può  essere mediata dal   Proxy , che può compiere  anche altre operazioni (...
Composite Il client può trattare componenti e compositi usando la stessa interfaccia. La composizione può essere ricursiva...
Gruppo di Shapes Il gruppo di shapes è il  Composite La shape è  il  Component Le shapes concrete (Circle, Square, ecc...)...
Codice del modello composite #include “ Shape .h” class  Circle : public  Shape  { public: Circle ( Point2D c, double r ):...
Codice del modello composite #include “ Shape .h” class  GroupofShapes  : public  Shape  { public: typedef vector< Shape  ...
Strategy Il pattern  Strategy  permette di scegliere l’algoritmo da eseguire a run-time. Nuovi algoritmi possono essere in...
Observer Lo stato dell’ Observer  dipende dallo stato del  Subject . Il  Subject  notifica a tutti gli  Observer  registra...
Appendice: strighe C-style <ul><li>Le variabili carattere sono gestite come array di  char  (un char contiene un solo cara...
Appendice: la classe  string <ul><li>Per semplificare la gestione delle stringhe è stata creata la classe  string </li></u...
Confronto stringhe C-style e  string <ul><li>#include<iostream> </li></ul><ul><li>#include< cstring > </li></ul><ul><li>in...
Appendice:operazioni di I/O <ul><li>Si utilizza la libreria  iostream  </li></ul><ul><ul><li>Gli operatori di  stream   >>...
Overloading degli operatori di I/O <ul><li>Gli operatori  <<  e  >>  possono essere ridefiniti per consentire operazioni d...
Appendice: I/O con files <ul><li>E’ possibile definire altre unità di I/O </li></ul><ul><ul><li>Si utilizza la libreria  f...
Appendice: I/O in memoria <ul><li>E’ possibile definire unità di I/O in memoria (non legate a files) </li></ul><ul><ul><li...
Appendice: Manipolatori di I/O <ul><li>Modificano il comportamento di una  stream . </li></ul>boolalpha : true e false rap...
Appendice: Manipolatori di I/O (2) <ul><li>I seguenti manipolatori richiedono: </li></ul><ul><ul><li>#include <iomanip> </...
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Riepilogo Java C/C++
Upcoming SlideShare
Loading in...5
×

Riepilogo Java C/C++

3,739

Published on

Short introduction to most popular programming languages

Published in: Education
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,739
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
79
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • Struttura di un programma C, paradigma procedurale, Case Sensitive
  • Struttura
  • A pointer in C is the address of something The unary operator `&amp;&apos; is used to produce the address of an object Pointers to pointers Pointers to functions
  • Vediamo ora nel dettaglio come scrivere delle classi che risolvono un problema. Ad esempio il classico problema di visualizzare forme geometriche e di manipolarle con una GUI. Abbiamo bisogno di varie forme geometriche: cerchi, rettangoli, esagoni, che si possano creare, distruggere, disegnare, muovere, ruotare etc. Non pretendiamo qui di presentare un’implementazione completa, ma di dare solo un’idea di come si possa ottenere un certo tipo di comportamento utilizzando la programmazione ad oggetti. Nel nostro esempio assumiamo l’esistenza di una libreria grafica di base non OO e una libreria di classi di geometria con punti, vettori in due dimensioni..
  • Qui vediamo la struttura essenziale di una classe e molti degli elementi sintattici di base: la dichiarazione di una classe con membri pubblici e privati costruttore, distruttore metodi inline metodi definiti in un’altra file attributi di tipo “built-in ” e di classe Color sarebbe un enumerator ma non si vede la dichiarazione.. come si istanzia un oggetto e come si invoca un suo metodo un loop “for” l’uso di operatori vari in un piccolo algoritmo l’uso di oggetti temporanei (che il compilatore può ottimizzare)
  • Repetita juvant!?!
  • Una semplice applicazione delle classi precedenti. Più dettagli sulla sintassi già vitsa in precedenza. Si vede l’allocazione sull’heap (ma non esplicitamente che new ritorna un puntatore) Viene anche introdotto un vettore STL e la sua sintassi di base (ripresa poi in dettaglio in seguito).
  • Rullo di tamburi…..
  • La chiave di volta della programmazione orientata ad oggetti: l&apos;ereditarietà di un’interfaccia astratta per ottenere una gestione polimorfica degli oggetti. In “puro” OO la classe di base deve contenere solo metodi puramente virtuali e nessun attributo. Questo e’ ovviamente sempre possibile farlo. Solo pigrizia e una tendenza a cercare un’ottimizzazione precoce ci fanno implementare classi di base che contengono anche parte dell’implementazione comune.
  • Il punto più controverso dell’OO: l&apos;ereditarietà pubblica dell’implementazione. In questo caso i puristi richiederebbero: Class CCShape : public virtual Shape {..}; Class Rectangle : private CCShape, public Shape {…}; ma per un corso introduttivo mi sembra veramente troppo!!! Posiamo l’attenzione su una delle tante trappole del C++: l’invocazione di metodi virtuali nel costruttore e distruttore della classe base.
  • The notation is the most apparent part of a method and in object orientation has been for a while the subject of almost religious wars. The process specifies the practices to be followed to develop a software product ensuring that it conforms to the specifications (user requirements) and it is free of defects. Processes can be very rigorous and formal (like for military applications) or almost not existing like in HEP. Here we will concentrate only on the technical aspects of a software process leaving the managerial aspects to some future discussion. A process for us will be a collection of suggested practices to succeed in the Analysis and Design of an Object Oriented Software System.
  • Object Oriented Design makes use also of many well known techniques which have been used successfully for many years such as entity-relationship models, functional decomposition and, why not, structural programming
  • The “Shape” example (used in the C++ course) in UML notation. We can see: Abstract classes (recognizable from the name in italics ), Arrows indicating inheritance, The notation used for aggregation with roles and cardinality, In some classes are shown the methods (lower part) and the attributes (higher part) with the symbols for private, protected and public. UML, compared with Booch, is less C++ oriented and thus many other properties, relevant to C++, can not be shown.
  • Another UML diagram: this time for the Trajectory surface package. We can directly compare the diagram with the C++ to better understand the semantics of the various symbols.
  • Class diagrams should not necessarily show all class and relationship in the software with all their details. They are intended to document particular aspects of the model architecture and design and therefore should contain only the details relevant to the part the designer wants to stress. This diagram is intended to describe the Plane class and onlly the details of the relationships among Plane and the classes which collaborate with it are shown
  • Sequence Diagrams are a powerful tool to describe the dynamic behavior of the model. Usually a Sequence Diagram is associated to a “scenario” Each participating object is represented by a vertical line Horizontal arrows shows messages send from one object to another. The sequence of the messages, an therefore the development of the scenario, is easily seen reading the diagram from top to bottom.
  • Object Collaboration Diagrams convey exactly the same information as Sequence Diagrams and there is indeed a one to one correspondence among the components of the two diagrams. The only difference is the focus: The Sequence diagram focuses on the temporal sequence of the messages while the OCD more on the collaboration among the various objects. My opinion is that using either one or the other is just a manner of personal taste although I find the sequence diagrams more clear and better matching the textual presentation of a scenario.
  • Codice della componente e della foglia. Si noti la “forward declaration” necessaria per implementare il puntatore di ritorno al genitore. In DaqLeaf introduciamo anche “explicit” per evitare la conversione implicita da float a DaqLeaf. E chiaro che il modello non e’ completo e l’implementazione si presta a molte critiche, ma questo e’ solo un esempio...
  • Qui vediamo dichiarazione e definizione del composito. Power() e’ inline per pura pigrizia. Tanto per cambiare faccio vedere il loop usando un while… si notino i typedef per “semplificare” la notazione seguente (in realtà sono utile per “esportare” pubblicamente begin() ed end(). Ma noi il visitor qui non lo facciamo e quindi non ne parliamo…)
  • Tutti le variabili e i metodi di una classe sono utilizzabili dai membri della classe. Per controllare l’accesso esistono 4 modificatori: Private – accessibili solo alla classe Protected – accessibili alla classe, alle sottoclassi e alle classi del package Public – accessibili a chi accede alla classe, quindi alle sottoclassi Senza modificatori sono accessibili esclusivamente dalle classi dello stesso package Dentro ad un pacchetto protected e la mancanza di modificatori si equivalgono, al di fuori del pacchetto il modificatore protected indica che la visibilità e’ legatta alla struttura gerarchica delle classi
  • Collections è una classe di metodi statici di modifica e adattamento dei vari oggetti collection. Le diverse implementazioni di map differiscono per l’ordinamento che restituiscono e per l’implementazione dalla quale dipende la complessità.
  • Si esegue il blocco_1. Qualora si verifichi un’eccezione del tipo elencata nella clausola catch, il controllo viene passato al blocco_2. L’identificatore dell’eccezione che si è verificata può essere utilizzata nel blocco_2 per invocare alcuni metodi che descrivono l’eccezione; ad esempio: getMessage(), toString() o printStackTrace().
  • Riepilogo Java C/C++

    1. 1. C/C++/JAVA Refresh rapido
    2. 2. Cominciamo col C
    3. 3. Struttura di un programma C /* This is a comment */ // This is a one-line comment # include <stdio.h> /* includes header files */ main() /* Must have a main function. First function { printf (&quot;Hello World!&quot;); /* stdio functions */ }
    4. 4. Tipi <ul><li>int - stores integers (-32767 to +32768) </li></ul><ul><li>unsigned int – 0 to 65535 </li></ul><ul><li>char – holds 1 byte of data (-127 to 128) </li></ul><ul><li>unsigned char – holds 1 byte (0 to +255) </li></ul><ul><li>long – usually double int (signed) </li></ul><ul><li>unsigned long – positive double int </li></ul><ul><li>float – floating point variable </li></ul><ul><li>double – twice of a floating point variable </li></ul>
    5. 5. printf <ul><li>printf (“%d”,i); </li></ul><ul><li>Usual variable type Display </li></ul><ul><ul><li>%c char single character </li></ul></ul><ul><ul><li>%d (%i) int signed integer </li></ul></ul><ul><ul><li>%e (%E) float or double exponential format </li></ul></ul><ul><ul><li>%f float or double signed decimal </li></ul></ul><ul><ul><li>%g (%G) float or double use %f or %e as required </li></ul></ul><ul><ul><li>%o int unsigned octal value </li></ul></ul><ul><ul><li>%p pointer address stored in pointer </li></ul></ul><ul><ul><li>%s array of char sequence of characters </li></ul></ul><ul><ul><li>%u int unsigned decimal </li></ul></ul><ul><ul><li>%x (%X) int unsigned hex value </li></ul></ul>
    6. 6. Operatori <ul><li>+ addition </li></ul><ul><li>- subtraction </li></ul><ul><li>* multiplication </li></ul><ul><li>/ division </li></ul><ul><li>% mod or remainder (e.g., 2%3 is 2), also called 'modulo' </li></ul><ul><li><< left-shift (e.g., i<<j is i shifted to the left by j bits) </li></ul><ul><li>>> right-shift </li></ul><ul><li>& bitwise AND </li></ul><ul><li>| bitwise OR </li></ul><ul><li>^ bitwise exclusive-OR </li></ul><ul><li>&& logical AND (returns 1 if both operands are non-zero; else 0) </li></ul><ul><li>|| logical OR (returns 1 if either operand is non-zero; else 0) </li></ul><ul><li>< less than (e.g., i<j returns 1 if i is less than j) </li></ul><ul><li>> greater than </li></ul><ul><li><= less than or equal </li></ul><ul><li>>= greater than or equal </li></ul><ul><li>== equals </li></ul><ul><li>!= does not equal </li></ul>
    7. 7. Incremento e decremento <ul><li>++ Increment operator </li></ul><ul><li>-- Decrement Operator </li></ul><ul><li>k++ or k-- (Post-increment/decrement) </li></ul><ul><li>k = 5; </li></ul><ul><li>x = k++; // sets x to 5, then increments k to 6 </li></ul><ul><li>++k or --k (Pre-increment/decrement) </li></ul><ul><li>k = 5; </li></ul><ul><li>x = ++k; // increments k to 6 and then sets x to the </li></ul><ul><li> // resulting value, i.e., to 6 </li></ul>
    8. 8. Funzioni e prototipi #include <stdio.h> int add1(int); void main() { int x; x=5; x=add1(x); printf(&quot;%d“,x); } int add1(int i) { int y; y=i+1; return (y); }
    9. 9. Operatori sui bit <ul><li><< left shift </li></ul><ul><li>>> right shift </li></ul><ul><li>| bitwise OR </li></ul><ul><li>& bitwise AND </li></ul><ul><li>^ bitwise XOR </li></ul><ul><li>~ bitwise NOT </li></ul>
    10. 10. Tabella di “verità”
    11. 11. Esempio shifting
    12. 12. Condizionali <ul><li>if (expression) statement </li></ul><ul><li>else statement </li></ul><ul><li>while (expression) statement </li></ul><ul><li>do statement while (expression) </li></ul><ul><li>for( initialization; expression; increment ) </li></ul><ul><li>statement </li></ul><ul><li>switch (expression) </li></ul><ul><li>{ case item1: </li></ul><ul><li>statement1; </li></ul><ul><li>break; </li></ul><ul><li>default: </li></ul><ul><li>statement; </li></ul><ul><li>break; </li></ul><ul><li>} </li></ul>
    13. 13. Array int x[10]; double y[15]; x[10]=10; char c[15];
    14. 14. Puntatori!!! int a, *b, c; // b is a pointer b = &a; // Store in b the address of a c = *b; // Store in c the value at // address b (i.e., a)
    15. 15. Puntatori a caratteri e array char *y; char x[100]; y = &x[0]; y = x; // Does the same as the line above *(y+1) gives x[1] *(y+i) gives x[i]
    16. 16. Ancora puntatori int x,y; int *p1,*p2; 1000 1004 1008 1012 x y p1 p2
    17. 17. Ancora puntatori(2) x=-42; y=163 1000 1004 1008 1012 x y p1 p2 -42 163
    18. 18. Ancora puntatori(3) p1=&x; p2=&y; 1000 1004 1008 1012 x y p1 p2 -42 163 1000 1004
    19. 19. Ancora puntatori(4) *p1=17; 1000 1004 1008 1012 x y p1 p2 17 163 1000 1004
    20. 20. Ancora puntatori(5) p1=p2; 1000 1004 1008 1012 x y p1 p2 17 163 1000 1004
    21. 21. Ancora puntatori(6) <ul><li>Passaggio di parametri per riferimento </li></ul><ul><li>Aritmetica dei puntatori </li></ul><ul><li>malloc </li></ul><ul><li>free </li></ul>
    22. 22. Strutture struct emprec { char name[25]; int age; int pay; }; struct emprec employee; employee.age=32;
    23. 23. C++ extend C <ul><li>Le classi, con funzioni virtuali ed ereditarietà multipla </li></ul><ul><li>Le eccezioni </li></ul><ul><li>Le variabili di riferimento </li></ul><ul><li>I namespace </li></ul><ul><li>I template di classe </li></ul><ul><li>I template di funzione </li></ul><ul><li>La libreria di ingresso/uscita </li></ul><ul><li>La libreria per gestire stringhe </li></ul><ul><li>La libreria per gestire contenitori </li></ul><ul><li>… </li></ul>
    24. 24. Introduzione al C++ e alla programmazione ad oggetti
    25. 25. Introduzione <ul><li>Le due componenti principali dei programmi: </li></ul><ul><ul><li>Algoritmi : l’insieme delle istruzioni che svolgono un particolare compito </li></ul></ul><ul><ul><li>Dati : ciò su cui gli algoritmi agiscono per produrre una soluzione unica </li></ul></ul><ul><li>La relazione fra queste componenti definisce il paradigma di programmazione </li></ul><ul><ul><li>Programmazione procedurale : problemi modellati dagli algoritmi. Dati immagazzinati in aree comuni o passate agli algoritmi </li></ul></ul><ul><ul><li>Programmazione ad oggetti : problemi modellati dalle relazioni fra tipi di dati astratti ( ADT, Abstract Data Types ), chiamati generalmente oggetti </li></ul></ul>
    26. 26. Il rapporto Dato-Algoritmo Linguaggio Bits Bits macchina Programmazione Dati Algoritmi Livello di astrazione Assemblers Symbolic Op-code Words Compilatori Variables & Statements Types Linguaggi Data Subroutines strutturati structures Ada (Modula) Abstract Packages Data Types (Modules) Object Oriented Objects Objects
    27. 27. Cos’è un oggetto ? <ul><li>Né più né meno di quello che potreste trovare scritto in un vocabolario… </li></ul><ul><ul><li>Un oggetto è un’entità che si possa immaginare dotata di determinate caratteristiche e funzionalità . </li></ul></ul><ul><li>Lo stato di un oggetto è rappresentato da dati che ne descrivono le caratteristiche in un certo istante </li></ul><ul><li>Le funzionalità di un oggetto sono le operazioni che può svolgere quando glie lo si richiede (cioè quando riceve un messaggio ) </li></ul><ul><li>Nella nostra vita quotidiana siamo molto più abituati a ragionare per oggetti che non in modo strutturato! </li></ul>
    28. 28. Un esempio...
    29. 29. Soldato
    30. 30. … cos’è un oggetto : <ul><li>Un insieme di dati e funzioni: </li></ul>Funzione Funzione Funzione Codice funzione Codice funzione Codice funzione Dato Dato Dato
    31. 31. Incapsulazione <ul><li>Netta divisione fra interfaccia e implementazione </li></ul><ul><li>Da fuori si vede solo l’interfaccia che definisce i messaggi accettati dall’oggetto </li></ul><ul><li>I dettagli dell’implementazione (dati e codice delle funzioni) sono invisibili dall’esterno </li></ul><ul><li>Ogni oggetto ha in se tutto ciò che gli serve per rispondere alle chiamate (o deve sapere a chi chiedere…) </li></ul><ul><li>Il confinamento di informazioni e funzionalità in oggetti permette livelli maggiori di astrazione e semplifica la gestione di sistemi complessi. </li></ul>
    32. 32. Approccio OO <ul><li>Sono le strutture di dati che svolgono le azioni, non le subroutines </li></ul><ul><li>Il lavoro è svolto dal server , non dal client </li></ul><ul><li>“ Cos’ è?” “Com’ è fatto?” </li></ul><ul><li> Data Oriented </li></ul><ul><li>“ Cosa può fare per me?” </li></ul><ul><li> Object Oriented </li></ul>
    33. 33. Perché programmare per oggetti ? <ul><li>Programmare per oggetti non velocizza l’esecuzione dei programmi... </li></ul><ul><li>Programmare per oggetti non ottimizza l’uso della memoria... </li></ul><ul><li>E allora perchè programmare per oggetti ? </li></ul><ul><li>Programmare per oggetti facilita la progettazione e il mantenimento di sistemi software molto complessi! </li></ul>
    34. 34. Caratteristiche del software non mantenibile <ul><li>Rigidità </li></ul><ul><ul><li>non può essere cambiato con faciltà </li></ul></ul><ul><ul><li>non può essere stimato l’impatto di una modifica </li></ul></ul><ul><li>Fragilità </li></ul><ul><ul><li>una modifica singola causa una cascata di modifiche successive </li></ul></ul><ul><ul><li>i bachi sorgono in aree concettualmente separate dalle aree dove sono avvenute le modifiche </li></ul></ul><ul><li>Non riusabilità </li></ul><ul><ul><li>esistono molte interdipendenze, quindi non è possibile estrarre parti che potrebbero essere comuni </li></ul></ul>
    35. 35. Programmazione ad oggetti <ul><li>La programmazione ad oggetti, attraverso l’ incapsulazione , consente di: </li></ul><ul><ul><li>ridurre la dipendenza del codice di alto livello dalla rappresentazione dei dati </li></ul></ul><ul><ul><li>riutilizzare del codice di alto livello </li></ul></ul><ul><ul><li>sviluppare moduli indipendenti l’uno dall’altro </li></ul></ul><ul><ul><li>avere codice utente che dipende dalle interfacce ma non dall’implementazione </li></ul></ul>
    36. 36. C++ e Object Orientation <ul><li>Il C++ può essere usato come linguaggio procedurale o per programmazione ad oggetti </li></ul><ul><li>Object Orientation implementata attraverso il concetto di classe </li></ul><ul><li>Prima di affrontare il problema della programmazione OO con C++ dobbiamo: </li></ul><ul><ul><li>capire dove la programmazione procedurale fallisce </li></ul></ul><ul><ul><li>affrontare la sintassi del C++ </li></ul></ul>
    37. 37. Programmazione procedurale <ul><li>Esempio: cinematica relativistica </li></ul>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) Idea: perché non usare una function?
    38. 38. Evoluzione del codice <ul><li>Se cambia il formato del common block? </li></ul>COMMON /MYDATA/ P1(4), P2(4), P3(4), P4(4) COMMON /MYDATA/ P(4), E(4), THETA(4), PHI(4) <ul><li>Bisogna cambiare la funzione (gli argomenti sono diversi) </li></ul>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)) FUNCTION COSTHETA1(THETA1, THETA2, + PHI1, PHI2) COSTHETA1 = SIN(THETA1)*SIN(THETA2) * + COS(PHI1-PHI2) + COS(THETA1)*COS(THETA2) END <ul><li>...e il codice! </li></ul>
    39. 39. Il concetto di dipendenza <ul><li>Nell’esempio precedente il codice di analisi (“ alto livello ”) dipende dai dettagli della struttura dati (“ basso livello ”). </li></ul>COMMON /MYDATA/ P1(4), P2(4), + P3(4), P4(4) COSTHETA12 = COSTHETA(P1, P2) COSTHETA13 = COSTHETA(P1, P3) COSTHETA14 = COSTHETA(P1, P4 ) FUNCTION COSTHETA(P1, P2) REAL P1(4), P2(4) COSTHETA = (P1(1)*P2(1) + P1(2)*P2(2) + + P1(3)*P2(3))/... END COSTHETA dipende dalla struttura dei dati P1 e P2 Il codice di analisi dipende dalla struttura del common block MYDATA
    40. 40. OO riduce le dipendenze! <ul><li>Riduce la dipendenza del codice di alto livello dalla rappresentazione dei dati Permette il riutilizzo del codice di alto livello </li></ul><ul><li>Nasconde i dettagli di implementazione Supporta tipi di dati astratti ( vedere seguito  ... ) </li></ul>
    41. 41. Sintassi: FORTRAN vs C / C++ <ul><li>Struttura del programma </li></ul>PROGRAM TEST C esempio di programma ... END int main() { // esempio di programma ... return 0; // fine } INTEGER I INTEGER*4 J REAL X REAL*8 D int i; long j; float x; double d; In C/C++ non è necessario un particolare formato il codice spazi... Il C/C++ è case sensitive Istruzioni separate da “;”
    42. 42. Il main program <ul><li>Ogni programma in C++ , per essere eseguibile, deve contenere una funzione main() da cui l’esecuzione comincerà </li></ul><ul><li>main() deve avere un tipo (decidere quale è compito del programmatore). Regola generale è che main() ritorni un intero, a significare il return code dell’applicazione </li></ul>int main() { // il piu` semplice programma in C++ return 0; }
    43. 43. I/O: lettura e scrittura <ul><li>Non esiste nel C++ nativo. Si usa: iostream </li></ul><ul><ul><li>Gli operatori << e >> sono usati per definire la direzione del flusso </li></ul></ul><ul><ul><li>cin , cout e cerr rappresentano lo standard input, output e error del programma </li></ul></ul>#include <iostream> int main() { return 0; } direttiva al preprocessore end of line #include <iostream> cout << “Hello, world !” << endl;
    44. 44. Commenti <ul><li>Esistono due tipi di commento in C++ </li></ul><ul><ul><li>inline: </li></ul></ul><ul><ul><li>multiline (come in C ): </li></ul></ul><ul><ul><li>I due tipi possono essere usati indifferentemente, ma si raccomanda di usare l’inline (più semplice e meno ambiguo) </li></ul></ul>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 */
    45. 45. Tipi predefiniti in C++ <ul><li>Sono definiti una serie di tipi numerici che permettono di rappresentare numeri interi, reali e caratteri </li></ul><ul><ul><li>char (un solo byte) viene normalmente usato per rappresentare interi inferiori a 256 </li></ul></ul><ul><ul><li>stringhe e numeri complessi sono implementati come tipi derivati </li></ul></ul>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
    46. 46. Tipi predefiniti in C++ (2) 123 123 0x123 interi costanti , decimale, ottale, esadecimale 123l 123u interi, long, unsigned ‘ A’ ‘1’ ‘ ’ 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 Esempi di costanti ‘ a’ alert ‘ backslash ‘ ’ backspace ‘ ’ carriage return ‘ ”’ double quote ‘ f’ form feed ‘ ’ tab ‘ ’ newline ‘ ’ carattere nullo ‘ ’’ single quote ‘ v’ vertical tab ‘ 101’ 101 ottale, ‘A’ ‘ x041’ esadecimale, ‘A’ Costanti carattere “” stringa nulla (‘’) “ nome” ‘n’ ‘o’ ‘m’ ‘e’ ‘’ “ una ”stringa”” stampa: una “stringa” “ una stringa un alla fine della linea su piu` linee” per continuare la stringa Stringhe costanti
    47. 47. Tipi predefiniti in C++ (3) char [1] int [1] bool short [1] long [1] float double long double 8 16 16 16 32 32 64 64 8 32 32 16 32 32 64 128 8 32 32 16 64 32 64 128 OS 16 bit OS 32 bit OS 64 bit [1] Può essere unsigned
    48. 48. Identificatori <ul><li>Un identificatore è composto da uno o più caratteri </li></ul><ul><li>Il primo carattere deve essere una lettera o un underscore. Caratteri successivi possono essere lettere, numeri o underscore </li></ul><ul><li>Non c’ è un limite in lunghezza, anche se alcuni sistemi si limitano a considerare i primi 31 caratteri </li></ul><ul><li>Gli identificatori che iniziano con un doppio underscore o con un underscore e una lettera maiuscola sono riservati ad usi di sistema </li></ul><ul><li>C++ e` case sensitive! </li></ul>const int Ntries; double _attempts; double 2A; // errore!
    49. 49. Keywords <ul><li>Alcuni identificatori sono esplicitamente riservati al sistema (hanno un preciso significato in C++ ) e non possono essere usati </li></ul>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
    50. 50. const <ul><li>La keyword const viene utilizzata per dichiarare un oggetto costante </li></ul><ul><li>In C le costanti vengono normalmente dichiarate usando il preprocessore </li></ul><ul><ul><li>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 ) </li></ul></ul>#define N 100 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
    51. 51. Dichiarazione <ul><li>Le dichiarazioni associano un significato ad un identificatore </li></ul><ul><li>in C++ ogni cosa deve essere dichiarata per poter essere usata </li></ul><ul><li>Una dichiarazione è spesso anche una definizione. Per variabili semplici questo consiste nell’associare un valore alla variabile al momento della dichiarazione </li></ul>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 }
    52. 52. typedef <ul><li>L’istruzione typedef viene utilizzata per creare un alias per tipi esistenti </li></ul><ul><li>typedef NON può essere usato per implementare nuovi tipi, ma solo per definire un alias </li></ul>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
    53. 53. Enumeratori <ul><li>In C++ sono supportati tipi definiti dall’utente </li></ul>enum Color { red, green, blue }; Color screenColor = blue; Color windorColor = red; int n = blue; // valido Color c = 1; // errore enum Seme { cuori, picche, quadri, fiori };
    54. 54. Scope <ul><li>Le variabili possono essere dichiarate e definite quasi ovunque in un programma in C++ </li></ul><ul><li>la visibilità ( scope ) di una variabile dipende da dove la variabile è stata dichiarata </li></ul>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! … }
    55. 55. Scope (2) <ul><li>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! </li></ul>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; ... } Scope resolution operator
    56. 56. namespace <ul><li>Funzioni e variabili definite a global scope sono visibili dappertutto in un programma in C++ </li></ul><ul><ul><li>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 </li></ul></ul>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 }
    57. 57. namespace (2) <ul><li>Per utilizzare variabili e funzioni racchiuse in un namespace si può: </li></ul><ul><ul><li>o accedere all’intero namespace </li></ul></ul><ul><ul><li>oppure accedere alla singola variabile o funzione </li></ul></ul><ul><ul><li>oppure dichiarare la singola funzione </li></ul></ul>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);
    58. 58. Operatori -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 Espressioni Aritmetiche Commento 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; 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. bit-wise significato < 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. Operatori relazionali Fortran
    59. 59. Espressioni di assegnazione <ul><li>Le espressioni di assegnazione sono valutate da destra a sinistra </li></ul><ul><li>Le assegnazioni multiple sono permesse </li></ul><ul><li>alcuni operatori di assegnazione combinano assegnazione ed altri operatori </li></ul><ul><li>Assegnazioni possono essere fatte all’interno di espressioni aritmetiche </li></ul>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;
    60. 60. Statements 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 Statement C++ commenti
    61. 61. Statements (2) 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 Statement C++ commenti
    62. 62. Statement composti <ul><li>Uno statement composto in è costituito da una serie di statement contenuti fra parentesi graffe </li></ul><ul><li>Usato normalmente per raggruppare istruzioni in un blocco ( if , for , while , do-while , etc.) </li></ul><ul><li>Il corpo di una funzione è sempre uno statement composto </li></ul><ul><li>La dichiarazione di una variabile può avvenire ovunque all’interno di un blocco, in questo caso lo scope della variabile sarà il blocco stesso </li></ul><ul><li>Ovunque si possa usare uno statement singolo si può definire un blocco </li></ul>
    63. 63. if <ul><li>Attenzione all’uso di = e == </li></ul><ul><li>Nel dubbio, usare sempre un blocco… </li></ul><ul><li>Attenzione agli else! </li></ul>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;
    64. 64. while e do-while <ul><li>La forma generale di un while è : </li></ul><ul><li>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 </li></ul><ul><li>la sintassi di un do-while è invece: </li></ul><ul><li>Lo statement verrà quindi eseguito almeno una volta </li></ul>while ( condizione ) statement; do statement; while (condizione);
    65. 65. break e continue <ul><li>break e continue sono utilizzati nei loop per saltare alla fine del loop o fuori dal loop stesso </li></ul><ul><li>break e continue possono solamente essere utilizzati nel corpo di un for , while o do-while . break e` anche usato negli switch </li></ul>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
    66. 66. switch <ul><li>Lo switch è uno statement condizionale che generalizza lo if-else </li></ul><ul><li>lo statement è generalmente composito e consiste di diversi case e, opzionalmente, di un default </li></ul>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; }
    67. 67. switch (2) <ul><li>Non si puo` dichiarare una variabile in uno dei case </li></ul><ul><li>… ma si puo` creare una variabile locale definendo uno statement composto... </li></ul>switch (k) { case 0: int j=0; // Illegale! Errore! . . . case 1: . . . } switch (k) { case 0: { int j=0; // OK, questo compila . . . } case 1: . . . }
    68. 68. L’operatore ? <ul><li>L’operatore ? e` l’unico esempio di operatore ternario in C++ </li></ul><ul><ul><li>Equivale a: </li></ul></ul><ul><ul><li>Esempio: </li></ul></ul>expr1 ? expr2 : expr3; double max(double a, double b) { double max = (a>b) ? a : b; return max; } if(expr1) expr2; else expr3;
    69. 69. Sintassi: FORTRAN vs C / C++ <ul><li>Controllo di flusso del programma </li></ul>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 ) { . . . }
    70. 70. Funzioni matematiche <ul><li>In C++ non esistono funzioni predefinite </li></ul>int main() { return 0; } cmath.h definisce sin , cos , ... { 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; <ul><li>Potenze: pow(b,exp) (non si può usare ** ) </li></ul>
    71. 71. Array <ul><li>Sono supportati gli array di dimensione fissa </li></ul>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; } <ul><li>L’indice va da 0 a n-1 . Usare un indice maggiore di n-1 può causare un crash . </li></ul>int x[] = { 1, 2, 3, 4 }; char[] t = { ‘C’ , ‘i’ , ‘a’ , ‘o’ , ‘’ }; char[] s = “Ciao” ; int m[2][3] = { {11, 12, 13}, {21, 22, 23} }; <ul><li>Inizializzazione: </li></ul>
    72. 72. Esempio con gli arrays <ul><li>Moltiplicazione fra matrici: </li></ul>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; }
    73. 73. Puntatori <ul><li>Riferimento ad una locazione di memoria </li></ul>12 24 0x7b03a928 int main() { int j = 12; return 0; } int * ptr = & j; #include <iostream> cout << * ptr << endl; j = 24; cout << * ptr << endl; cout << ptr << endl; indirizzo di memoria j 12 ptr 24
    74. 74. Puntatori <ul><li>Puntatore nullo </li></ul>#include <iostream> int main() { int j = 12; int *ptr = 0; cout << *ptr << endl; // crash ! return 0; } Segmentation violation (core dumped) j 12 ptr
    75. 75. Puntatori e array <ul><li>In C gli array sono trattati come puntatori </li></ul>int main() { float x[5]; int j; for (j = 0; j < 5; j++) x[j] = 0; float *ptr = x; *ptr = 1.5; // x[0] = 1.5 *(ptr+1) = 2.5; // x[1] = 2.5 *(ptr+3) = 3.5; // x[3] = 3.5 } x X[0] 1.5 X[1] X[2] X[3] X[4] 2.5 0.0 3.5 0.0 X+1 X+3
    76. 76. Puntatori: allocazione dinamica <ul><li>Riferimento ad una locazione di memoria </li></ul>#include <iostream> int main() { int *ptr = new int; *ptr = 12; cout << *ptr << endl; delete ptr; return 0; } <ul><li>Attenzione: </li></ul><ul><ul><li>Non usare delete fa accumulare locazioni di memoria inutilizzate ( memory leak ) </li></ul></ul><ul><ul><li>Utilizzare puntatori prima del new o dopo il delete causa il crash del programma </li></ul></ul>12 ptr
    77. 77. Puntatori: allocazione dinamica <ul><li>Riferimento a più locazioni di memoria </li></ul>#include <iostream> int main() { int *ptr = new int[3]; ptr[0] = 10; ptr[1] = 11; ptr[2] = 12 delete [] ptr; return 0; } 10 ptr 11 12
    78. 78. new e delete <ul><li>Gli operatori new and delete vengono utilizzati per allocazione/deallocazione di memoria dinamica </li></ul><ul><ul><li>la memoria dinamica ( heap ), è un’area di memoria libera provvista dal sistema per quegli oggetti la cui durata di vita è sotto il controllo del programmatore </li></ul></ul><ul><li>new riserva la quantità necessaria di memoria richiesta e ritorna l’indirizzo di quest’area </li></ul>int *i=new int; alloca un intero, returna il puntatore char *c=new char [ 100 ] ; alloca un array (stringa) di 100 caratteri int *i=new int ( 99 ) ; alloca un intero e lo inizializza a 99 char *c=new char ( ‘c’ ) ; alloca un carattere inizializzato a c int *j=new int[n][4]; alloca un array di puntatori ad intero operatore new commenti
    79. 79. new e delete (2) <ul><li>L’operatore delete è usato per restituire una certa area di memoria (allocata con new ) allo heap </li></ul><ul><li>Ogni oggetto allocato con new deve essere distrutto con delete se non viene piu` utilizzato, altrimenti l’area di memoria che esso occupata non potra` piu` essere ri-allocata ( memory leak ) </li></ul><ul><li>L’argomento di delete è tipicamente un puntatore inizializzato preventivamente con new </li></ul>delete ptr; distrugge un puntatore ad un oggetto delete p[i]; distrugge l’oggetto p[i] delete [] p; distrugge ogni oggetto di tipo p operatore delete commenti
    80. 80. new e delete (3) <ul><li>Attenzione </li></ul><ul><ul><li>la dimensione dello heap non e` infinita </li></ul></ul><ul><ul><li>l’allocazione con new può fallire, nel qual caso new restituisce un puntatore nullo o suscita un’eccezione. Nel caso di allocazione di memoria importante bisogna verificare che l’operazione abbia avuto successo prima di usare il puntatore </li></ul></ul><ul><ul><li>ogni oggetto creato con new deve essere distrutto con delete , ogni oggetto creato con new [] deve essere distrutto con delete [] , queste forme NON sono intercambiabili </li></ul></ul>
    81. 81. Regole di conversione e cast <ul><li>In C++ esistono conversioni esplicite ed implicite. </li></ul><ul><ul><li>Le conversioni implicite (e.g. int  float ) nelle espressioni aritmetiche, nel passare i parametri ad una funzione o nel ritornare un valore da una funzione rendono il meccanismo di conversione molto conveniente ma anche potenzialmente pericoloso (errori a run time) </li></ul></ul><ul><li>char, short e bool vengono promossi ad int </li></ul><ul><li>Tipi interi che non possono essere rappresentati con un int vengono promossi a unsigned </li></ul><ul><li>In una espressione di tipo misto, gli operandi di ordine inferiore vengono promossi all’ordine superiore secondo la gerarchia: </li></ul><ul><ul><ul><li>int<unsigned<long<unsigned long<float<double<long double </li></ul></ul></ul><ul><li>bool e` un tipo intero, con true che viene promosso a 1 e false a 0 </li></ul>Conversioni implicite
    82. 82. Regole di conversione e cast (2) <ul><li>Ogni genere di puntatore può essere convertito in un puntatore generico a void </li></ul><ul><li>Al contrario di quanto avviene in C , un puntatore generico non è compatibile con un puntatore di tipo arbitrario ma richiede un cast esplicito </li></ul><ul><li>Ogni puntatore puo` essere inizializzato a 0 senza bisogno di un cast esplicito. </li></ul><ul><li>In C++ usare 0 e non NULL per i puntatori! </li></ul>char *ch; void *generic_p; . . . generic_p=ch; // OK, char* va in void* ch=generic_p; // OK in C, illegale in C++ ch=(char *)generic_p; // OK, C e C++ arcaico
    83. 83. Casting in ANSI C++ <ul><li>Data la complessità delle operazioni di casting in C++ nuovi operatori di casting sono stati aggiunti a quelli già esistenti in C </li></ul><ul><li>Esiste anche un dynamic_cast , utilizzato per riconoscere il tipo di un oggetto a run-time (RTTI) </li></ul>x=(float) i; cast in C++ - notazione C x=float(i); cast in C++, notazione funzionale x=static_cast<float>(i); ANSI C++ - raccomandato i=reinterpret_cast<int>(&x) ANSI C++, non portabile e system dependent func(const_cast<int>(c_var)) dove C_var e` una variabile dichiarata const. Usato per eliminare la “ const-ness” per chiamare func Cast commenti
    84. 84. Funzioni <ul><li>In C++ le funzioni sono caratterizzate da un nome, dal tipo della variabile ritornata e da una lista di parametri (opzionali) </li></ul><ul><li>La lista dei parametri (anche se vuota) deve essere esplicitata </li></ul><ul><li>Il valore ritornato deve essere compatibile, a meno di conversione esplicita, con il tipo della funzione </li></ul>Valore di ritorno double max( double a, double b) { return (a>b) ? a : b; } Tipo ritornato Parametri Corpo della funzione
    85. 85. Funzioni (2) funzione double cube(double x) parametri passati { return x*x*x; } “by value” procedura void pr_square(int i) subroutine, non si { cout<<i*I<<endl; } usa return senza argomenti void hello () puo` anche essere { cout<<“Hello”<<endl; } void hello(void) argomenti passati void swap(int& i,int& j) i e j hanno i loro per riferimento { int t=i; i=j; j=t; } valori scambiati variabile int scanf(const char, … ) chiamata con un qualsiasi numero di argomenti inline inline double cube(int x) codice inline argomenti di int power(int i, int n=2) il 2do argomento default puo` essere tralasciato Tipo di dichiarazione C++ commenti
    86. 86. Prototipi delle funzioni <ul><li>Prima di essere usata, una funzione deve essere dichiarata (nel file che la usa) </li></ul><ul><li>I prototipi rendono le funzioni in C++ “ type safe ”, nel senso che i valori reali degli argomenti vengono all’occorrenza convertiti nei tipi formali specificati dal prototipo </li></ul>Prototipo di max (normalmente in max.h ) #include <iostream> double max(double, double); int main() { double m = max(1, 3); cout<<“Il massimo e` “<<m<<endl; return 0; } main.cc double max (double a, double b) { return (a>b) ? a : b; } max.cc
    87. 87. Call-by-Reference <ul><li>L’uso dei riferimenti permette ad una funzione di modificare il valore dei suoi argomenti </li></ul><ul><ul><li>Per ragioni di efficenza, oggetti di grandi dimensioni (in termini di memoria) vengono normalmente passati “ by reference ”. </li></ul></ul><ul><ul><li>Per evitare che possano essere modificati dalla funzione, il riferimento viene definito const </li></ul></ul>bool greater(int& i, int& j) { // se i>j scambia i e j if (i>j) { int temp=i; i=j; j=temp; return true; } else return false; } Argomenti passati “by reference” possono essere modificati dalla funzione stessa
    88. 88. Funzioni inline <ul><li>La keyword inline suggerisce al compilatore che ogni chiamata alla funzione deve essere convertita in codice eseguibile (la definizione della funzione viene sostituita alla chiamata dovunque nell codice) </li></ul><ul><li>Le funzioni inline vengono usate per ragioni di efficienza e (per non sovraccaricare il compilatore) devono essere semplici </li></ul><ul><li>Il compilatore può decidere autonomamente (per esempio se la funzione è troppo lunga) di ignorare la direttiva inline </li></ul>
    89. 89. Argomenti di default <ul><li>Ad ogni parametro di una funzione può essere assegnato un valore di default . Questo permette di chiamare la funzione tralasciando quei parametri il cui valore di default risulta appropriato </li></ul><ul><li>Solo ai parametri più a destra nella calling sequence può essere dato un default. </li></ul>Argomento di default int pow(int , int); int main() { int r=3; int a1=pow(3,3); // a1=27 int a2=pow(3); // a2=9 return 0; } main.cc int pow (int a, int k=2) { if (k==2) return a*a; else return a*pow(a, k-1); } pow.cc
    90. 90. Overloading <ul><li>Funzioni diverse possono avere lo stesso nome </li></ul><ul><li>La funzione che viene chiamata è scelta dal compilatore in base al tipo di ritorno ed al numero e tipo degli argomenti </li></ul>double average_array(const int a[], int size) { int sum=0; for (int i=0;i<size;i++) sum+=a[i]; return double( sum ) /size; } double average_array(const double a[], int size) { double sum=0; for (int i=0;i<size;i++) sum+=a[i]; return sum/size; } average_array.cc
    91. 91. Overloading (2) <ul><li>La lista dei tipi degli argomenti di una funzione è chiamata signature </li></ul><ul><li>Il tipo ritornato dalla funzione non fa parte della signature, mentre il numero e l’ordine degli argomenti è cruciale </li></ul>void print(int i=0) {. . .} // (1) void print(int i, double x) {. . .} // (2) void print(double y, int i) {. . .} // (3) . . . print(‘A’); // ‘A’ e` convertito a int, chiama (1) print(str[]); // errore! Non e` possibile una conversione print(15,9); // errore! Ambiguita` fra (2) e (3) print(15,9.); // OK, chiama (2) print(); // OK, chiama (1) con il default
    92. 92. L’algoritmo di selezione <ul><li>L’utente può sempre utilizzare una conversione forzata ( type cast ) per ottenere una corrispondenza </li></ul><ul><li>Il compilatore segnala tutti i casi in cui esiste ambiguità </li></ul>Ricerca della corrispondenza esatta Promozioni standard degli argomenti Conversioni standard dei tipi Conversioni definite dall’utente Corrispondenza con l’ellipsi (…) int  long int  float traccia  int I tentativi del compilatore
    93. 93. Funzioni esterne <ul><li>Si possono chiamare funzioni FORTRAN da C++: </li></ul><ul><li>SUBROUTINE HBOOK1(ID, TITLE, NBIN, MIN, MAX, OPT) </li></ul><ul><li>SUBROUTINE HFILL(ID,X, Y, WEIGHT) </li></ul><ul><li>extern “C” void hbook1_(int&, char*, int&, float&, float&, float&, int ); </li></ul><ul><li>extern “C” void hfill_(int&, float&, float&, float&); </li></ul><ul><li>... </li></ul><ul><li>hbook1_( 100 , title, ……) // BUS ERROR!!! (il FORTRAN passa </li></ul><ul><li>// sempre “by-reference” </li></ul><ul><li>int id=100; </li></ul><ul><li>hbook1_(id, title, ……) // OK! </li></ul>
    94. 94. Parametri del programma <ul><li>Dotando main() di una lista di argomenti, è possibile avere accesso ai parametri passati dalla command line: </li></ul><ul><li>argc è il numero di parametri passati dalla command line (sempre almeno 1, il nome del programma) mentre il vettore di stringhe argv contiene ogni singolo parametro </li></ul>#include <iostream.h> int main(int argc, char *argv[]) { cout<<“ argc e`: “<<argc<<endl; cout<<“ il nome dell’eseguibile e` “<<*argv<<endl; for (int i=1; i<argc; i++) cout<<“Argomento #”<<i<<“ = “<<*(argv+i)<<endl; return 0; }
    95. 95. Parametri del programma (2) <ul><li>Lanciato con il comando </li></ul><ul><ul><li>prompt> mytest questo e un test </li></ul></ul><ul><li>il programma produrra` il seguente output: </li></ul><ul><ul><li>argc e` : 5 </li></ul></ul><ul><ul><li>il nome dell’eseguibile e`/user/andrea/myprogram </li></ul></ul><ul><ul><li>Argomento #1 = questo </li></ul></ul><ul><ul><li>Argomento #2 = e </li></ul></ul><ul><ul><li>Argomento #3 = un </li></ul></ul><ul><ul><li>Argomento #4 = test </li></ul></ul>
    96. 96. Organizzazione dei files <ul><li>Normalmente, le dichiarazioni delle interfacce e le specifiche sono separate dall’implementazione </li></ul><ul><ul><li>header files ( .h o .hh ) </li></ul></ul><ul><ul><ul><li>inclusi nei file sorgente utilizzando direttive del precompilatore </li></ul></ul></ul><ul><ul><ul><li>non contengono codice eseguibile (con l’eccezione delle definizioni delle funzioni inline) </li></ul></ul></ul><ul><ul><ul><li>non devono essere inclusi piu` di una volta, per evitare problemi con il linker </li></ul></ul></ul>#include <iostream.h> #ifndef MyHeader_H #define MyHeader_H // dichiarazioni … .. #endif
    97. 97. Organizzazione dei files (2) <ul><ul><li>Files sorgente ( .C , .cxx , .cpp , .cc ) </li></ul></ul><ul><ul><ul><li>contengono l’implementazione di funzioni e metodi </li></ul></ul></ul><ul><ul><ul><li>codice eseguibile </li></ul></ul></ul><ul><ul><ul><li>includono gli header files utilizzando le direttive del preprocessore </li></ul></ul></ul><ul><ul><ul><li>vengono compilati </li></ul></ul></ul><ul><ul><li>Funzioni inline ( .icc ) </li></ul></ul><ul><ul><ul><li>La definizione di una funzione inline deve essere visibile là dove viene usata. </li></ul></ul></ul><ul><ul><ul><li>Normalmente implementate negli header files o in files separati (con estensione .icc ) che devono essere inclusi nel files sorgente che ne facciano uso </li></ul></ul></ul>
    98. 98. C++ e Object Orientation <ul><li>Definizione di nuovi tipi (oltre a int , float , double) come: </li></ul><ul><ul><ul><li>numeri complessi, </li></ul></ul></ul><ul><ul><ul><li>vettori, </li></ul></ul></ul><ul><ul><ul><li>matrici, . . . </li></ul></ul></ul><ul><li>ma anche: </li></ul><ul><ul><ul><li>traiettorie, </li></ul></ul></ul><ul><ul><ul><li>superfici, </li></ul></ul></ul><ul><ul><ul><li>elementi di apparati sperimentali,... </li></ul></ul></ul><ul><li>Gli oggetti permettono di modellare una problema che rappresenti la realtà </li></ul>
    99. 99. … C++ e Object Orientation <ul><li>Object Orientation implementata in C++ attraverso il concetto di classe : </li></ul><ul><li>I dati privati (o attributi ) di una classe definiscono lo stato dell’oggetto </li></ul><ul><li>Le funzioni (o metodi ) di una classe implementano la risposta ai messaggi </li></ul>
    100. 100. Una classe C++ Messaggio Messaggio Messaggio Metodo Metodo Metodo Attributo Attributo Attributo
    101. 101. Classe Vector2D <ul><li>Un esempio: un vettore bidimensionale </li></ul>costruttore funzioni o metodi dati o attributi Punto e virgola! class Vector2D { public: Vector2D(double x, double y); double x(); double y(); double r(); double phi(); private: double x_; double y_ } ; Vector2D.h #include “Vector2D.h” Vector2D::Vector2D(double x, double y): x_ (x), y_ (y) { } double Vector2D::x() { return x_ ; } double Vector2D::r() { return sqrt( x_ * x_ + y_ * y_ ); } ... Vector2D.cc
    102. 102. Interfaccia e implementazione <ul><li>Gli attributi privati non sono accessibili al di fuori della classe </li></ul><ul><li>I metodi pubblici sono gli unici visibili </li></ul>#include “Vector.h” Vector2D::Vector2D(double x, double y) : x_(x), y_(y) {} double Vector2D::x() { return x_; } double Vector2D::r() { return sqrt(x_*x_ + y_*y_); } Vector2D.cc class Vector2D { public : Vector2D(double x, double y); double x(); double y(); double r(); double phi(); private : double x_; double y_; }; Vector2D.h
    103. 103. Costruttori e distruttori <ul><li>Un costruttore è un metodo il cui nome è quello della classe a cui appartiene </li></ul><ul><li>Lo scopo di un costruttore è quello di costruire oggetti del tipo della classe. Questo implica l’inizializzazione degli attributi e, frequentemente, allocazione di memoria dallo heap </li></ul><ul><li>Un costruttore la cui lista di argomenti è vuota o composta di argomenti di default viene normalmente chiamato costruttore di default </li></ul>Vector2D::Vector2D() {. . . .} // costruttore di default #include “Vector2D.h” . . . Vector2D v; // oggetto costruito con il // costruttore di default
    104. 104. Costruttori e distruttori (2) <ul><li>Un costruttore del tipo che ha come argomento un riferimento ad un oggetto della stessa classe viene chiamato copy constructor </li></ul><ul><li>Il copy constructor viene normalmente utilizzato: </li></ul><ul><ul><li>quando un oggetto è inizializzato per assegnazione </li></ul></ul><ul><ul><li>quando un oggetto è passato come argomento ad una funzione </li></ul></ul><ul><ul><li>quando un oggetto è ritornato da una funzione </li></ul></ul><ul><li>Se non viene fornito esplicitamente dall’utente, il compilatore ne genererà uno automaticamente </li></ul>Vector2D::Vector2D(const Vector2D& v) {. . . .} Vector2D v(v1); // dove v1 e` di tipo Vector2D
    105. 105. Costruttori e distruttori (3) <ul><li>Gli attributi di una classe possono essere inizializzati nel costruttore per mezzo di una lista di inizializzatori, che precede il corpo della funzione </li></ul><ul><li>Quando uno degli attributi è esso stesso una classe, il costruttore appropriato viene scelto sulla base dei parametri forniti nell’inizializzazione </li></ul><ul><li>E` obbligatorio inizializzare gli attributi (non statici) che siano o riferimenti o const </li></ul>Vector2D::Vector2D(double x, double y) : x_(x), y_(y) { . . . }
    106. 106. Costruttori e distruttori (4) <ul><li>Il distruttore è un metodo il cui nome è quello della classe a cui appartiene preceduto da una tilde ( ~ ) </li></ul><ul><li>Il distruttore viene chiamato automaticamente quando un oggetto sta per essere distrutto (sia perchè delete è stato invocato sia perchè l’oggetto è finito fuori scope </li></ul><ul><li>Il compito del distruttore è di assicurarsi che l’oggetto per cui è invocato verrà distrutto senza conseguenze. In particolare, se memoria è stata allocata nel costruttore, il distruttore dovrà assicurarsi di restituirla allo heap </li></ul>Vector2D::~Vector2D() {} // vuoto, in questo caso
    107. 107. Costruttori e distruttori (5) <ul><li>I costruttori con un solo parametro sono automaticamente trattati come operatori di conversione </li></ul><ul><li>Per evitare la conversione si puo` usare explicit </li></ul>Vector2D::Vector2D(int i) {. . .} // costruisce un vettore a partire da un intero, ma puo` // essere usato per convertire un intero in vettore v=Vector2D(i); explicit Vector2D(int); // solo costruttore
    108. 108. Classe Vector2D <ul><li>Come usare Vector2D : </li></ul>invoca il constructor #include <iostream.h> #include “Vector2D.h” int main() { Vector2D v(1, 1); cout << “ v = (“ << v.x() << “,” << v.y() << “)” << endl; cout << “ r = “ << v.r(); cout << “ phi = “ << v.phi() << endl; return 0; } main.cc v = (1, 1) r = 1.4141 phi = 0.7854 Output:
    109. 109. Classe Vector2D <ul><li>… oppure attraverso un puntatore... </li></ul>Allocazione sullo heap Attenzione! #include <iostream.h> #include “Vector2D.h” int main() { Vector2D *v = new Vector2D(1, 1); cout << “ v = (“ << v -> x() << “,” << v -> y() << “)” << endl; cout << “ r = “ << v -> r(); cout << “ phi = “ << v -> phi() << endl; delete v; return 0; } main.cc v = (1, 1) r = 1.4141 phi = 0.7854 Output:
    110. 110. Interfaccia e implementazione <ul><li>La struttura interna dei dati ( x_ , y_ ) che rappresentano l’oggetto della classe Vector2D sono nascosti ( private ) agli utilizzatori della classe. </li></ul><ul><li>Gli utilizzatori non dipendono dalla struttura interna dei dati (come lo erano gli utilizzatori dei common blocks Fortran) </li></ul><ul><li>Se la struttura interna cambia (es.: r_ , phi_ ), il codice che usa Vector2D non deve essere modificato. </li></ul>
    111. 111. <ul><li>Protezione dell’accesso ai dati: </li></ul><ul><li>I metodi di una classe hanno libero accesso ai dati privati e protetti di quella classe </li></ul>Classe Vector2D #include <iostream> #include “Vector2D .h” int main() { Vector2D v(1, 1); cout << “ V = (“ << v.x_ << “,” // << v.y_ << “,” << endl; // non compila ! cout << “ r = “ << v.r(); cout << “ phi = “ << v.phi() << endl; } main.cc
    112. 112. <ul><li>Selettore : metodo che non modifica lo stato (attributi) della classe. E’ dichiarato const </li></ul><ul><li>Modificatore: metodo che può modificare lo stato della classe </li></ul>Selettori e modificatori modificatore Selettori ( const ) #include “Vector2D.h” void Vector2D::scale(double s) { x_ *= s; y_ *= s; } Vector2D.cc class Vector2D { public: Vector2D(double x, double y); double x() const ; double y() const ; double r() const ; double phi() const ; void scale(double s); private : double x_, y_; }; Vector2D.h #include “Vector2D.h” int main() { const Vector2D v(1, 0); double r = v.r() // OK v.scale( 1.1 ); // errore! } main.cc
    113. 113. friend <ul><li>La keyword friend puo` essere usata perche` una funzione (o una classe) abbia libero accesso ai dati privati di un’altra classe </li></ul>class A { . . . friend int aFunc(); friend void C::f(int); }; class B { … friend class C; }; class C { . . . };
    114. 114. friend (2) <ul><li>friend (nonostante il nome) e` nemico dell’ incapsulamento e quindi dell’Object Orientation </li></ul><ul><li>Un uso eccessivo di friend è quasi sempre sintomo di un cattivo disegno </li></ul><ul><li>Esistono anche situazioni in cui un friend può essere accettabile </li></ul><ul><ul><li>Overloading di operatori binari </li></ul></ul><ul><ul><li>Considerazioni di efficienza </li></ul></ul><ul><ul><li>Relazione speciale fra due classi </li></ul></ul>“ A programmer must confer with an architect before making friend declarations”
    115. 115. static <ul><li>Attributi dichiarati static in una classe sono condivisi da tutti gli oggetti di quella classe </li></ul><ul><li>Metodi dichiarati static non possono accedere ad attributo non statici della classe </li></ul><ul><li>Attiributi statici possono essere usati e modificati soltanto da metodi statici </li></ul><ul><li>Nonostante l’utilizzo di static sembri imporre condizioni troppo restrittive, esso risulta utile nell’implementazione di: </li></ul><ul><ul><li>contatori </li></ul></ul><ul><ul><li>singleton (vedi oltre) </li></ul></ul>
    116. 116. Un contatore Class MyClass { private: static int counter; static void increment_counter() { counter++; } static void decrement_counter() { counter--; } public: MyClass() { increment_counter(); } ~MyClass() { decrement_counter(); } static int HowMany() { return counter; } }; #include <iostream.h> #include “MyClass.h” int MyClass::counter=0; int main() { MyClass a,b,c; MyClass *p=new MyClass; cout<<“ How many? “<< MyClass::HowMany() <<endl; delete p; cout<<“ and now? “<< a.HowMany() <<endl; return 0; } Un membro statico deve essere inizializzato una e una sola volta nel codice eseguibile Un metodo statico puo` essere invocato cosi`... … o cosi`...
    117. 117. Un singleton <ul><li>Un singleton è una classe di cui, ad ogni momento nel corso del programma, non può esistere più di una copia (istanza) </li></ul>class aSingleton { private: static aSingleton *ptr; aSingleton () {} public: static aSingleton *GetPointer(){ if (ptr==0) ptr=new aSingleton; return ptr; } }; #include “aSingleton.h” aSingleton *aSingleton::ptr=0; int main() { aSingleton *mySing= aSingleton::GetPointer(); . . . Return 0; } Pattern utile per l’implementazione di classi “manager” di cui deve esistere una sola istanza Attenzione a non farlo diventare l’equivalente di un common block!
    118. 118. Operatori <ul><li>E’ possibile ridefinire + , - , * , [] , ++ , == , . . . </li></ul>class Vector2D { public: Vector2D(double x, double y); double x() const; double y() const; double r() const; double phi() const; private: double x_; double y_; }; Vector2D operator+(const Vector2D& v1, const Vector2D& v2); Vector2D operator-(const Vector2D& v1, const Vector2D& v2); Vector2D.h Vector2D operator+(const Vector2D& v1, const Vector2D& v2) { return Vector2D(v1.x() + v2.x(), v1.y() + v2.y()); } Vector2D operator-(const Vector2D& v1, const Vector2D& v2) { return Vector2D(v1.x() - v2.x(), v1.y() - v2.y()); } Vector2D.cc
    119. 119. Operatori (2) <ul><li>Esempio: </li></ul>ridefinizione di << #include <iostream> #include “Vector2D.h” int main() { Vector2D v1(1, 0), v2(0, 1); Vector2D v; v = v1 + v2; cout << “ v = “ << v << endl; cout << “ r = “ << v.r(); cout << “ phi = “ << v.phi() << endl; } main.cc v = (1, 1) r = 1.4141 theta = 0.7854 Output : v.operator=( operator+(v1, v2) ); Sintassi alternativa (!#@!?) :
    120. 120. Operatori (3) <ul><li>Esempio: </li></ul> greco #include <iostream> #include <cmath> #include “Vector3D.h” #include “Matrix.h” // matrice 3x3 int main() { Vector3D v1(1, 1, 0); double phi = M_PI /3; double c = cos(phi), s = sin(phi); Matrix m(1, 0, 0, 0, c, s, 0, -s, c); Vector3D u = m * v; } main.cc
    121. 121. this <ul><li>In una classe è automaticamente definito un attributo particolare: this </li></ul><ul><ul><li>this è un puntatore all’oggetto di cui fa parte </li></ul></ul><ul><ul><li>E’ particolarmente utile quando si definisce un operatore di assegnazione ( = ): </li></ul></ul>class Vector2D { public: Vector2D& operator=(const Vector2D& ); // ... private: double x_, y_; }; Vector2D.h Vector2D& operator=(const Vector2D& v){ x_=v.x(); y_=v.y(); return *this; } Vector2D.cc #include “Vector2D.h” int main() { Vector2D null(0, 0); Vector2D a, b; a=b=null; } main.cc L’operatore = ritorna una referenza a se stesso. Permette assegnazioni multiple
    122. 122. Overloading di operatori <ul><li>possono esistere funzioni con lo stesso nome ma con argomenti diversi </li></ul><ul><li>Non bisogna pero` esagerare! Ogni operatore deve avere un significato ben preciso, per ragioni di chiarezza. </li></ul>class Vector2D { public: // ... private: double x_, y_; }; Vector2D operator*(const Vector2D &, double); double operator*(const Vector2D&, const Vector2D&); Vector2D.h Vector2D operator*(const Vector2D&, double s) { return Vector2D( v.x() * s, v.y() * s); } double operator*(const Vector2D& v1, const Vector2D& v2) { return ( v1.x() * v2.x() + v1.y() * v2.y() ); } Vector2D.cc
    123. 123. Overloading di operatori (2) <ul><li>Permette di utilizzare tipi definiti dall’utente come se fossero tipi fondamentali </li></ul><ul><li>La cardinalita `, l’ associativita ` e la precedenza di un operatore non possono essere modificati </li></ul><ul><li>Operatori unari sono implementati come metodi senza argomenti (l’oggetto è l’argomento implicito) </li></ul><ul><li>Operatori binari possono essere implementati come metodi con un argomento (il primo argomento, implicito, è l’oggetto il cui operatore agisce) o come funzioni friend a due argomenti. </li></ul>
    124. 124. Programmazione generica <ul><li>Il C++ fornisce un metodo per creare un polimorfismo parametrico. E’ possibile utilizzare lo stesso codice per tipi differenti: il tipo della variabile diventa un parametro </li></ul>template<class T> T max( T p1, T p2 ) { if ( p1 < p2 ) return p2; else return p1; } int main() { Vector v1,v2; cout << max<int>(10,20) << endl; cout << max<float>(2.6,1.0) << endl; cout << max<Vector>(v1,v2) << endl;} Main.cc Per il tipo T deve essere definito l’operatore <
    125. 125. Sintassi <ul><li>Ogni volta che nella definizione della funzione o della classe appare identifier questo viene sostituito dal compilatore con il tipo fornito nella chiamata. </li></ul><ul><li>La dichiarazione e l’implementazione del template devono essere nello stesso file ove il template viene utilizzato </li></ul>template < class identifier > function definition template < class identifier > class definition typename
    126. 126. <ul><li>Parametri interi possono essere inclusi nella dichiarazione del template </li></ul><ul><li>I parametri di default possono essere tralasciati </li></ul>Parametri templati template <typename T=int , int n=10> class array_n { ... private: T items[n]; // n istanziato esplicitamente }; array_n<complex, 1000> w; // w array di complessi
    127. 127. Templates di templates <ul><li>L’argomento di un template puo` essere esso stesso un template </li></ul><ul><li>questo permette la creazione e l’utilizzo di meta-templates (templates istanziati con templates) molto sofisticati </li></ul><ul><li>la Standard Template Library fa uso di questa possibilita` </li></ul>template <class T1, template <class T2> class T3 >
    128. 128. Funzioni template e parametri <ul><li>Una buona parte dei compilatori accetta una sintassi ristretta per quel che riguarda le funzioni template. ANSI/C++ prevede invece che anche parametri numerici possano essere inclusi nella definizione del template </li></ul>template <class T> void swap(T& x, T& y){ T temp; temp=x; x=y; y=temp; } template <class T, int n=10> T aFunc(){ T temp[n]; . . . } OK per ogni compilatore ANSI/C++, ma la maggior parte dei compilatori lo rifiuta
    129. 129. Membri statici <ul><li>Per le classi template, gli attributi statici non sono universali ma specifici di ogni istanza </li></ul><ul><li>Le variabili statiche MyClass<int>::counter e MyClass<double>::counter sono diverse </li></ul>template <class T> class MyClass { public: static int counter; ... }; MyClass<int> a,b; MyClass<double> c;
    130. 130. Un esempio: lo stack di interi ... Lo stack vuoto class Contenuto { ... private: Contenuto* next; int val; }; class Stack { ... private: Contenuto* top; }; val Contenuto next val Contenuto next val Contenuto next Stack top Stack top
    131. 131. Un esempio: lo stack di interi class Stack { public: Stack() {top = 0;} ~Stack() {} void push ( int i ) { Contenuto* tmp = new Contenuto(i,top ); top = tmp; } int pop () { int ret = top->getVal(); Contenuto* tmp = top; top = top->getNext(); delete tmp; return ret; } private: Contenuto* top; }; class Contenuto { public: Contenuto ( int i, Contenuto* ptn ) { val=i; next=ptn; } int getVal (){ return val; } Contenuto* getNext() {return next;} private: Contenuto* next; int val; }; int main() { Stack s; s.push ( 10 ); s.push ( 20 ); cout << s.pop() << “ - “ << s.pop; return 0; }; User code >> 10 - 20 Output
    132. 132. Lo stack “templato” template <class T > class Stack { public: Stack() {top = NULL;} ~Stack() {;} void push ( T i ) { Contenuto<T>* tmp = new Contenuto<T> (i,top ); top = tmp; } T pop () { T ret = top->getVal(); Contenuto<T>* tmp = top; top = top->getNext(); delete tmp; return ret; } private: Contenuto<T>* top; }; template <class T > class Contenuto { public: Contenuto ( T i, Contenuto* ptn ) { val = i; next = ptn; } T getVal (){ return val; } Contenuto* getNext() {return next;} private: Contenuto* next; T val; }; int main() { Stack<int> s; s.push ( 10 ); s.push ( 20 ); Stack<double> s1; Stack<Shape *> s2; cout << s.pop() << “ “ << s.pop; return 0;}; User code
    133. 133. La Standard Template Library <ul><li>La libreria standard STL e’ una libreria di classi di contenitori, algoritmi ed iteratori. </li></ul><ul><li>STL e’ una libreria generica: tutti i suoi componenti sono parametrizzati mediante l’utilizzo dei template </li></ul>vettori, liste, mappe, …. find, replace, reverse, sort, …. Iteratori Contenitori puntatori intelligenti Algoritmi
    134. 134. <ul><li>Gli iteratori sono dei puntatori agli elementi di un contenitore e ci permettono di muoverci all’interno di esso: </li></ul><ul><ul><li>Iteratori monodirezionali: Permettono di accedere all’elemento successivo o al precedente </li></ul></ul><ul><ul><li>Iteratori bidirezionali : Permettono di accedere sia all’elemento successivo che al precedente </li></ul></ul><ul><ul><li>Iteratori ad accesso casuale : Permettono di accedere ad un qualunque elemento del contenitore </li></ul></ul>Iteratori (puntatori intelligenti)
    135. 135. <ul><li>Un contenitore è un oggetto capace di immagazzinare altri oggetti e che possiede metodi per accedere ai suoi elementi. </li></ul><ul><ul><li>Ogni contenitore ha un iteratore associato che permette di muoversi tra gli elementi contenuti </li></ul></ul><ul><ul><li>Una sequenza è un contenitore di lunghezza variabile i cui elementi sono organizzati linearmente. E’ possibile aggiungere e rimuovere elementi </li></ul></ul><ul><ul><li>Un contenitore associativo è una sequenza che permette un efficiente accesso ai suoi elementi basato su una chiave. </li></ul></ul>Contenitori
    136. 136. Sequenze <ul><li>vector </li></ul><ul><ul><li>Tempo costante di inserimento e cancellazione di elementi all’inizio e alla fine del vettore. </li></ul></ul><ul><ul><li>Tempo lineare con il numero di elementi per inserimento e cancellazione di elementi all’interno del vettore </li></ul></ul><ul><ul><li>Iteratore ad accesso casuale </li></ul></ul><ul><li>list </li></ul><ul><ul><li>Tempo costante di inserimento e cancellazione di elementi in ogni punto della lista </li></ul></ul><ul><ul><li>Iteratore bidirezionale </li></ul></ul>
    137. 137. vector <ul><li>Le locazioni di memoria sono contigue </li></ul><ul><ul><li>Accesso casuale, veloce l’accesso agli elementi, lenti inserimento ed estrazione </li></ul></ul>1 2 ... 9 ++ begin() end() p p p p p 0 push_back() p
    138. 138. list <ul><li>Simile allo stack, ma consente di muoversi in due direzioni </li></ul><ul><li>Le locazioni di memoria non sono contigue </li></ul><ul><ul><li>Lenta la ricerca, veloci inserimento ed estrazione </li></ul></ul>... list top bottom val nodo next prev val nodo next prev val nodo next prev
    139. 139. Contenitori associativi <ul><li>Sono contenitore di coppie ( key, value ) e possiedono un iteratore bidirezionale </li></ul><ul><li>map </li></ul><ul><ul><li>Viene richiesto l’operatore < per la chiave </li></ul></ul><ul><ul><li>Gli elementi sono ordinati secondo la chiave </li></ul></ul>
    140. 140. Algoritmi <ul><li>Gli algoritmi sono delle funzioni globali capaci di agire su contenitori differenti </li></ul><ul><li>Sono incluse operazioni di ordinamento (sort, merge, min, max...), di ricerca (find, count, equal...), di trasformazione (transform, replace, fill, rotate, shuffle...), e generiche operazioni numeriche (accumulate, adjacent difference...). </li></ul>find count copy fill sort min , max
    141. 141. Esempio uso sequenze #include < > #include <algorithm> #include <iostream> int main() { <int> container; int val; for (int i=0; i<10; i++) { val = (int)((float)rand()/RAND_MAX*10); container.push_back(val); } <int>::iterator it1; for ( it1= container.begin(); it1!= container.end(); it1++) cout << &quot;vector : &quot; << *it1 << endl; return 0; } vector vector vector list list list
    142. 142. Esempio uso contenitori associativi #include <map> #include <algorithm> #include <iostream> #include <string> int main() { map<string,int> amap ; amap[&quot;Primo”]=1; amap[“Secondo”]=2; cout << &quot;Size : &quot; << amap.size() << endl; amap[&quot;Terzo&quot;]=3; amap[&quot;Quarto&quot;]=4; cout << &quot;Size : &quot; << amap.size() << endl; map<string,int>::iterator it; for ( it= amap.begin(); it!= amap.end(); it++) cout << &quot;map : &quot; << it->first << &quot; &quot; << it->second << endl; cout << amap.find(&quot;Terzo&quot;)-> second << endl; return 0; }
    143. 143. Assegnazione di un metodo ad un messaggio <ul><li>I metodi pubblici di una classe costituiscono l’ interfaccia della classe (cioè i messaggi che l’oggetto può interpretare) </li></ul><ul><li>La funzione è assegnata al messaggio in fase di codifica ( early binding ) </li></ul><ul><li>Può essere necessario assegnare la funzione al messaggio a run-time ( late binding ) </li></ul><ul><li> </li></ul><ul><li>Polimorfismo </li></ul>
    144. 144. Controllo dei tipi <ul><li>Controllare i tipi significa verificare che ad un oggetto vengano inviati solo messaggi che è in grado di comprendere: </li></ul><ul><ul><li>controllo del nome del metodo </li></ul></ul><ul><ul><li>controllo della lista degli argomenti </li></ul></ul><ul><li>In C++ il controllo è fatto dal compilatore ( strong typing ) </li></ul><ul><li>In altri linguaggi (ad esempio SmallTalk) è fatto a run-time ( weak typing ) </li></ul>
    145. 145. Typing & Binding Typing Definizione dei messaggi e degli argomenti Binding Assegnazione di un metodo ad un messaggio Strong Consistenza dei tipi verificata dal compilatore Weak Consistenza dei tipi verificata a run-time Early In fase di programmazione INFLESSIBILE Late A run-time POLIMORFISMO
    146. 146. Esempio: i soldati <ul><li>Tutti i soldati devono capire il messaggio attacca. Il messaggio ha conseguenze diverse a seconda del tipo di soldato: </li></ul><ul><ul><li>un arcere lancia una freccia </li></ul></ul><ul><ul><li>un fante usa la spada </li></ul></ul><ul><ul><li>un cavaliere lancia una lancia </li></ul></ul><ul><li>Il gestore della schermata vuole tenere una lista di soldati e vuole poter dire ad ogni soldato di attaccare indipendentemente dal tipo ma basandosi solo sulla posizione. </li></ul>
    147. 147. <ul><li>list<Soldato> lista; </li></ul><ul><li>riempiLista(lista); </li></ul><ul><li>Posizione unaPosizione=...; </li></ul><ul><li>list<Soldato>::iterator iter; </li></ul><ul><li>for(iter=lista.begin();iter!=lista.end();iter++){ </li></ul><ul><li>Soldato unSoldato=(*iter); </li></ul><ul><li>if(unSoldato.posizione()==unaPosizione) unSoldato. attacca() ; </li></ul><ul><li>} </li></ul><ul><li>class Soldato { </li></ul><ul><li>void attacca() { </li></ul><ul><li>// cosa scrivo qui?!? Per quale tipo di </li></ul><ul><li>// soldato implemento il metodo attacca()? </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
    148. 148. Polimorfismo <ul><li>Polimorfismo con tipi controllati dal compilatore ( Strong typing & late binding ). </li></ul><ul><li>Come? </li></ul><ul><li>In C++ viene implementato tramite il concetto di ereditarietà ( inheritance ) </li></ul><ul><li>Classe astratta : definisce i messaggi </li></ul><ul><li>Classe concreta : assegna i metodi ai messaggi </li></ul><ul><li>La classe concreta eredita da quella astratta </li></ul>
    149. 149. Ereditarietà <ul><li>Una classe può essere derivata da una classe esistente usando la sintassi: </li></ul><ul><ul><li>public , protected e private specificano il tipo di accesso ai membri della classe </li></ul></ul><ul><li>Se la classe base non ha un costruttore di default: </li></ul><ul><ul><li>La classe derivata deve implementarlo </li></ul></ul><ul><li>Se la classe base ha un costruttore di default: </li></ul><ul><ul><li>il costruttore della classe derivata deve esplicitamente invocarlo nella sua lista di inizializzatione </li></ul></ul><ul><ul><ul><li>Il costruttore della classe base può così essere eseguito prima che il costruttore della classe derivata sia eseguito </li></ul></ul></ul>class newclass: (public|protected|private) oldclass { dichiarazioni... };
    150. 150. Ereditarietà (2) <ul><li>Una classe derivata pubblicamente è a tutti gli effetti un sottotipo della classe base. </li></ul><ul><ul><li>Un oggetto della classe derivata può essere trattato come se fosse un oggetto della classe base </li></ul></ul><ul><ul><li>Un puntatore alla classe base può puntare ad oggetti della classe derivata </li></ul></ul><ul><ul><li>Un riferimento alla classe derivata può, se la cosa ha un senso, essere implicitamente convertito ad un riferimento alla classe base </li></ul></ul><ul><ul><li>E` possibile dichiarare un riferimento alla classe base ed inizializzarlo ad un oggetto della classe derivata </li></ul></ul>
    151. 151. Ereditarietà (3) <ul><li>La definizione dell’interfaccia (metodi pubblici) della classe base è estremamente importante perchè determina il comportamento delle classi derivate </li></ul><ul><li>Un metodo della classe base può essere: </li></ul><ul><ul><li>dichiarato e definito normalmente </li></ul></ul><ul><ul><ul><li>la classe derivata eredita questo metodo e NON pu ò ridefinirlo </li></ul></ul></ul><ul><ul><li>dichiarato virtual e definito normalmente </li></ul></ul><ul><ul><ul><li>la classe derivata eredita questo metodo e pu ò ridefinirlo </li></ul></ul></ul><ul><ul><li>dichiarato virtual e non definito (=0) </li></ul></ul><ul><ul><ul><li>la classe derivata eredita il metodo e DEVE ridefinirlo </li></ul></ul></ul>
    152. 152. Classi base astratte <ul><li>Una funzione puramente virtuale è un metodo virtuale non definito. E` dichiarato come: </li></ul><ul><li>Una classe che ha almeno un metodo puramente virtuale è chiamata classe astratta </li></ul><ul><li>Oggetti di una classe astratta non possono esistere </li></ul><ul><li>Puntatori ad una classe base astratta possono essere definiti ed usati polimorficamente (per puntare ad oggetti delle classi derivate) </li></ul><ul><li>Una classe base astratta viene introdotta per specificare l’ interfaccia di una categoria di classi </li></ul>virtual func_prototype = 0 ;
    153. 153. <ul><li>class Soldato { </li></ul><ul><li>virtual void attacca()=0 ; </li></ul><ul><li>}; </li></ul><ul><li>class Arcere : public Soldato { </li></ul><ul><li>virtual void attacca() { </li></ul><ul><li>// lancia una freccia </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>class Fante : public Soldato { </li></ul><ul><li>virtual void attacca() { </li></ul><ul><li>// usa la spada </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>... </li></ul>
    154. 154. Erediarietà multipla <ul><li>L’ereditarietà multipla permette di derivare una classe da due o più classi base. La sintassi viene estesa per permettere una lista di classi base </li></ul><ul><li>L’ ereditarietà multipla viene spesso utilizzata per combinare un’interfaccia ed una implementazione, ma è molte volte sintomo di un cattivo disegno </li></ul>class A { . . . . }; class B { . . . . }; class AplusB: public A, private B { . . . . };
    155. 155. dynamic_cast <ul><li>dynamic_cast opera una conversione, se è possibile, fra due tipi. Il puntatore ritornato NON è nullo soltanto se il tipo dell’oggetto su cui si opera è quello che ci si aspetta </li></ul>class Base { . . . . // base implementation }; class Derived: public Base { . . . . void new_method() ; // non e’ definito in Base! }; void func(Base *ptr) // ptr e’ un obbetto dell classe Base { ptr-> new_method (); // Errore!!! Derived *p = dynamic_cast<Derived *> (ptr) if (p !=0) { p-> new_method (); } }
    156. 156. Ereditarietà (4) <ul><li>Una classe derivata estende la classe base e ne eredita tutti i metodi e gli attributi </li></ul>DchTrack è una Track che ha degli attributi in più ( hits_ ) e nuovi metodi ( DchHit* hit(int n), int hits() ) class Track { public: LorentzVector momentum() { return p_; } protected: LorentzVector p_; }; Track.h #include “Track.h” class DchTrack : public Track { public: int hits() { return hits_->size(); } DchHit* hit(int n) { return hits_[n]; } protected: list<DchHit> hits_; }; DchTrack.h
    157. 157. Esempio: shape <ul><li>Tutti gli oggetti nella finestra hanno comportamenti comuni che possono essere considerati in astratto: </li></ul><ul><ul><li>disegna </li></ul></ul><ul><ul><li>sposta </li></ul></ul><ul><ul><li>ingrandisc </li></ul></ul><ul><ul><li>etc... </li></ul></ul>
    158. 158. Cerchi e quadrati Quadrato Cerchio
    159. 159. Cerchio public: Circle (Point2d center, double radius); ~Circle (); void moveAt (const Point2d & p); void moveBy (const Point2d & p); void scale (double s); void rotate (double phi); void draw () const; void cancel () const; class Circle { }; private: Point2d center_; double radius_; Circle.h Costruttore Distruttore Nome della classe Punto e virgola ! Point2d : classe che rappresenta un punto in 2 dimensioni. “ Dati” privati ( Attributi , membri) Interfaccia Pubblica Metodi : operazioni sugli oggetti
    160. 160. Cerchio (2) # include “Circle.h” void Circle :: draw () const { const int numberOfPoints = 100; float x[numberOfPoints], y[numberOfPoints]; float phi = 0, deltaPhi = 2*M_PI/100; for ( int i = 0; i < numberOfPoints; ++i ) { x[i] = center_.x() + radius_ * cos( phi ); y[i] = center_.y() + radius_ * sin( phi ); phi += dphi; } polyline_draw (x, y, numberOfPoints, color_, FILL); } void Circle :: moveAt ( const Point2d& p ) { cancel (); center_ = p; draw (); } void Circle :: scale ( double s ) { cancel (); radius_ *= s; draw (); } Circle :: Circle ( Point2d c, double r ) : center_( c ), radius_( r ) { draw (); } Circle :: ~Circle () { cancel (); } Circle.cc #include “Circle.h” int main() { Circle c ( Point2d(10, 10), 5 ); c . draw (); c . moveAt (Point2d(20, 30)); return 0; } Main.cc
    161. 161. Quadrato upperCorner loweCorner centerToUpperCorner _ class Square { public: Square (const Point2d&, const Point2d&, Color color = TRASPARENT); ~Square (); void moveAt ( const Point2d& p ); void moveBy ( const Point2d& p ); void changeColor ( Color color ); void scale ( double s ); void rotate ( double phi ); void draw () const; void cancel () const; private: Point2d center_; Vector2d centerToUpperCorner_; Color color_; }; Square.h #include “Square.h” void Square :: draw () const { float x[4], y[4]; Vector2d delta( centerToUpperCorner_ ); for ( int i = 0; i < 4; i++ ) { Point2d corner = center_ + delta; x[i] = corner.x(); y[i] = corner.y(); delta.rotate( M_PI_2 ); } polyline_draw (x, y, 4, color_, FILL); } void Square :: rotate ( double phi ) { cancel (); centerToUpperCorner_.rotate( phi ); draw (); } Square :: Square (const Point2d& lowerCorner, const Point2d& upperCorner, Color color) : center_( median(lowerCorner, upperCorner) ), centerToUpperCorner_( upperCorner - center_ ), color_( color ) { draw (); } void Square :: scale ( double s ) { cancel (); centerToUpperCorner_ *= s; draw (); } Square.cc
    162. 162. Codice Applicativo (Client) Come gestire cerchi e quadrati insieme? Costruisce un vettore di puntatori a cerchi, crea oggetti in memoria e salva i loro puntatori nel vettore. Itera sul vettore e invoca draw () per ogni elemento #include “Circle.h” #include “Square.h” int main() { Circle c1( Point2d (2.,3.), 4.23 ); Square r1( Point2d (2.,1.), Point2d (4.,3.) ); Circle * circles[ 10 ]; for ( int i = 0; i < 10; ++i ) { circles[ i ] = new Circle ( Point2d (i,i), 2. ); } for ( int i = 0; i < 10; ++i ) circles[ i ]-> draw (); return 0; } Main.cc
    163. 163. Polimorfismo Tutte le Shape s hanno la stessa interfaccia: draw, pick, move, fillColor... , ma ogni sottotipo diverso può avere la usa personale implementazione
    164. 164. Interfaccia astratta Interfaccia di metodi puramente virtuali class Shape { public: Shape () { } virtual ~Shape () { } virtual void moveAt (const Point2d& where) = 0 ; virtual void changeColor (Color newColor) = 0 ; virtual void scale (double s) = 0 ; virtual void rotate (double phi) = 0 ; virtual void draw () const = 0 ; virtual void cancel () const = 0 ; }; Shape.h #include “Shape.h” class Square : public Shape { // …. Il resto tutto uguale a prima }; Square.h #include “Circle.h” #include “Square.h” int main() { Shape * shapes[ 20 ]; int index = 0; for ( int i = 0; i < 10; i++ ) { Shape * s; s = new Circle ( Point2d(i, i), 2.) ); shapes[ index ++ ] = s; s = new Square ( Point2d(i, i), Point2d(i+1, i+2)) ); shapes[ index ++ ] = s; } for ( int i = 0; i < 20; i++ ) shapes[ i ]-> draw (); return 0; } Main.cc
    165. 165. Ereditarietà e riuso del codice Non si possono chiamare metodi virtuali in costruttori e distruttori (troppo presto, troppo tardi) Class CenteredShape : public Shape { public: CenteredShape (Point2d c, Color color = TRASPARENT) : center_(c), color_(color) { /*draw();*/ } ~Circle () { /*cancel();*/ } void moveAt ( const Point2d& ); void moveBy ( const Vector2d& ); void changeColor ( Color ); virtual void scale ( double ) = 0 ; virtual void rotate ( double ) = 0 ; virtual void draw () const = 0 ; virtual void cancel () const = 0 ; protected: Point2d center_; Color color_; }; CenteredShape.h #include “CenteredShape.hh” class Square : public CenteredShape { public: Square ( Point2d lowerCorner, Point2d upperCorner, Color col = TRASPARENT) : CenteredShape ( median(lowerCorner, upperCorner), col), touc_(upperCorner - center_) { draw(); } ~Square () { cancel(); } virtual void scale ( double s ) { cancel(); centerToUpperCorner_ *= s; draw(); } virtual void rotate ( double phi ); virtual void draw () const; virtual void cancel () const; private: Vector2d touc_; }; Square.h
    166. 166. Attenzione alle generalizzazioni... <ul><li>Attenzione : scegliere le relazioni di ereditarietà può essere non banale. </li></ul><ul><li>Un quadrato è un rettangolo? </li></ul>Avere lx_ e ly_ è ridondante per Square Cosa succede se si invoca scaleX o scaleY ? class Rectangle { public: Rectangle (double x0, double y0, double lx, double ly) : lx_(lx), ly_(ly), x0_(x0), y0_(y0) { } void scaleX (double s); void scaleY (double s); protected: double x0_, y0_; double lx_, ly_; }; Rectangle.h class Square : public Rectangle { public: Square (double x0, double y0, double l) : Rectangle (x0, y0, l, l) { } }; Square.h
    167. 167. Ereditarietà multipla <ul><li>Una classe può ereditare da più classi </li></ul>class DrawableObj { public: virtual void draw () = 0 ; }; DrawableObj.h class Shape { public: virtual void scale (double s) = 0 ; virtual void moveAt ( Vector2d& ) = 0 ; }; Shape.h class DrawableShape : public DrawableObj , public Shape { public: virtual void draw (); virtual void scale (double s); virtual void moveAt ( Vector2d& ); }; DrawableShape.h
    168. 168. Strategie di sviluppo di un progetto <ul><li>Requisiti : cosa l’utente vuole </li></ul><ul><li>Analisi : la visione dell’informatico dei requisiti </li></ul><ul><li>Disegno : l’aspetto del sistema software </li></ul><ul><li>Produzione : codifica </li></ul><ul><li>Testing : debugging e verifica dei requisiti </li></ul><ul><li>Mantenimento : installazione del prodotto e controllo del funzionamento per il resto della sua vita </li></ul>
    169. 169. Modello a cascata Analisi Disegno Produzione Testing Requisiti
    170. 170. Modello evoluzionario Requisiti Analisi Disegno Produzione Testing
    171. 171. Confronto fra i modelli di sviluppo <ul><li>A cascata </li></ul><ul><li>Processo lineare (si torna al passo precedente solo in caso di problemi) </li></ul><ul><li>Confinamento delle attività in ogni fase </li></ul><ul><li>Facile da gestire (gestione delle scadenze) </li></ul><ul><li>Difficile da modificare </li></ul><ul><li>Prodotto utilizzabile solo alla fine del processo </li></ul><ul><li>Evoluzionario </li></ul><ul><li>Processo ciclico (brevi processi completi) </li></ul><ul><li>Attività distribuite su più fasi </li></ul><ul><li>Difficile da gestire </li></ul><ul><li>Facile da modificare e integrare </li></ul><ul><li>Prototipo utilizzabile fin dal primo ciclo </li></ul>
    172. 172. Requisiti <ul><li>Definizione delle richieste da parte dell’utente del programma (o di una sua parte) sul sistema </li></ul><ul><li>Si parla di programmazione per contratto perchè l’utente richiede solamente la definizione del servizio richiesto NON la metodologia seguita per fornirglielo </li></ul><ul><ul><li>è possibile delegare parte del lavoro richiesto ad altri </li></ul></ul><ul><ul><li>il sistema è indipendente da chi è il suo utente </li></ul></ul><ul><li>INCAPSULAMENTO! </li></ul>
    173. 173. Analisi <ul><li>Comprensione e razionalizzazione delle richieste dell’utente </li></ul><ul><li>Costruzione di un modello </li></ul><ul><ul><li>astrazione (semplificazione delle relazioni) </li></ul></ul><ul><ul><li>rilevanza (identificazione degli oggetti chiave) </li></ul></ul><ul><li>Da non trascurare: analisi delle soluzioni esistenti. Può far risparmiare molto tempo!!! </li></ul>
    174. 174. Disegno Definizione delle interfacce Definizione di oggetti e classi Definizione degli stati e dell’implementazione Definizione delle relazioni
    175. 175. Disegno (2) <ul><li>Dopo ogni ciclo bisogna analizzare i rischi, la stabilità del disegno e la complessità delle classi </li></ul><ul><li>Se una classe è troppo complessa conviene dividerla </li></ul><ul><li>Ad ogni ciclo il numero di modifiche deve diminuire </li></ul><ul><li>Architetture troppo complesse devono essere modularizzate </li></ul>
    176. 176. Codifica <ul><li>C’è poco da dire… </li></ul><ul><li>Non sopravvalutate questa fase: </li></ul>
    177. 177. Testing <ul><li>Debugging : è ovvio… il codice non deve dare errori. </li></ul><ul><li>Use cases : specificano il comportamento del sistema in una regione. </li></ul><ul><li>Scenarios : sono esempi concreti di use cases. Per definizione se tutti gli scenari sono soddisfatti correttamente il test è positivo. </li></ul>
    178. 178. Metodi di sviluppo del software <ul><li>Un metodo comprende: </li></ul><ul><li>Una notazione </li></ul><ul><ul><li>mezzo comune per esprimere strategie e decisioni </li></ul></ul><ul><li>Un processo </li></ul><ul><ul><li>specifica come deve avvenire lo sviluppo </li></ul></ul>
    179. 179. Metodi Object Oriented <ul><ul><li>Booch Method by Grady Booch </li></ul></ul><ul><ul><li>OMT by Jim Rumbaugh </li></ul></ul><ul><ul><li>Objectory ( Use Cases ) by Ivar Jacobson </li></ul></ul><ul><ul><li>CRC by R.Wirfs-Brock </li></ul></ul><ul><li>Di recente introduzione: UML </li></ul><ul><ul><li>uno standard OMG (Object Management Group), dal novembre 1997 </li></ul></ul>Grady Booch Jim Rumbaugh Ivar Jacobson
    180. 180. UML per l’analisi e il disegno <ul><li>Class Diagrams : aspetto statico del sistema. Classi con attributi e metodi e relazioni tra di esse. </li></ul><ul><li>Sequence e collaboration digrams : comportamento dinamico del sistema. Sequenza dei messaggi scambiati fra gli oggetti. </li></ul><ul><li>Use case diagrams : illustra gli use cases, le relazioni fra di essi e gli attori che vi partecipano. </li></ul><ul><li>State diagrams : descrive gli stati in cui ogni oggetto si può trovare e le modalità con cui passa da uno stato all’altro </li></ul>
    181. 181. Concetti delle classi rivisitati <ul><li>Relazioni tra oggetti </li></ul><ul><li>Decomposizione funzionale all’interno di una classe </li></ul><ul><ul><li>responsabilità dei metodi </li></ul></ul><ul><li>Decomposizione funzionale tra più classi </li></ul><ul><ul><li>responsabilità delle classi </li></ul></ul>
    182. 182. Rappresentazione delle classi operatori attibuti pubblico protetto privato Nome + metodo(arg) # metodo(arg) - metodo(arg) - dato - dato
    183. 183. Rappresentazione di una classe C++ in UML class Nome { private: Tipo1 variabile1 ; Tipo2 variabile2 ; Tipo3 variabile3 ; public: Nome (); ~Nome (); Tipo4 funzione1 ( arg ); protected: Tipo5 funzione2 ( arg ); private: Tipo6 funzione3 ( arg ); }; Nome.h Nome - variabile1 : Tipo1 - variabile2 : Tipo2 - variabile3 : Tipo3 + funzione1 (arg): Tipo4 # funzione2 (arg): Tipo5 - funzione3 (arg): Tipo6
    184. 184. Attributi e metodi Notazione di Rational Rose Publico ( + ) Privato ( - ) Protetto ( # )
    185. 185. Principali relazioni fra classi <ul><li>associazione </li></ul><ul><li>aggregazione by reference </li></ul><ul><ul><li>(il composito non vive senza il componente) </li></ul></ul><ul><li>aggregazione by value </li></ul><ul><ul><li>(aggregazione fisica: esistenza contemporanea) </li></ul></ul><ul><li>dipendenza </li></ul><ul><li>generalizzazione (inheritance) </li></ul>
    186. 186. Aggregazione (contenimento) <ul><li>By reference (condivisa) </li></ul><ul><li>un autista guida più automobili </li></ul><ul><li>By value (possesso) </li></ul><ul><li>una automobile possiede il suo motore </li></ul>
    187. 187. Cardinalità e direzionalità <ul><li>Il punto non conosce </li></ul><ul><li>i poligoni </li></ul><ul><li>Il poligono è costituito </li></ul><ul><li>da punti </li></ul>Non navigabile
    188. 188. Dipendenza <ul><li>Non c’è nessuna associazione </li></ul><ul><li>C’è comunque relazione di uso </li></ul><ul><li>Il CD non conosce </li></ul><ul><li>il CDPlayer </li></ul><ul><li>Il CDPlayer usa il CD: se cambia </li></ul><ul><li>il formato del CD il CDPlayer deve </li></ul><ul><li>essere modificato </li></ul>
    189. 189. Generalizzazione (ereditarietà) Ereditariet à virtuale!
    190. 190. Class Diagram di “Shape”
    191. 191. Class Diagram
    192. 192. Class Diagram
    193. 193. Object Sequence Diagram
    194. 194. Object Collaboration Diagram
    195. 195. CRC Classi, Responsabilità, Collaborazioni C D E F B A x y z s f q p w
    196. 196. Assegnare Responsabilità <ul><li>Identificare i protagonisti </li></ul><ul><li>Analizzare il ruolo dei vari oggetti </li></ul><ul><li>Concentrarsi sul comportamento non la rappresentazione </li></ul><ul><li>Cercare Oggetti con proprietà comuni: </li></ul><ul><ul><li>appartiene a classi diverse, o sono solo oggetti diversi? </li></ul></ul><ul><li>Definire le interfacce (le operazioni che soddisfano le responsabilità) </li></ul><ul><li>Una corretta assegnazione delle responsabilità è la chiave di una buona modularità e riuso </li></ul>
    197. 197. Collaborazione tra classi <ul><li>Le responsabilità vanno suddivise tra i vari oggetti del sistema </li></ul><ul><li>non deve esistere un controllo centralizzato </li></ul><ul><li>Un oggetto deve compiere le proprie responsabilità e delegare ad altri operazioni specifiche </li></ul><ul><ul><li>Legge di Demeter : non usate oggetti lontani: </li></ul></ul><ul><ul><li>Invece di: traiettoria.listapunti().aggiungi(Punto); </li></ul></ul><ul><ul><li>usare: traiettoria.aggiungiPunto(Punto); </li></ul></ul>
    198. 198. Identificare Relazioni <ul><li>Cercare collaborazioni </li></ul><ul><li>Cercare aggregazioni </li></ul><ul><li>Cercare generalizazioni </li></ul><ul><li>Come un client conosce il suo service provider ? </li></ul>
    199. 199. Relazioni <ul><li>Logiche </li></ul><ul><li>Generalizazione: Is-a </li></ul><ul><li>Aggregazione: Has </li></ul><ul><li>Dipendenza: Knows </li></ul><ul><li>Implementazione </li></ul><ul><li>Inheritance </li></ul><ul><li>Template instantiation </li></ul><ul><li>Composizione by value </li></ul><ul><li>Composizione by reference </li></ul>{
    200. 200. Avere o essere? <ul><li>Uno dei punti critici è distinguere se il rapporto fra due oggetti è del tipo avere o essere : </li></ul><ul><ul><li>Un LorentzVector è un Vector o ha un Vector? </li></ul></ul><ul><ul><li>Una Traccia è un vector<Hit> o ha un vector<Hit>? </li></ul></ul><ul><ul><li>Un Rivelatore è una Superficie o ha una superficie? </li></ul></ul><ul><li>Per risolvere il problema bisogna guardare a cosa fanno! </li></ul>
    201. 201. Principio di Liskov <ul><li>Gli oggetti figli possono essere usati ovunque l’oggetto genitore è richiesto </li></ul><ul><ul><li>usare l’ inheritance quando è richiesto il polimorfismo </li></ul></ul><ul><ul><li>Non cambiare il comportamento della base class </li></ul></ul>
    202. 202. Composizione by value o by refrence <ul><li>In C++ la scelta fra aggregazione by value o by refrence può seguire questo schema: </li></ul><ul><ul><li>Tipi semplici (int, float, …): by value </li></ul></ul><ul><ul><li>Parte dello stato dell’oggetto: by value </li></ul></ul><ul><ul><li>Oggetti condivisi: by reference </li></ul></ul><ul><ul><li>Assegnati a run time: by reference </li></ul></ul><ul><li>Oggetti condivisi by reference : attenzione a chi ha la responsabilità di crearli e cancellarli! (1 new  1 delete!) </li></ul>
    203. 203. Approccio Outside-in <ul><li>Il corretto approccio è quello di guardare il sistema dall’esterno. </li></ul><ul><li>Identificare prima di tutto gli oggetti che interagiscono con l’utente esterno e i messaggi a cui devono saper rispondere ( think client! ) </li></ul><ul><li>In seguito identificare gli oggetti che forniscono servizi a questi ultimi e così via </li></ul><ul><li>Gli algoritmi vengono per ultimi!!! </li></ul>
    204. 204. CRC Workshop <ul><li>Metodo per la definizione si una architettura bilanciata </li></ul><ul><li>Ogni partecipante svolge il ruolo di una classe. </li></ul><ul><ul><li>Individuazione delle classi </li></ul></ul><ul><ul><li>Contrattazione delle responsabilità </li></ul></ul><ul><ul><li>Definizione delle collaborazioni </li></ul></ul><ul><ul><li>Difesa dal tentativo di assegnazione di responsabilità contrarie alla natura della classe </li></ul></ul>
    205. 205. Regole per il CRC workshop <ul><li>Tentate di rifuutare le responsabilità </li></ul><ul><ul><li>Dovrei? (Non sono io che lo devo fare!) </li></ul></ul><ul><ul><li>Potrei? (Non ho i mezzi, o lo stato per farlo!) </li></ul></ul><ul><li>Cercate di fare poco lavoro </li></ul><ul><ul><li>Se avete dovuto accettare una responsabilità cercate di far fare il lavoro a qualcun’altro </li></ul></ul><ul><li>Potenziate i collaboratori, non interferite </li></ul>
    206. 206. Design Patterns <ul><li>Sono elementi di software OO riutilizzabile </li></ul><ul><li>Piccoli insiemi di classi che collaborano implementando dei comportamenti tipici </li></ul><ul><ul><li>Creational patterns </li></ul></ul><ul><ul><li>Structural patterns </li></ul></ul><ul><ul><li>Behavioral patterns </li></ul></ul><ul><li>I principali sono raccolti in un libro: </li></ul><ul><li>E. Gamma et al., Design Patterns </li></ul>
    207. 207. Factory I client possono richiedere la creazione di un prodotto senza dipendervi La Factory dipende dai prodotti concreti, mentre i client dipendono solo da quelli astratti
    208. 208. Proxy Una richiesta da un client a un server, può essere mediata dal Proxy , che può compiere anche altre operazioni (I/O, caching, etc.)
    209. 209. Composite Il client può trattare componenti e compositi usando la stessa interfaccia. La composizione può essere ricursiva. Esempio : programmi di grafica
    210. 210. Gruppo di Shapes Il gruppo di shapes è il Composite La shape è il Component Le shapes concrete (Circle, Square, ecc...) sono le Leaf Circle, Square, ... draw( ) Shape draw( ) GroupofShapes draw( ) 1..* 1..* Client _components
    211. 211. Codice del modello composite #include “ Shape .h” class Circle : public Shape { public: Circle ( Point2D c, double r ): Shape(), center_(c), radius_(r) {} void draw () const { ; // draw circle } // altri metodi definiti per Circle pr ivate : double radius_ ; Point2D center_; }; Circle .h class Shape { public: Shape () {} virtual void draw () const = 0; // altri metodi virtuali ( = 0 ) }; Shape .h
    212. 212. Codice del modello composite #include “ Shape .h” class GroupofShapes : public Shape { public: typedef vector< Shape *> Container; typedef Container::const_iterator Iterator; GroupofShapes (){} void draw () const { Iterator p=components.begin(); Iterator pe=components.end(); while (p!=pe) { (*p)-> draw (); p++; } return; } // gli altri metodi sono definiti operando // sui componenti protected: Container components; }; GroupofShapes .h
    213. 213. Strategy Il pattern Strategy permette di scegliere l’algoritmo da eseguire a run-time. Nuovi algoritmi possono essere introdotti senza modificare il codice utente.
    214. 214. Observer Lo stato dell’ Observer dipende dallo stato del Subject . Il Subject notifica a tutti gli Observer registrati che il suo stato è cambiato.
    215. 215. Appendice: strighe C-style <ul><li>Le variabili carattere sono gestite come array di char (un char contiene un solo carattere) </li></ul><ul><ul><li>accesso agli elementi tramite la sintassi degli array </li></ul></ul><ul><ul><li>carattere nullo usato come terminatore ( ‘’ ) </li></ul></ul><ul><li>Funzoni di libreria per la gestione dei char* : </li></ul><ul><ul><li>#include<cstring> per utilizzarle </li></ul></ul><ul><ul><li>int strlen(const char*); lunghezza della stringa </li></ul></ul><ul><ul><li>int strcmp(const char*, const char*); confronto di due stringhe </li></ul></ul><ul><ul><li>char* strcpy(char*, const char*); copia la seconda stringa nella prima </li></ul></ul>
    216. 216. Appendice: la classe string <ul><li>Per semplificare la gestione delle stringhe è stata creata la classe string </li></ul><ul><ul><li>#include<string> per usarla </li></ul></ul><ul><ul><li>Definiti gli operatori standard: </li></ul></ul><ul><ul><ul><li>= per l’assegnazione </li></ul></ul></ul><ul><ul><ul><li>+ e += per la concatenazione </li></ul></ul></ul><ul><ul><ul><li>== e tutti gli altri operatori relazionali per il confronto </li></ul></ul></ul><ul><ul><ul><li>[] per l’accesso agli elementi </li></ul></ul></ul><ul><ul><li>Disponibile sintassi simile a quella dei contenitori STL: </li></ul></ul><ul><ul><ul><li>iteratori: string::iterator e string::const_iterator </li></ul></ul></ul><ul><ul><ul><li>funzioni begin() , end() , size() , ecc... </li></ul></ul></ul><ul><ul><li>Interoperabilità con char* : </li></ul></ul><ul><ul><ul><li>char* c=“Pippo”; string s=c; </li></ul></ul></ul><ul><ul><ul><li>char* c1 = s.c_str(); s += c; </li></ul></ul></ul>
    217. 217. Confronto stringhe C-style e string <ul><li>#include<iostream> </li></ul><ul><li>#include< cstring > </li></ul><ul><li>int main(){ </li></ul><ul><li>int err=0;int big=1000000; </li></ul><ul><li>char* c1 =“LLLong string”; </li></ul><ul><li>for(int i=0;i<big;i++){ </li></ul><ul><li>int len= strlen(c1) ; </li></ul><ul><li>char* c2=new char[len+1] ; </li></ul><ul><li>strcp(c2,c1) ; </li></ul><ul><li>if( strcmp(c2,c1) )err++; </li></ul><ul><li>delete[] c2 ; </li></ul><ul><li>} </li></ul><ul><li>cout<<err<<“errori”<<endl; </li></ul><ul><li>return 0; </li></ul><ul><li>} </li></ul><ul><li>#include<iostream> </li></ul><ul><li>#include< string > </li></ul><ul><li>int main(){ </li></ul><ul><li>int err=0;int big=1000000; </li></ul><ul><li>string s1=“LLLong string”; </li></ul><ul><li>for(int i=0;i<big;i++){ </li></ul><ul><li>// int len= s1.size() ; </li></ul><ul><li>string s2=s1 ; </li></ul><ul><li>if( s2!=s1 )err++; </li></ul><ul><li>} </li></ul><ul><li>cout<<err<<“errori”<<endl; </li></ul><ul><li>return 0; </li></ul><ul><li>} // 2 volte piu’ veloce!!! </li></ul>
    218. 218. Appendice:operazioni di I/O <ul><li>Si utilizza la libreria iostream </li></ul><ul><ul><li>Gli operatori di stream >> e << dirigono il flusso da/per le unità desiderate: </li></ul></ul><ul><ul><ul><li>cout : standard output. Si sono già visti molti esempi </li></ul></ul></ul><ul><ul><ul><li>cerr : standard error. Si usa come cout </li></ul></ul></ul><ul><ul><ul><li>cin : standard input (normalmente la tastiera) </li></ul></ul></ul>include<iostream> include<string> int main(){ string nome; cout << “Come ti chiami?” << endl; cin >> nome; // Notare la direzione!!! if(nome.empty()) cerr << “Stringa nulla!” << endl; else cout << “Ciao “ << nome << “!” << endl; return 0; }
    219. 219. Overloading degli operatori di I/O <ul><li>Gli operatori << e >> possono essere ridefiniti per consentire operazioni del tipo: </li></ul><ul><ul><ul><li>Vector2D v(1,2); </li></ul></ul></ul><ul><ul><ul><li>cout << “Il vettore v vale “ << v << endl; </li></ul></ul></ul><ul><li>Si utilizza una funzione friend : </li></ul><ul><ul><li>class Vector2D { </li></ul></ul><ul><ul><li>friend ostream& operator << ( ostream& os , const Vector2D v); </li></ul></ul><ul><ul><li>[...] </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>ostream& operator <<( ostream& os , const Vector2D v){ os << “(“ << v.x() << “,” << v.y() << “)”;} </li></ul></ul><ul><li>Si ottiene: </li></ul><ul><ul><ul><li>Il vettore v vale (1,2) </li></ul></ul></ul>
    220. 220. Appendice: I/O con files <ul><li>E’ possibile definire altre unità di I/O </li></ul><ul><ul><li>Si utilizza la libreria fstream (include iostream ) </li></ul></ul><ul><ul><li>I files di input sono dichiarati ifstream </li></ul></ul><ul><ul><li>I files di output sono dichiarati ofstream </li></ul></ul><ul><ul><li>I files di input/output sono dichiarati fstream </li></ul></ul><ul><ul><li>Costruttore con argomento const char* (nome file) </li></ul></ul>#include < fstream > #include <string> int main(){ ifstream fin (“file1.dat”); // deve esistere! if(!fin){ cerr << “file1.dat non esiste” << endl; return -1; } ofstream fout (“file2.dat”); // se esiste viene sovrascritto int i=0; string parola; while ( inf >> parola) fout << “La “ << ++i << “-esima parola e’ “ << parola << endl; fin.close(); fout.close(); return 0; }
    221. 221. Appendice: I/O in memoria <ul><li>E’ possibile definire unità di I/O in memoria (non legate a files) </li></ul><ul><ul><li>Si utilizza la libreria sstream (include iostream ) </li></ul></ul><ul><ul><li>Le unità di input sono dichiarati istringstream </li></ul></ul><ul><ul><li>Le unità di output sono dichiarati ostringstream </li></ul></ul><ul><ul><li>Le unità di input/output sono dichiarati stringstream </li></ul></ul><ul><ul><li>I costruttori non hanno argomento </li></ul></ul><ul><ul><li>Il metodo str() applicato ad un oggetto di questo tipo ritorna la stringa ( string ) contenuta nell’unità: </li></ul></ul><ul><ul><ul><li>ostringstream messaggio; </li></ul></ul></ul><ul><ul><ul><li>messaggio << “Ciao!” << endl; </li></ul></ul></ul><ul><ul><ul><li>string s=messaggio .str() ; </li></ul></ul></ul>
    222. 222. Appendice: Manipolatori di I/O <ul><li>Modificano il comportamento di una stream . </li></ul>boolalpha : true e false rappresentati come stringhe noboolalpha : true e false rappresentati come 1 e 0 (default) showbase : interi stampati col prefisso che indica la base noshowbase : interi stampati senza il prefisso (default) showpoint : floating point stampati sempre col punto decimale noshowpoint : stampa i floating point come interi se non frazionari (default) showpos : stampa + per numeri positivi noshowpos : non stampa + per i numeri positivi (default) skipws: salta gli spazi bianchi in input (default) noskipws : non salta gli spazi bianchi in input uppercase : stampa 0X in esadecimale, E in scientifica lowercase : stampa 0x oppure e (default) dec : interi in base 10 (default) hex : interi in base 16 oct: interi in base 8
    223. 223. Appendice: Manipolatori di I/O (2) <ul><li>I seguenti manipolatori richiedono: </li></ul><ul><ul><li>#include <iomanip> </li></ul></ul>left : aggiunge caratteri di riempimento alla destra del val. right : aggiunge caratteri di riempimento alla sinistra internal : aggiunge caratteri fra segno e valore fixed : floating point in notazione decimale (default) scientific : floating point in notazione scientifica flush : svuota il buffer ends : aggiunge il carattere nullo ( ) e svuota il buffer endl : aggiunge un
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×