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 ("Hello World!"); /* stdio functions */ }
4.
5.
6.
7.
8. Funzioni e prototipi #include <stdio.h> int add1(int); void main() { int x; x=5; x=add1(x); printf("%d“,x); } int add1(int i) { int y; y=i+1; return (y); }
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
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 ‘ ’ alert ‘ ’ backslash ‘ ’ backspace ‘ ’ carriage return ‘ ’ double quote ‘ ’ form feed ‘ ’ tab ‘ ’ newline ‘ ’ carattere nullo ‘ ’ single quote ‘ ’ vertical tab ‘ 01’ 101 ottale, ‘A’ ‘ 041’ 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. 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.
49.
50.
51.
52.
53.
54.
55.
56.
57.
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.
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. 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.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
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.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100. Una classe C++ Messaggio Messaggio Messaggio Metodo Metodo Metodo Attributo Attributo Attributo
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
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.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
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. 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. 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.
134.
135.
136.
137.
138.
139.
140.
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 << "vector : " << *it1 << endl; return 0; } vector vector vector list list list
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
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. Polimorfismo Tutte le Shape s hanno la stessa interfaccia: draw, pick, move, fillColor... , ma ogni sottotipo diverso può avere la usa personale implementazione
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. 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.
167.
168.
169. Modello a cascata Analisi Disegno Produzione Testing Requisiti
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. 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. Composite Il client può trattare componenti e compositi usando la stessa interfaccia. La composizione può essere ricursiva. Esempio : programmi di grafica
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. 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. 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. 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. Observer Lo stato dell’ Observer dipende dallo stato del Subject . Il Subject notifica a tutti gli Observer registrati che il suo stato è cambiato.
215.
216.
217.
218.
219.
220.
221.
222.
223.
Editor's Notes
Struttura di un programma C, paradigma procedurale, Case Sensitive
Struttura
A pointer in C is the address of something The unary operator `&' 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'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'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().