les pointeurs - lirmm.frbosio/hmee325/02-pointers.pdf · les pointeurs n définition d ... rappel...
TRANSCRIPT
22/09/16
1
MASTER EEA 2ème année
HMEE325 : Optimisation et
programmation avancée Langage C/C++: gestion dynamique de la mémoire
Alberto BOSIO [email protected]
http://www.lirmm.fr/~bosio/HMEE325
2
Les pointeurs n Définition d’un pointeur
n Un pointeur est une variable contenant des adresses d’emplacements mémoires
n On dit d’un pointeur bien initialisé, qu’il pointe sur un emplacement mémoire int *pI1, *pI2; double *pD;
n Allocation statique n Avant toute chose, un pointeur doit être initialisé int X; int *P; P = &X; // P contient l’adresse de la variable X *P = 6; // Est équivalent à X = 6
22/09/16
2
3
Allocation dynamique
n En langage C++ n L’opérateur « new <Type> » permet de
réserver un emplacement mémoire pouvant contenir un objet de type Type
n Si possible, l’opérateur « new <Type> » retourne l’adresse de l’emplacement réservé
n Si la mémoire est saturée, l’opérateur « new <Type> » retourne la valeur nulle
n L’opérateur « delete » permet de libérer un espace mémoire réservé
4
Exemple // On place dans P l’adresse d’un emplacement
mémoire pouvant contenir un entier int *P; // déclaration P = new int; // allocation if (P == NULL) cerr << Memory Allocation Error << endl;
else { // On place l’entier 5 dans l’emplacement pointé par P *P = 5; // On libère l’emplacement pointé par P // grâce à l’opérateur delete
delete P; }
22/09/16
3
5
Manipulations de base
int *P, *Q; // Déclaration de deux pointeurs
int X; // Déclaration d’une variable standard
6
Manipulations de base
P = &X; // Allocation statique
*P = 6; // Affectation indirecte de X cout << X; // Affiche 6
22/09/16
4
7
Manipulations de base P = new int; // Allocation dynamique
*P = 7; // Initialisation de l’emplacement // pointé par P cout << *P; // Affiche 7
8
Manipulations de base
Q = P; // Copie du contenu d’un pointeur
22/09/16
5
9
Manipulations de base Q = P; // Copie du contenu d’un pointeur Q = new int; // Allocation statique *Q = *P + 1; // Initialisation de l’emplacement
// pointé par Q P = 0; // Emplacement pointé par P perdu delete Q; // Libération correcte Q = 0; // Affectation non automatique
10
Manipulations de base
Q = new int; // Allocation statique
*Q = *P + 1; // Initialisation de l’emplacement
22/09/16
6
11
Manipulations de base
P = NULL; // Emplacement pointé par P perdu
delete Q; // Libération correcte Q = NULL; // Affectation non automatique
12
Problème de gestion mémoire int *P, *Q; // Déclaration de deux pointeurs P = new int; // Allocation dynamique *P = 1; Q = P; // Copie de pointeur *Q = *Q + 2; // Modification de l’emplacement // pointé par P et Q
22/09/16
7
13
Problème de gestion mémoire delete P; // Libération de l’emplacement P = NULL; // pointé par P -> et Q // DANGER - DANGER - DANGER // Q pointe sur un emplacement non réservé
14
Allocation dynamique de tableaux
const int N = 4; // Déclaration statique double T[N];
for(int i=0; i<N; i++) //Initialisation du tableau
T[i] = 2*i;
22/09/16
8
15
Allocation dynamique de tableaux
const int N = 4; // Déclaration statique double T[N]; for(int i=0; i<N; i++) //Initialisation du tableau
T[i] = 2*i;
La taille du tableaux doit être constant
16
Allocation dynamique de tableaux int N; cout << "Insert the size : "; cin >> N; double T[N];
for(int i=0; i<N; i++) //Initialisation du tableau
T[i] = 2*i;
22/09/16
9
17
Allocation dynamique de tableaux int N; cout << "Insert the size : "; cin >> N; double T[N];
for(int i=0; i<N; i++) //Initialisation du tableau
T[i] = 2*i;
18
Allocation dynamique de tableaux int N; double *pT; // pointeur
cout << "Insert the size : "; cin >> N;
pT = new double[N]; // allocation dyunamique
22/09/16
10
19
Allocation dynamique de tableaux int N; double *pT; // pointeur
cout << "Insert the size : "; cin >> N;
pT = new double[N]; // allocation dynamique
Dans ce cas N = 3
20
Allocation dynamique de tableaux for(int i=0; i<N; i++) //Utilisation du tableau
pT[i] = T[i] + 1;
22/09/16
11
21
Allocation dynamique de tableaux
delete [] pT; // Libération du tableau
pT = NULL;
22
Allocation dynamique de tableaux
pT = T; // pT pointe sur T for(int i=0; i<N; i++)
pT[i] = T[i] + 2;
// T[i] = T[i] + 2;
22/09/16
12
23
Allocation dynamique de structures struct Point { // Modèle de structure int x; int y; }; Point A; A.x = 3; A.y = 5; Point *pA; // Déclaration d’un pointeur pA = new Point; // Allocation dynamique pA->x = 7; pA->y = 3;
24
Allocation dynamique de structures struct Point { // Modèle de structure int x; int y; }; Point A; A.x = 3; A.y = 5; Point *pA; // Déclaration d’un pointeur pA = new Point; // Allocation dynamique pA->x = 7; pA->y = 3;
Operatuer « -> »
Équivalent a l’operatuer « * »
(*pA).x = 7; (*pA).y = 3;
22/09/16
13
25
Allocation dynamique de structures
Point *pB; // Copie de pointeur pB = pA;
pB->y = pB->x + 1;
26
Allocation dynamique de structures
pA = &A; // Affectation statique
pA->x = 1; (*pA).y = A.y - 1;
22/09/16
14
27
Allocation dynamique de structures
delete pA; // Libération de mémoire
pA = pB = 0;
28
Modes de transmission des arguments n Par référence
void echanger(int& a, int& b){ int tmp = a; a = b; b = tmp; }
n Par adresses void echanger(int* pa, int* pb) { int tmp = *pa; *pa = *pb; *pb = tmp; }
22/09/16
15
29
Modes de transmission des arguments n Par référence
void echanger(int& a, int& b){ int tmp = a; a = b; b = tmp; }
n Par adresses void echanger(int* pa, int* pb) { int tmp = *pa; *pa = *pb; *pb = tmp; }
Le mode de transmission par
référence « spécifique au C++ » cache certaines difficultés de manipulation des pointeurs
30
Modes de transmission des arguments n Transmission équivalente de structures
n Par référence void symetrique(Point& a) { a.x = -a.x; a.y = -a.y; } n Par adresses void symetrique(Point* pa) { pa->x = -pa->x; // (*pa).x = -(*pa).x pa->y = -pa->y; // (*pa).y = -(*pa).y }
22/09/16
16
31
Modes de transmission des arguments n Transmission de tableaux
n Toujours par adresses, le nom d’un tableau représentant : n son adresse mémoire n l’adresse de son premier élément
void initialiser(int *pT, int n) { for(int i = 0; i < n; i++) pT[i] = i; } void main() { int x[3]; initialiser(x, 3); // pT = x = &x[0] }
32
Allocation dynamique de mémoire
n Langage C versus C++ n La fonction « sizeof » retourne la taille de l’espace mémoire occupé par une
variable de type donné n La fonction « malloc » doit être utilisée à la place de l’opérateur « new »
int n; cout << sizeof(n) << sizeof(int); int *pI, *pV; Point *pT, *pR; pI = new int; // pI = (int*) malloc(sizeof(int)); pV = new int[10]; // pV = (int*) malloc(sizeof(int)*10); pT = new Point; // pT = (Point*) malloc(sizeof(Point)); pR = new Point[2];// pR = (Point*) malloc(sizeof(Point)*2);
C++ C
22/09/16
17
33
Allocation dynamique de mémoire
n Langage C versus C++ n La fonction « free » doit être utilisée à la place de
l’opérateur « delete » pI = new int; delete pI; pI = (int*) malloc(sizeof(int));free(pI);
n Les fonctions « free » et « malloc » doivent être utilisées de pair de même que les opérateurs « new » et « delete »
34
Conversion de types
n Classe de base class Point {
private:int mx;int my;
public:Point (int x, int y);~Point ();
void afficher ();
};
n Classe dérivée class PointCol : public Point {private:
char m_couleur[51];
public:PointCol (int x, int y, char *col);
~PointCol ();
void afficher ();
};
22/09/16
18
35
Conversion de types
36
Conversion de types
Un objet d’une classe dérivée peut toujours être converti en un objet de la classe de base correspondante, mais pas l’inverse
22/09/16
19
37
Rappel sur le typage statique
n Classe de base class Point {
private:int mx;int my;
public:Point (int x, int y);~Point ();
void afficher ();
};
n Classe dérivée class PointCol : public Point {private:
char m_couleur[51];
public:PointCol (int x, int y, char *col);
~PointCol ();
void afficher ();
};
38
Rappel sur le typage statique
22/09/16
20
39
Rappel sur le typage statique
1. En cas de typage statique, on affiche (1,2) ou (5,3)
2. La fonction Point::afficher est toujours appelée car ad est de type Point*
3. Le choix de la fonction afficher à appeler est fait à la compilation
40
Mise en œuvre du typage dynamique - Polymorphisme
n Classe de base class Point {
private:int mx;int my;
public:Point (int x, int y);~Point ();
virtual void afficher ();
};
n Classe dérivée class PointCol : public Point {private:
char m_couleur[51];
public:PointCol (int x, int y, char *col);
~PointCol ();
virtual void afficher ();
};
22/09/16
21
41
Mise en œuvre du typage dynamique
1. En cas de typage dynamique, on affiche (1,2) ou (5,3)-Noir
2. Le choix de la fonction afficher à appeler est fait à l’exécution en fonction du type de l’objet pointé par ad (non du type du pointeur ad)
How virtual functions are (typically) implemented n If a class has any virtual functions, an extra (hidden) pointer is
added to the beginning of each object of that class. This pointer points to the virtual function table (v-table for short), which pointers to code for each virtual function supported by the object.
vtable ptr
...
data
data
ptr to code
ptr to code
...
object vtable 01001 01011 11010 01001
01001 01011 11010 01001
22/09/16
22
How virtual functions are (typically) implemented n Example:
class Shape { int xCoord, yCoord; // coordinates of center ShapeColor color; // current color public: void move(int xNew, int yNew); virtual void draw(); virtual void rotate(double angle); virtual double area(); }; Shape s1;
The object s1 looks like:
vtable ptr
color
xCoord
yCoord
ptr to Shape::draw
ptr to Shape::rotate
ptr to Shape::area
s1
Shape v-table
How virtual functions are (typically) implemented n Multiple object of type Shape share the same v-table:
n Shape s1; n Shape s2;
22/09/16
23
How virtual functions are (typically) implemented
vtable ptr
color
xCoord
yCoord
s2
vtable ptr
color
xCoord
yCoord
s1 ptr to Shape::draw
ptr to Shape::rotate
ptr to Shape::area
Shape v-table
How virtual functions are (typically) implemented n Each class derived from Shape gets its own v-table, which contains
code for inherited and overridden member functions. Suppose Circle inherits Shape::rotate (without overriding it), and overrides Shape::draw and Shape::area.
n To make things interesting, let’s also suppose that Circle adds a new virtual function, circumference.
class Circle: public Shape { int radius; public: void draw(); double area(); virtual double circumference(); };
22/09/16
24
How virtual functions are (typically) implemented
n Shape s1; n Shape s2; n Circle c1;
n Now the objects and v-tables look like:
s2
vtable ptr
color
xCoord
yCoord
s1
ptr to Circle::draw
ptr to Shape::rotate
ptr to Circle::area
Circle v-table
ptr to Shape::draw
ptr to Shape::rotate
ptr to Shape::area
Shape v-table
ptr to Circle::circ...
vtable ptr
color
xCoord
yCoord
vtable ptr
color
xCoord
yCoord
radius
c1
22/09/16
25
How virtual functions are (typically) implemented n When a virtual function is invoked, C++ looks up the right code at run-
time (it knows at compile-time what offset in the v-table to look in) and calls it:
n Shape *sPtr = new Circle(); n double a = sPtr->area();
sPtr
ptr to Circle::draw
ptr to Shape::rotate
ptr to Circle::area
ptr to Circle::circ...
vtable ptr
color
xCoord
yCoord
radius
Polymorphisme
n Le mot polymorphisme est formé à partir du grec ancien (polloi) qui signifie « plusieurs » (morphos) qui signifie « forme »
50
22/09/16
26
Abstraction des données
n On veut modéliser d’autres formes géométriques dans le même programme : n Triangle n Cercle n ….
51
Abstraction des données
n Définir une nouvelle classe à partir de classes déjà existantes
n Par dérivation n Héritage simple : à partir d’une classe n Héritage multiple : à partir de plusieurs
classes
52
22/09/16
27
53
Abstraction des données
n Intérêts de l’héritage n Définir de nouveaux attributs et de
nouvelles méthodes pour la classe dérivée, qui viennent s’ajouter à ceux et celles héritées
n Créer une hiérarchie de classes de plus en plus spécialisées (ne pas repartir de zéro)
n Utiliser des librairies de classes existantes
54
Exemple
n Définition des classes «Triangle », « Cercle », «Rectangle» à partir d’une classe «Forme». Un triangle, cercle ou rectangle étant un exemple de forme géométrique
22/09/16
28
55
Exemple
Exemple
56
// class de base
class forme {
/* interface */public:
forme () ;virtual ~forme ();
virtual int surface ( ) = 0; virtual int perimetre ( ) = 0;
};
// implementation
forme::forme () {cout << " form constructor " << endl;
}
forme::~forme () {cout << " form destructor " << endl;
}
22/09/16
29
Exemple
57
// class de base
class forme {
/* interface */public:
forme () ;virtual ~forme ();
virtual int surface ( ) = 0; virtual int perimetre ( ) = 0;
};
Fonction virtuelle
Exemple
58
// class de base
class forme {
/* interface */public:
forme () ;virtual ~forme ();
virtual int surface ( ) = 0; virtual int perimetre ( ) = 0;
};
Fonction virtuelle pure
22/09/16
30
Définition
59
n Une classe est dite classe abstraite si elle a au moins une fonction virtuelle pure.
n On ne peut pas instancier un objet à partir d’une classe abstraite : n forme l_forme;
Définition
60
n Une classe est dit classe abstrait si elle as au moins une fonction virtuelle pure.
n On peux pas instancier un objet a partir d’une classe abstrait: n forme obj_forme;
main.cpp:24: error: cannot declare variable 'l_forme' to be of abstract type 'forme' forme.h:20: note: because the following virtual functions are pure within 'forme': forme.h:29: note: virtual int forme::surface() forme.h:30: note: virtual int forme::perimetre()
22/09/16
31
Exemple
61
// classe dérivée
class cercle : public forme {
private:int r;
public:cercle ();virtual ~cercle ();void set_r (int pr);
virtual int surface ();virtual int perimetre ();
};
62
L’héritage simple
n Les membres publics de la classe base sont des membres publics dérivés
n Une classe dérivée n’a jamais accès aux membres privés de la classe base
22/09/16
32
Exemple
63
// implementation
cercle::cercle () {cout << " cercle constructor " << endl;r = 0;
}
cercle::~cercle () {cout << " cercle destructor " << endl;
}
Exemple
64
// implementation
void cercle::set_r (int pr) {if (pr >= 0)
r = pr;else
r = 0;}int cercle::surface () {
cout << " cercle surface " << endl;return ( 2 * 3.14 * r);
}int cercle::perimetre () {
cout << " cercle perimetre " << endl;return ( 3.14 * r *r );
}
22/09/16
33
Exemple
65
// main
int main (void) {cercle l_cercle; // objet definition
l_cercle.set_r (2);
cout << “ surface = “ << l_cercle.surface () << endl;
return 0; // end }
Exemple
66
n Déterminer les résultats en sortie de l’exemple précédent.
22/09/16
34
Exercise
67
nombre
entiers naturels
entiers relatifs rationnels réel
interafce: • set_value • get_value • print_number
Inheritance
Class D: private B { … };Class D: protected B { … };Class D: public B { … };
68
22/09/16
35
Inheritance
n If B is a private base: n Its public and protected members can be
used only by D n Only members of D can convert D* in to B*
n If B is a protected base: n Its public and protected members can be
used only by D and any class derived from D n Only members of D or derived from D can
convert D* in to B*
69