Pillole di C++
-
Upload
corrado-santoro -
Category
Education
-
view
498 -
download
2
Transcript of Pillole di C++
Il C++ in pillole
Corrado Santoro
ARSLAB - Autonomous and Robotic Systems LaboratoryDipartimento di Matematica e Informatica - Universita di Catania, Italy
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.
Ereditarieta singola e multipla.
Ereditarieta 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 visibilita
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 ilprototipo 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 verra
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, %d\n", 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 avra
visibilita e vita solo dentro main.
Appena la funzione terminera, p sara distrutto (stessasemantica 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, %d\n", 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, cioe 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, %d\n", 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, %d\n", p3.get_x(), p3.get_y());
}
✡✝ ✆
Corrado Santoro Il C++ in pillole
Puntatori e reference
In C++ e possibile “nascondere” un puntatore usando una sintassiche 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, %d\n", 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 dovra
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, %d\n", 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 “+” puo 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,%f\n", 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,%f\n", 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.
Poicha la console e essa stessa un file, essa evirtualizzata 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 world\n";
}
✡✝ ✆
✞#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 puo avere diverse forme
(implementazioni) che differiscono a seconda dei tipi e del numero diparametri 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 dueversioni:
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 funzioneseguente:✞ostream & operator<<(ostream & out, char * s);
✡✝ ✆
7. Il carattere di a-capo viene stampato sullo schermo.
Corrado Santoro Il C++ in pillole
Ereditarieta
Corrado Santoro Il C++ in pillole
Ereditarieta: 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 inInheritedClass.
protected: i membri public di BaseClass diventano protected inInheritedClass, i protected diventano private.
public: nessuna modifica.
Corrado Santoro Il C++ in pillole
Esempio sull’ereditarieta
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’ereditarieta: 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’ereditarieta
✞#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);
}
✡✝ ✆
Cio e possibile in quanto il tipo di q e polimorfico:
“Square *” per definizione, e
“Rectangle *” poiche 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 LaboratoryDipartimento di Matematica e Informatica - Universita di Catania, Italy
L.A.P. 1 Course
Corrado Santoro Il C++ in pillole