Pillole di C++

45
Il C++ in pillole Corrado Santoro ARSLAB - Autonomous and Robotic Systems Laboratory Dipartimento di Matematica e Informatica - Universit` a di Catania, Italy [email protected] L.A.P. 1 Course Corrado Santoro Il C++ in pillole

Transcript of Pillole di C++

Page 1: Pillole di C++

Il C++ in pillole

Corrado Santoro

ARSLAB - Autonomous and Robotic Systems LaboratoryDipartimento di Matematica e Informatica - Universita di Catania, Italy

[email protected]

L.A.P. 1 Course

Corrado Santoro Il C++ in pillole

Page 2: Pillole di C++

C++: Definizioni e Sintassi Base

Corrado Santoro Il C++ in pillole

Page 3: Pillole di C++

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

Page 4: Pillole di C++

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

Page 5: Pillole di C++

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

Page 6: Pillole di C++

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

Page 7: Pillole di C++

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

Page 8: Pillole di C++

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

Page 9: Pillole di C++

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

Page 10: Pillole di C++

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

Page 11: Pillole di C++

Passaggio parametri, puntatori e reference

Corrado Santoro Il C++ in pillole

Page 12: Pillole di C++

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

Page 13: Pillole di C++

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

Page 14: Pillole di C++

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

Page 15: Pillole di C++

Allocazione Dinamica

Corrado Santoro Il C++ in pillole

Page 16: Pillole di C++

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

Page 17: Pillole di C++

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

Page 18: Pillole di C++

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

Page 19: Pillole di C++

Costruttori e Distruttori

Corrado Santoro Il C++ in pillole

Page 20: Pillole di C++

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

Page 21: Pillole di C++

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

Page 22: Pillole di C++

Overloading Operatori

Corrado Santoro Il C++ in pillole

Page 23: Pillole di C++

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

Page 24: Pillole di C++

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

Page 25: Pillole di C++

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

Page 26: Pillole di C++

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

Page 27: Pillole di C++

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

Page 28: Pillole di C++

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

Page 29: Pillole di C++

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

Page 30: Pillole di C++

Polimorfismo

Corrado Santoro Il C++ in pillole

Page 31: Pillole di C++

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

Page 32: Pillole di C++

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

Page 33: Pillole di C++

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

Page 34: Pillole di C++

Ereditarieta

Corrado Santoro Il C++ in pillole

Page 35: Pillole di C++

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

Page 36: Pillole di C++

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

Page 37: Pillole di C++

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

Page 38: Pillole di C++

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

Page 39: Pillole di C++

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

Page 40: Pillole di C++

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

Page 41: Pillole di C++

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

Page 42: Pillole di C++

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

Page 43: Pillole di C++

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

Page 44: Pillole di C++

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

Page 45: Pillole di C++

Il C++ in pillole

Corrado Santoro

ARSLAB - Autonomous and Robotic Systems LaboratoryDipartimento di Matematica e Informatica - Universita di Catania, Italy

[email protected]

L.A.P. 1 Course

Corrado Santoro Il C++ in pillole