Lorenzo D'Emidio- Lavoro sulla Bioarchittetura.pptx
Pillole di C++
1. Il C++ in pillole
Corrado Santoro
ARSLAB - Autonomous and Robotic Systems Laboratory
Dipartimento di Matematica e Informatica - Universit`a di Catania, Italy
santoro@dmi.unict.it
L.A.P. 1 Course
Corrado Santoro Il C++ in pillole
3. Il C++ `e ...
l’estensione del C con il supporto della programmazione ad
oggetti.
Ha le seguenti caratteristiche base:
Definizione di classi e oggetti.
Allocazione statica e dinamica degli oggetti.
Ereditariet`a singola e multipla.
Ereditariet`a virtual e non-virtual.
Overloading degli operatori.
Template (simili ai generics di Java).
Libreria run-time molto ricca (Standard Template Library -
STL).
Corrado Santoro Il C++ in pillole
4. C++: dichiarazione di classe
✞
class MyClass {
private:
// elenco dei membri (attributi e metodi) privati
protected:
// elenco dei membri (attributi e metodi) protetti
public:
// elenco dei membri (attributi e metodi) pubblici
} ; // <----- RICORDATEVI DEL ";" FINALE!!
✡✝ ✆
Esempio:
✞
class Point {
private:
int x, y;
public:
Point(int ax, int ay); // costruttore
int get_x();
int get_y();
} ;
✡✝ ✆
Corrado Santoro Il C++ in pillole
5. Modificatori di visibilit`a
public: il metodo o attributo `e visibile ovunque.
private: il metodo o attributo `e visibile solo all’interno
della stessa classe (default).
protected: il metodo o attributo `e visibile solo all’interno
della stessa classe e delle classi ereditate.
Corrado Santoro Il C++ in pillole
6. C++: dichiarazione e implementazione
A differenza di Java, in C++ esiste (come in C) una netta separazione
tra dichiarazione di classe e implementazione dei metodi.
La dichiarazione di classe riporta solo l’elenco degli attributi ed il
prototipo dei metodi.
L’ implementazione dei metodi `e fatta separatamente riportando la
definizione del metodo e, di seguito, il suo codice.
Il nome effettivo del metodo, specificato nell’implementazione, `e
formato dalla stringa nomeclasse::nomemetodo.
Corrado Santoro Il C++ in pillole
7. C++: dichiarazione e implementazione di classe
✞
class Point {
private:
int x, y;
public:
Point(int ax, int ay); // costruttore
int get_x();
int get_y();
} ;
Point::Point(int ax, int ay)
{
x = ax; y = ay;
}
int Point::get_x()
{
return x;
}
int Point::get_y()
{
return y;
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
8. C++: dichiarazione e implementazione di classe
E’ tuttavia possibile implementare un metodo direttamente nella
dichiarazione di classe (Java-style). In tal caso il metodo verr`a
trattato come inline.
✞
class Point {
private:
int x, y;
public:
Point(int ax, int ay); // costruttore
int get_x() { return x; };
int get_y() { return y; };
} ;
Point::Point(int ax, int ay)
{
x = ax; y = ay;
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
9. Creazione e uso degli oggetti
✞
class Point {
private:
int x, y;
public:
Point(int ax, int ay); // costruttore
int get_x() { return x; };
int get_y() { return y; };
} ;
Point::Point(int ax, int ay)
{ x = ax; y = ay; }
int main(int argc, char **argv)
{
Point p(4,5); // creazione *statica* oggetto p di classe Point
printf("Point p = %d, %dn", p.get_x(), p.get_y());
}
✡✝ ✆
L’accesso ai metodi/attributi di un oggetto si effettua con la
notazione puntata.
p `e definito all’interno della funzione main e pertanto avr`a
visibilit`a e vita solo dentro main.
Appena la funzione terminer`a, p sar`a distrutto (stessa
semantica delle variabili C).
Corrado Santoro Il C++ in pillole
10. Un altro esempio
✞
#include <stdio.h>
class Point {
private:
int x, y;
public:
Point(int ax, int ay); // costruttore
int get_x() { return x; };
int get_y() { return y; };
Point add(Point p);
} ;
Point::Point(int ax, int ay)
{ x = ax; y = ay; }
Point Point::add(Point p)
{
Point ret_val(x + p.get_x(), y + p.get_y());
return ret_val;
}
int main(int argc, char **argv)
{
Point p1(4,5), p2(10,10);
Point p3 = p1.add(p2);
printf("Risultato = %d, %dn", p3.get_x(), p3.get_y());
}
✡✝ ✆
Compilazione: g++ file.cc -o file ...
Corrado Santoro Il C++ in pillole
12. Semantica del passaggio di oggetti a metodi/funzioni
La semantica di passaggio dei parametri `e identica a quella
del C, cio´e i parametri (qualunque essi siano) vengono
passati sempre per copia.
Passare un oggetto a un metodo significa pertanto effettuarne
una copia.
✞
...
Point Point::add(Point p)
{
// p riceve *una copia* di p2 e *non lo stesso p2*
Point ret_val(x + p.get_x(), y + p.get_y());
return ret_val;
// nella fase di "return", p3 riceve una *copia* di ret_val,
// mentre ret_val viene distrutto alla conclusione del metodo add()
}
int main(int argc, char **argv)
{
Point p1(4,5), p2(10,10);
Point p3 = p1.add(p2); // <--- p2 viene *copiato* sulla variabile p del metodo add
printf("Risultato = %d, %dn", p3.get_x(), p3.get_y());
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
13. Reference agli oggetti
Q: E’ possibile avere dei reference, cos`ı come in Java?
A: S`ı!, usando i puntatori e l’allocazione dinamica✞
#include <stdio.h>
class Point {
int x, y; // private per default
public:
Point(int ax, int ay); // costruttore
int get_x() { return x; };
int get_y() { return y; };
Point add(Point * p);
} ;
Point::Point(int ax, int ay)
{ x = ax; y = ay; }
Point Point::add(Point * p)
{
// p punta a p2; p2 e (*p) sono *LO STESSO OGGETTO*
Point ret_val(x + p->get_x(), y + p->get_y());
// dato che p risulta un *puntatore*, uso la notazione "->"
return ret_val;
}
int main(int argc, char **argv)
{
Point p1(4,5), p2(10,10);
Point p3 = p1.add(&p2); // <-- passo il *PUNTATORE* a p2
printf("Risultato = %d, %dn", p3.get_x(), p3.get_y());
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
14. Puntatori e reference
In C++ `e possibile “nascondere” un puntatore usando una sintassi
che permette di specificare un tipo reference ad oggetto.
Di fatto `e un puntatore solo che `e nascosto (stessa semantica Java).
✞
class Point {
...
public:
...
Point add(Point & p);
} ;
...
Point Point::add(Point & p)
{
// p e p2 sono *LO STESSO OGGETTO*, il puntatore risulta ‘‘nascosto’’
Point ret_val(x + p.get_x(), y + p.get_y());
return ret_val;
}
int main(int argc, char **argv)
{
Point p1(4,5), p2(10,10);
Point p3 = p1.add(p2);
printf("Risultato = %d, %dn", p3.get_x(), p3.get_y());
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
16. Allocazione dinamica
E’ possibile allocare dinamicamente un oggetto usando
l’operatore new (equivalente al “malloc”) il quale restituisce
un puntatore all’oggetto.
Tuttavia ogni oggetto allocato dinamicamente dovr`a
essere esplicitamente distrutto usando l’operatore
delete (no garbage collection).
Ogni oggetto allocato dinamicamente esiste sempre fino
a che non `e distrutto esplicitamente da un delete.
Esempio: Point * p = new Point(3,4);
Corrado Santoro Il C++ in pillole
17. Allocazione dinamica
✞
#include <stdio.h>
class Point {
int x, y; // private per default
public:
Point(int ax, int ay); // costruttore
int get_x() { return x; };
int get_y() { return y; };
Point * add(Point * p);
} ;
Point::Point(int ax, int ay)
{ x = ax; y = ay; }
Point * Point::add(Point * p)
{
// alloco il risultato dinamicamente e ne restituisco il puntatore
Point * ret_val = new Point(x + p->get_x(), y + p->get_y());
return ret_val;
}
int main(int argc, char **argv)
{
Point p1(4,5), p2(10,10);
Point * p3 = p1.add(&p2);
printf("Risultato = %d, %dn", p3->get_x(), p3->get_y());
delete p3;
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
18. Allocazione dinamica di array
E’ possibile usare gli operatori “new” e “delete” anche per
allocare dinamicamente/deallocare un array.
Allocazione di un array di tipo T:
T * a = new T[size];
Deallocazione di un array:
delete [] a;
Esempio: int * p = new int[300];
Corrado Santoro Il C++ in pillole
20. Costruttore e Distruttore
La gestione del ciclo di vita di un oggetto `e demandata al
programmazione che ne controlla sia la creazione che la
distruzione (implicita o esplicita).
Accanto al metodo speciale “costruttore” esiste dunque
anche un metodo speciale denominato distruttore che
viene invocato quando l’oggetto `e cancellato dalla
memoria.
✞
class Point {
int x, y; // private per default
public:
Point(int ax, int ay); // costruttore
˜Point(); // distruttore
int get_x() { return x; };
int get_y() { return y; };
Point * add(Point * p);
} ;
Point::˜Point()
{
// .. codice del distruttore
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
21. Distruttore
L’uso del distruttore `e fondamentale per liberare eventuali
zone di memoria allocate dinamicamente dall’oggetto,
altrimento non verrebbero rilasciate (no garbage collection).
✞
class MyClass {
int * array;
public:
MyClass(int n); // costruttore
˜MyClass(); // distruttore
...
} ;
MyClass::MyClass(int n)
{
array = new int[n];
}
MyClass::˜MyClass()
{
delete [] array;
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
23. Overloading Operatori
Tutti gli operatori (artimetici, logici, relazionali, array
subscript []) posso essere ridefiniti sulla base del tipo dei
loro argomenti.
Esempio: considerando una classe Complex che
rappresenta un numero complesso, `e possibile ridefinire gli
operatori aritmetici in modo da poter scrivere un codice del
tipo:
✞
...
Complex a, b, c, d;
d = a + b * c;
...
✡✝ ✆
Corrado Santoro Il C++ in pillole
24. Overloading Operatori
Data un’espressione del tipo:
✞
Complex result, lhs, rhs;
result = lhs + rhs;
✡✝ ✆
Il comportamento dell’operatore “+” pu`o essere ridefinito in una
funzione o metodo chiamato operator+ con uno dei seguenti
prototipi:
✞
// FUNZIONI
Complex operator+(Complex lhs, Complex rhs);
Complex operator+(Complex &lhs, Complex rhs);
Complex operator+(Complex lhs, Complex &rhs);
Complex operator+(Complex &lhs, Complex &rhs);
✡✝ ✆
✞
// METODI DELLA CLASSE COMPLEX
Complex Complex::operator+(Complex rhs);
Complex Complex::operator+(Complex &rhs);
✡✝ ✆
Corrado Santoro Il C++ in pillole
25. Overloading Operatori: Esempio
✞
class Complex {
float re, im;
public:
Complex();
Complex(float r, float i);
void set(float r, float i) { re = r; im = i; };
float real() { return re; };
float imag() { return im; };
Complex operator+(Complex & p);
};
Complex::Complex()
{
re = 0; im = 0;
}
Complex::Complex(float r, float i)
{
this->re = r; this->im = i;
}
Complex Complex::operator+(Complex & p)
{
Complex result(re + p.re, im + p.im);
return result;
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
26. Overloading Operatori: Esempio
✞
class Complex {
float re, im;
public:
Complex();
Complex(float r, float i);
void set(float r, float i) { re = r; im = i; };
float real() { return re; };
float imag() { return im; };
Complex operator+(Complex & p);
};
...
Complex Complex::operator+(Complex & p)
{
Complex result(re + p.re, im + p.im);
return result;
}
main()
{
Complex a(1,2), b(3,4);
Complex c = a + b;
printf("Risultato = %f,%fn", c.real(), c.imag());
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
27. Overloading Operatori: Esempio 2
✞
class Complex {
float re, im;
public:
Complex();
Complex(float r, float i);
void set(float r, float i) { re = r; im = i; };
float real() { return re; };
float imag() { return im; };
};
...
Complex operator+(Complex & lhs, Complex & rhs)
{
Complex result(lhs.real() + rhs.real(), lhs.imag() + rhs.imag());
return result;
}
main()
{
Complex a(1,2), b(3,4);
Complex c = a + b;
printf("Risultato = %f,%fn", c.real(), c.imag());
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
28. Overloading Operatori e Stream
L’overloading degli operatori permette d’uso di una sintassi
“elegante” quando occorre accedere ai file.
I file in C++ (cos`ı come in Java) sono virtualizzati tramite
oggetti di tipo stream.
Poich`a la console `e essa stessa un file, essa `e
virtualizzata tramite due oggetti:
cout, di tipo ostream (equivalente alla printf)
cin, di tipo istream (equivalente alla scanf)
Essi sono definiti nell’header iostream
Utilizzano gli operatori “>>” e “<<”
Corrado Santoro Il C++ in pillole
29. Stream e Cout: Esempio
✞
#include <iostream> // senza il .h, gli header file C++ non lo hanno
using namespace std;
// cout e cin sono definiti nel "namespace" std
// Lo "using" serve a impostare un prefisso di namespace,
// altrimenti occorrerebbe esplicitarlo
main()
{
cout << "Hello worldn";
}
✡✝ ✆
✞
#include <iostream> // senza il .h, gli header file C++ non lo hanno
using namespace std;
// cout e cin sono definiti nel "namespace" std
// Lo "using" serve a impostare un prefisso di namespace,
// altrimenti occorrerebbe esplicitarlo
main()
{
int a, b;
cout << "Inserisci due valori:";
cin >> a;
cin >> b;
cout << "Somma = " << (a + b) << "n";
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
31. Polimorfismo
In C++ ogni metodo o funzione pu`o avere diverse forme
(implementazioni) che differiscono a seconda dei tipi e del numero di
parametri forniti.
✞
class Complex {
float re, im;
public:
Complex();
Complex(float r, float i);
void set(float r, float i) { re = r; im = i; };
void set(Complex &c) { re = c.real(); im = c.imag(); };
float real() { return re; };
float imag() { return im; };
Complex operator+(Complex & p);
};
✡✝ ✆
Nell’esempio il metodo set `e polimorfico in quanto sono presenti due
versioni:
La prima con due parametri float
La seconda con un solo parametro Complex
Corrado Santoro Il C++ in pillole
32. Polimorfismo, overloading operatori e cout
Cosa accade con una istruzione del genere?
✞
float res = 10.5;
cout << "Risultato = " << res << "n";
✡✝ ✆
1. L’operatore << `e left-associativo, quindi l’espressione equivale a:
✞
float res = 10.5;
( ( (cout << "Risultato = ") << res) << "n");
✡✝ ✆
2. Valutazione della prima parentesi, viene cercata la funzione
seguente:
✞
ostream & operator<<(ostream & out, char * s)
{
printf("%s", s);
return out;
}
✡✝ ✆
3. “Risultato = ” `e stampato a schermo e l’espressione diventa:
✞
float res = 10.5;
( ( cout << res) << "n");
✡✝ ✆
Corrado Santoro Il C++ in pillole
33. Polimorfismo, overloading operatori e cout
✞
float res = 10.5;
( ( cout << res) << "n");
✡✝ ✆
4. Valutazione della successiva parentesi, viene cercata la funzione
seguente:
✞
ostream & operator<<(ostream & out, float f)
{
printf("%f", f);
return out;
}
✡✝ ✆
5. “10.5” `e stampato a schermo e l’espressione diventa:
✞
( cout << "n");
✡✝ ✆
6. Valutazione dell’ultima, viene cercata nuovamente la funzione
seguente:
✞
ostream & operator<<(ostream & out, char * s);
✡✝ ✆
7. Il carattere di a-capo viene stampato sullo schermo.
Corrado Santoro Il C++ in pillole
35. Ereditariet`a: Sintassi
class newClass : visibility baseClass { ... } ;
✞
class InheritedClass : private BaseClass {
// ....
};
class InheritedClass : protected BaseClass {
// ....
};
class InheritedClass : public BaseClass {
// ....
};
✡✝ ✆
private: i membri public di BaseClass diventano private in
InheritedClass.
protected: i membri public di BaseClass diventano protected in
InheritedClass, i protected diventano private.
public: nessuna modifica.
Corrado Santoro Il C++ in pillole
36. Esempio sull’ereditariet`a
Una classe Rectangle e una classe ereditata Square che
specializza la classe base:
✞
class Rectangle {
float width, height;
public:
Rectangle(float w, float h);
float area() { return width * height; } ;
} ;
class Square : public Rectangle {
public:
Square(float side);
};
Rectangle::Rectangle(float w, float h)
{
width = w;
height = h;
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
37. Esempio sull’ereditariet`a: sintassi dei costruttori
Ogni classe ereditata, nel suo costruttore, deve chiamare il
costruttore padre come prima istruzione:
✞
class Rectangle {
float width, height;
public:
Rectangle(float w, float h);
float area() { return width * height; } ;
} ;
class Square : public Rectangle {
public:
Square(float side);
};
Rectangle::Rectangle(float w, float h)
{
width = w;
height = h;
}
Square::Square(float side) : Rectangle(side, side) // invocazione del costruttore del padre
{
// niente da fare qua!
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
38. Esempio sull’ereditariet`a
✞
#include <iostream>
using namespace std;
class Rectangle {
float width, height;
public:
Rectangle(float w, float h);
float area() { return width * height; } ;
} ;
class Square : public Rectangle {
public:
Square(float side);
};
Rectangle::Rectangle(float w, float h)
{ width = w; height = h; }
Square::Square(float side) : Rectangle(side, side) // invocazione del costruttore del padre
{ }
int main(int argc, char **argv)
{
Rectangle r(10,20);
Square q(50);
cout << "Area rettangolo = " << r.area() << "n";
cout << "Area quadrato = " << q.area() << "n";
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
39. Usiamo l’allocazione dinamica
✞
#include <iostream>
using namespace std;
class Rectangle {
float width, height;
public:
Rectangle(float w, float h);
float area() { return width * height; } ;
} ;
class Square : public Rectangle {
public:
Square(float side);
};
Rectangle::Rectangle(float w, float h)
{ width = w; height = h; }
Square::Square(float side) : Rectangle(side, side) // invocazione del costruttore del padre
{ }
int main(int argc, char **argv)
{
Rectangle * r = new Rectangle(10,20);
Square * q = new Square(50);
cout << "Area rettangolo = " << r->area() << "n";
cout << "Area quadrato = " << q->area() << "n";
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
40. Polimorfismo dei puntatori
✞
...
class Square : public Rectangle { ... };
...
void print_area(Rectangle * obj)
{
cout << "Area = " << obj->area() << "n";
}
int main(int argc, char **argv)
{
Rectangle * r = new Rectangle(10,20);
Square * q = new Square(50);
print_area(r);
print_area(q);
}
✡✝ ✆
Ci`o `e possibile in quanto il tipo di q `e polimorfico:
“Square *” per definizione, e
“Rectangle *” poich´e Square `e sottoclasse di
Rectangle.
Corrado Santoro Il C++ in pillole
41. Virtual vs. non-virtual inheritance
✞
...
class Rectangle {
float width, height;
public:
Rectangle(float w, float h);
float area() { return width * height; } ;
void show_area() { cout << "Area rettangolo = " << area() << "n"; };
} ;
class Square : public Rectangle {
public:
Square(float side);
void show_area() { cout << "Area quadrato = " << area() << "n"; };
};
...
void print_area(Rectangle * obj)
{
obj->show_area();
}
int main(int argc, char **argv)
{
Rectangle * r = new Rectangle(10,20);
Square * q = new Square(50);
print_area(r);
print_area(q);
}
✡✝ ✆
Cosa ci aspettiamo che stampi questo programma?
Corrado Santoro Il C++ in pillole
42. Virtual vs. non-virtual inheritance
✞
...
class Rectangle {
float width, height;
public:
Rectangle(float w, float h);
float area() { return width * height; } ;
void show_area() { cout << "Area rettangolo = " << area() << "n"; };
} ;
class Square : public Rectangle {
public:
Square(float side);
void show_area() { cout << "Area quadrato = " << area() << "n"; };
};
...
void print_area(Rectangle * obj)
{
obj->show_area();
}
int main(int argc, char **argv)
{
Rectangle * r = new Rectangle(10,20);
Square * q = new Square(50);
print_area(r);
print_area(q);
}
✡✝ ✆
✞
Area rettangolo = 200
Area rettangolo = 2500
✡✝ ✆
Corrado Santoro Il C++ in pillole
43. Virtual vs. non-virtual inheritance
Non-virtual inheritance: Data una classe C, un metodo m e un
oggetto a di tipo C * ma proveniente da un tipo D *, dove D `e
sottoclasse di C, la scrittura a->m() esegue sempre il codice
del metodo definito in C. (Comportamento di default del C++,
non presente in Java)
Virtual inheritance: Data una classe C, un metodo m e un
oggetto a di tipo C * ma proveniente da un tipo D *, dove D `e
sottoclasse di C, la scrittura a->m() esegue sempre il codice
del metodo definito in D. (Comportamento da esplicitare in
C++ tramite la keyword virtual, modello di default in Java)
Corrado Santoro Il C++ in pillole
44. Virtual vs. non-virtual inheritance
✞
...
class Rectangle {
float width, height;
public:
Rectangle(float w, float h);
float area() { return width * height; } ;
virtual void show_area() { cout << "Area rettangolo = " << area() << "n"; };
} ;
class Square : public Rectangle {
public:
Square(float side);
void show_area() { cout << "Area quadrato = " << area() << "n"; };
};
...
void print_area(Rectangle * obj)
{
obj->show_area();
}
int main(int argc, char **argv)
{
Rectangle * r = new Rectangle(10,20);
Square * q = new Square(50);
print_area(r);
print_area(q);
}
✡✝ ✆
✞
Area rettangolo = 200
Area quadrato = 2500
✡✝ ✆
Corrado Santoro Il C++ in pillole
45. Il C++ in pillole
Corrado Santoro
ARSLAB - Autonomous and Robotic Systems Laboratory
Dipartimento di Matematica e Informatica - Universit`a di Catania, Italy
santoro@dmi.unict.it
L.A.P. 1 Course
Corrado Santoro Il C++ in pillole