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
C++: Definizioni e Sintassi Base
Corrado Santoro Il C++ in pillole
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
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
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
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
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
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
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
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
Passaggio parametri, puntatori e reference
Corrado Santoro Il C++ in pillole
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
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
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
Allocazione Dinamica
Corrado Santoro Il C++ in pillole
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
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
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
Costruttori e Distruttori
Corrado Santoro Il C++ in pillole
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
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
Overloading Operatori
Corrado Santoro Il C++ in pillole
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
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
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
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
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
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
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
Polimorfismo
Corrado Santoro Il C++ in pillole
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
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
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
Ereditariet`a
Corrado Santoro Il C++ in pillole
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
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
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
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
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
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
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
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
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
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
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

Pillole di C++

  • 1.
    Il C++ inpillole 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
  • 2.
    C++: Definizioni eSintassi Base 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 diclasse ✞ 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 eimplementazione 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 eimplementazione 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 eimplementazione 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 usodegli 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
  • 11.
    Passaggio parametri, puntatorie reference Corrado Santoro Il C++ in pillole
  • 12.
    Semantica del passaggiodi 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 InC++ `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
  • 15.
  • 16.
    Allocazione dinamica E’ possibileallocare 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> classPoint { 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 diarray 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
  • 19.
    Costruttori e Distruttori CorradoSantoro Il C++ in pillole
  • 20.
    Costruttore e Distruttore Lagestione 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
  • 22.
  • 23.
    Overloading Operatori Tutti glioperatori (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’espressionedel 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 ✞ classComplex { 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 ✞ classComplex { 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: Esempio2 ✞ 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 eStream 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
  • 30.
  • 31.
    Polimorfismo In C++ ognimetodo 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 operatorie 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 operatorie 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
  • 34.
  • 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 classeRectangle 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: sintassidei 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> usingnamespace 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 ✞ ... classSquare : 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-virtualinheritance ✞ ... 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-virtualinheritance ✞ ... 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-virtualinheritance 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-virtualinheritance ✞ ... 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++ inpillole 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