2. Cours semaine 1 jour 4 Cours C++ 2
Plan du jour
Utilisation de l’abstraction de données :
définition de classes
Abstraction et implémentation
Initialisation et destruction
3. Cours semaine 1 jour 4 Cours C++ 3
Problèmes du C
Finalement (…), il existe deux choses en C :
Des structures de données où sont stockées des
valeurs
Certaines doivent être traitées de manière spéciale :
il faut réserver un bloc de mémoire avant de les
utiliser
Des fonctions qui exploitent ces structures
Structures et fonctions sont généralement
séparées, dans des fichiers différents
4. Cours semaine 1 jour 4 Cours C++ 4
Problèmes du C (2)
Les fichiers C se terminant par .h
permettent de stocker des valeurs
(généralement constantes), des définitions
de structures, parfois même des structures à
utiliser et, enfin, les signatures des fonctions
opérant sur les structures (ce dernier point
permettant la compilation séparée des
différents fichiers d’un projet)
h permet d’identifier les headers (entêtes)
5. Cours semaine 1 jour 4 Cours C++ 5
Problèmes du C (3)
Les fichiers C se terminant par .c permettent
de stocker la définition des fonctions utiles
à la réalisation des objectifs du programme
Une et une seule de ces fonctions est la fonction
main, le point d’entrée
Certaines fonctions sont accessibles
uniquement à travers un fichier .h : les librairies
système et utilitaire, qu’il faut inclure pour
réaliser certaines opérations
6. Cours semaine 1 jour 4 Cours C++ 6
Problèmes du C (4)
C, problème #1
L’utilisation de fonctions séparées des
structures oblige à passer, à chaque fois, la
structure sur laquelle on travaille,
éventuellement à travers une indirection
(pointeur) ou plusieurs : les fonctions ne
peuvent pas avoir de mémoire !
7. Cours semaine 1 jour 4 Cours C++ 7
Problèmes du C (5)
C, problème #2
Il faut toujours introduire les définitions de
fonctions existant dans les fichiers .h avant de
les utiliser : le compilateur est capable
d’essayer de deviner la signature d’une
méthode non déclarée MAIS ceci se termine
généralement mal à l’exécution, un jour ou
l’autre
8. Cours semaine 1 jour 4 Cours C++ 8
Problèmes du C (6)
C, problème #3
C est intimement lié à UNIX, système
d’exploitation qui possède un système de
gestion de fichiers hiérarchisé. Cependant, le
langage C n’est pas hiérarchisé : tous les
fichiers y sont vu de manière plate, bien
qu’éventuellement séparés. Dans ce cadre, deux
fonctions possédant une même signature
peuvent coexister un certains temps dans un
projet avant que le problème ne soit découvert.
9. Cours semaine 1 jour 4 Cours C++ 9
Problèmes du C (7)
C, problème # 4 (le pire ?)
La gestion de la mémoire dans le tas est laissé à
la charge du programmeur. Il est
malheureusement facile d’oublier de libérer un
emplacement après utilisation. De plus, un
nombre élevé d’allocations et de libérations de
mémoire fragmente le tas : d’autres allocations
sont plus difficiles ou plus longues à réaliser.
Des fonctions de gestion de la mémoire
devraient être fournies avec chaque structure.
10. Cours semaine 1 jour 4 Cours C++ 10
Problèmes du C (8)
Résolution de problèmes
Il faut arriver à regrouper la définition d’une
structure avec les méthodes qui sont capables
de l’utiliser
Dit de manière trop abrupte, il faudrait en quelque
sorte abandonner les fichiers .h
Il faut arriver à regrouper des structures et des
fonctions similaires en un même endroit
Cela pourrait se faire avec la création de gros
fichiers de code mais avec une perte de flexibilité
11. Cours semaine 1 jour 4 Cours C++ 11
Problèmes du C (9)
Les solutions précédentes ressemblent
fortement aux solutions mises en œuvre par
les codebooks des gros systèmes
informatiques
Manque de flexibilité
Travail en équipe et maintenance fastidieux
Il manque également quelques
améliorations générales des langages de
programmation issues du génie logiciel
12. Cours semaine 1 jour 4 Cours C++ 12
Types de donnée abstraits
Les types de données abstraits (ADT,
Abstract Data Types) correspondent à une
vision améliorée des librairies
Un ADT est un ensemble de structures associé à
un ensemble d’opérations
Un ADT met l’accent tant sur les données que
sur les opérations
13. Cours semaine 1 jour 4 Cours C++ 13
Types de donnée abstraits (2)
Un ADT est abstrait
Un ADT s’utilise à travers ses structures et ses
fonctions mais les agissements de ces fonctions
ne sont pas connues du programmeur
L’important est que soit connues les fonctions
et leurs comportements : la manière dont elles
sont implémentées doit restée sans importance
Un ADT respecte une sorte de contrat, deux
ADTs respectant le même contrat sont
interchangeables
14. Cours semaine 1 jour 4 Cours C++ 14
Types de donnée abstraits (3)
Un ADT effectue une encapsulation
Un ADT contient obligatoirement des données
ET des fonctions
Un ADT ne se dévoile pas en totalité :
certaines de ses valeurs et fonctions peuvent
être cachées
Même si deux ADTs respectent le même
contrat, leur mode de fonctionnement peut être
totalement différent
15. Cours semaine 1 jour 4 Cours C++ 15
Types de donnée abstraits (4)
Un ADT permet de disposer d’un « bloc »
de code complet, précis et disposant d’une
description et de spécifications claires et
sans ambiguïtés
Un ADT permet de ne pas être dépendant de
la représentation physique interne
Beaucoup moins de problèmes de portage
Plus facile de changer de plate-forme
16. Cours semaine 1 jour 4 Cours C++ 16
Types de donnée abstraits (5)
Un ADT
Décrit un ensemble de propriétés essentielles
sans sur-spécifier la représentation interne
On veut juste pouvoir s’en servir, on ne veut pas
savoir comment s’est fait
L’interface d’un ADT fournit une liste
d’opérations et non pas une description de
l’implémentation
Même si les deux se ressemblent parfois…
Dit « quoi » plutôt que « comment »
17. Cours semaine 1 jour 4 Cours C++ 17
Types de donnée abstraits (6)
Exemples d’ADT (sur des types simples)
boolean
Peut contenir les valeurs TRUE ou FALSE
Est capable d’effectuer des opérations telles and, or,
not, xor
integer
Peut contenir des valeurs comprises entre
INTEGER_MIN et INTEGER_MAX
Est capable d’effectuer des opérations comme add,
subtract, multiply ou divide
18. Cours semaine 1 jour 4 Cours C++ 18
Types de donnée abstraits (7)
Un ADT complexe
Une pile (Stack)
Doit pouvoir contenir des valeurs de type X,
inconnu au départ : après tout, les opérations sur une
pile ne dépendent pas du type des éléments stockés
Doit pouvoir effectuer des opérations telles que
push( X ), pop( X ), create, delete, is_empty,
is_full, count, etc
19. Cours semaine 1 jour 4 Cours C++ 19
Types de donnée abstraits (8)
Un autre ADT complexe
Une file (Queue)
Doit pouvoir contenir des valeurs de type X,
inconnu au départ (même point de vue que pour le
pile)
Doit pouvoir effectuer des opérations telles que
enqueue( X ), dequeue( X ), create, delete,
is_empty, is_full, count, etc
Une file représente normalement un concept
FIFO (first in first out). Imaginons que celle-ci
soit LIFO (last in first out)
20. Cours semaine 1 jour 4 Cours C++ 20
Types de donnée abstraits (9)
Liens entre les deux ADT complexes
précédents :
Ils ne diffèrent que par push/enqueue et
pop/dequeue
Si la file est implémentée en LIFO, il n’y a
aucune différence entre le pile et la file
Une librairie d’ADT pourra proposer au
développeur des piles et des files LIFO et
utiliser, EN INTERNE, un seul type : la pile
21. Cours semaine 1 jour 4 Cours C++ 21
Types de donnée abstraits (10)
Notre file possède donc
Le comportement d’une file
Les opérations applicables aux files
Et pourtant…
Son implémentation est réalisée grâce à une
pile
22. Cours semaine 1 jour 4 Cours C++ 22
ADT : interface, implémentation
L’interface d’un ADT est publique
Elle permet de disposer du contrat qui lie
l’ADT au programmeur (et réciproquement)
L’implémentation d’un ADT est privée
Le programmeur n’a pas à savoir comment le
type fonctionne en interne
Un ADT doit pouvoir être défini
indépendamment d’un langage de
programmation (de manière abstraite )
23. Cours semaine 1 jour 4 Cours C++ 23
ADT : implémentation
L’implémentation de l’ADT peut être
totalement différente de ce qui est
disponible à travers l’interface
Seuls compte les résultats obtenus
24. Cours semaine 1 jour 4 Cours C++ 24
ADT : implémentation (2)
25. Cours semaine 1 jour 4 Cours C++ 25
ADT : implémentation (3)
Mais, bien sûr, certaines implémentations
seront plus efficaces, ou plus rapides, que
d’autres pour certains problèmes
D’autres implémentations seront plus sûres
26. Cours semaine 1 jour 4 Cours C++ 26
ADT : implémentation (4)
27. Cours semaine 1 jour 4 Cours C++ 27
Classes
Les classes en C++
Basiquement, les classes sont des extensions au
type struct de C
Les classes sont des containers regroupant les
valeurs des variables d’état et des opérations
manipulant ces variables d’état
Cela ressemble à un ADT ! Les classes sont en fait
des ADT possédant des caractéristiques
supplémentaires
28. Cours semaine 1 jour 4 Cours C++ 28
Classes (2)
Variables d’état ?
Une classe, comme un ADT, représente un
concept, avec ses variables et ses opérations
Cependant, un programmeur n’est pas restreint,
dans son programme, à n’utiliser qu’une seule
fois l’ADT ou la classe
Si vous avez besoin de deux pile, vous pouvez créer
deux piles différentes !
29. Cours semaine 1 jour 4 Cours C++ 29
Classes (3)
Variables d’état
Marque la différence entre un langage sans
ADT et une langage utilisant des ADT
Dans les librairies C, on passe généralement la
structure de données sur laquelle on travaille à
chaque appel de fonction
Marque la différence entre la définition de
l’ADT et l’utilisation de l’ADT
Marque l’état d’un ADT pendant son utilisation
30. Cours semaine 1 jour 4 Cours C++ 30
Classes (4)
Définition
de l’ADT
variable v1
variable v2
variable v3
méthode m1
méthode m2
méthode m3
ADT #1
valeur A
valeur B
valeur C
méthode m1
méthode m2
méthode m3
ADT #2
valeur D
valeur E
valeur F
méthode m1
méthode m2
méthode m3
Utilisation de l’ADT
Valeurs
différentes
Méthodes
identiques
31. Cours semaine 1 jour 4 Cours C++ 31
Classes (5)
Dans le langage orienté objet, on parle de
définition de classes et d’instances de classe
La définition correspond à l’ensemble du
code, comme dans un ADT
L’instance correspond à une occurrence
d’utilisation de la classe pendant l’exécution
du programme
Il n’y a qu’une et une seule définition et de
0 à N instances de la classe
32. Cours semaine 1 jour 4 Cours C++ 32
Classes (6)
Chaque instance d’une classe peut donc
avoir des variables d’état stockant des
valeurs différentes de celles des autres
instances
Cela devient évident si l’on se rappelle que le
premier langage orienté objets a été inventé
pour faire de la simulation : chaque entité
représentée est libre d’avoir son propre
comportement
33. Cours semaine 1 jour 4 Cours C++ 33
Structures et classes
En C++, les classes sont des struct cachées :
Au départ, C++ n’était qu’un préprocesseur qui
transformait le code C++ en code C avant toute
compilation
Certaines mauvaises façons de rédiger le code
sont donc autorisées…
34. Cours semaine 1 jour 4 Cours C++ 34
Structures et classes (2)
struct A {
private:
int i, j, k;
public:
int f();
void g();
}
int A::f() {
return i + j + k;
}
void A::g() {
i = j = k = 0;
}
class B {
int i, j, k;
public:
int f();
void g();
}
int B::f() {
return i + j + k;
}
void B::g() {
i = j = k = 0;
}
35. Cours semaine 1 jour 4 Cours C++ 35
Structures et classes (3)
int main ()
{
A a;
B b;
a.f();
a.g();
b.f();
b.g();
}
36. Cours semaine 1 jour 4 Cours C++ 36
Structures et classes (4)
Une seule différence existe entre ces deux
écritures d’un code aux résultats similaires :
Par défaut, une struct est accessible à tous ; son
accès est dit public
Par défaut, une classe n’est accessible à
personne ; son accès est alors dit privé
37. Cours semaine 1 jour 4 Cours C++ 37
Restriction d’accès
Les restrictions d’accès sont une
conséquence normale de la nature des ADTs
: seule a besoin d’être connue l’interface
officielle, les méthodes utilisées en interne
devant rester du seul usage de l’ADT même
Une partie est publique
Une autre partie doit rester privée
38. Cours semaine 1 jour 4 Cours C++ 38
Restriction d’accès (2)
struct A
{
int i;
int j;
int k;
int f();
void g();
}
struct A
{
public:
int i;
int j;
int k;
int f();
void g();
}
Équivalent
à
39. Cours semaine 1 jour 4 Cours C++ 39
Restriction d’accès (3)
class B
{
int i;
int j;
int k;
int f();
void g();
}
Équivalent
à
class B
{
private:
int i;
int j;
int k;
int f();
void g();
}
40. Cours semaine 1 jour 4 Cours C++ 40
Restriction d’accès (4)
Les classes d’un langage orienté objet sont
des ADTs qui mettent en œuvre l’héritage
Si une classe B hérite d’une classe A
B possèdera par définition les variables et les
fonctions publiques de A
B NE POSSÈDERA PAS les variables et les
fonctions privées de A
41. Cours semaine 1 jour 4 Cours C++ 41
Restriction d’accès (5)
Les méthodes privées sont pourtant utilisées
pour effectuer les opérations purement
internes d’un ADT
Besoin d’un niveau intermédiaire de restriction
des accès
Le niveau intermédiaire est le niveau
"protégé"
C’est un accès public pour les classes de la
descendance, et un accès privé (interdit) pour
les autres classes
42. Cours semaine 1 jour 4 Cours C++ 42
Restriction d’accès (6)
Ces concepts d’accès public, protégé ou
privé sont utilisés dans (presque) tous les
langages orientés objet
Ces concepts sont tellement répandus que
les langages de modélisation orientés objet
permettent également de les représenter
Par exemple UML, l’Unified Modeling
Language, propose une représentation
graphique de ce type de restrictions
43. Cours semaine 1 jour 4 Cours C++ 43
Restriction d’accès (7)
C++ ajoute encore un raffinement dans le
contrôle d’accès aux variables et fonctions
Une classe peut avoir des amis (friends)
Ces classes amies possèdent les mêmes droits
sur les variables et fonctions que la classe elle-
même !
La notion de friends vient corrompre les
beaux principes des langages orientés objet.
Mais cela peut servir, parfois…
44. Cours semaine 1 jour 4 Cours C++ 44
Restriction d’accès (8)
class AccessControlExample {
public:
// variables et fonctions accessibles à toutes
// les autres classes
protected:
// variables et fonctions accessibles à la classe
// même, aux classes dérivées et aux
// classes amies
private:
// variables et fonctions accessibles à la classe
// même et aux classes amies
};
45. Cours semaine 1 jour 4 Cours C++ 45
C++ et UML
Microsoft Visual C++ (v6 entreprise)
fournit un environnement de modélisation
UML.
Il est possible de représenter des classes et leurs
relations selon la norme UML
Il est possible (…) de représenter les
restrictions d’accès aux variables et fonctions
46. Cours semaine 1 jour 4 Cours C++ 46
C++ et UML (2)
2 classes :
ClasseA et
ClasseB
ClasseA
possède 4
variables
et 4 fonctions
ClasseB ne
possède rien
mais hérite de
ClasseA
47. Cours semaine 1 jour 4 Cours C++ 47
C++ et UML (3)
public
protégé
privé
implémentation
classe A
48. Cours semaine 1 jour 4 Cours C++ 48
C++ et UML (4)
Ne sont visible que les propriétés (variables) et
les méthodes (fonctions) publiques ou protégées
classe B
49. Cours semaine 1 jour 4 Cours C++ 49
C++ et UML (5)
La protection d’accès "implémentation" est sans
intérêt en C++ : elle peut être utilisée en Java et
d’autre language sous le terme "package access" :
seules les classes du même espace de nommage
ont accès aux méthodes et attributs (fonctions et
variables)
Les notions "private" + "friend" la remplace
Cette protection d’accès est disponible parce que
le logiciel est en fait une sous-version de Rational
Rose…
55. Cours semaine 1 jour 4 Cours C++ 55
Bug des petits amis Visual C
#include <iostream>
using namespace std;
class Test {
public:
Test(int x): T(x) {};
friend ostream & operator << (ostream & out_stream, Test &test);
private:
int T;
};
ostream & operator << (ostream & out_stream, Test &test) {
out_stream << test.T ;
return out_stream;
}
56. Cours semaine 1 jour 4 Cours C++ 56
Bug des petits amis Visual C (2)
#include <iostream>
using std::ostream;
class Test {
public:
Test(int x): T(x) {};
friend ostream & operator << (ostream & out_stream, Test &test);
private:
int T;
};
ostream & operator << (ostream & out_stream, Test &test) {
out_stream << test.T ;
return out_stream;
}
Suppression de l’erreur si le
Service Pack 3 n’est pas appliqué
57. Cours semaine 1 jour 4 Cours C++ 57
Et la mémoire ?
Nous avons vu que la définition d’une
classe était équivalente à la définition d’une
struct
Cela a une conséquence très importante : en
C++, tout comme en C, la définition simple
d’une classe n’est pas synonyme de
réservation d’espace mémoire
L’espace mémoire doit obligatoirement être
alloué à la création de chaque instance de la
classe
58. Cours semaine 1 jour 4 Cours C++ 58
Et la mémoire ? (2)
L’allocation de la mémoire ne se fait pas
pour tous les types de données…
Comme en C, l’utilisation des types de base
permet d’avoir une taille prédéfinie et donc un
processus de réservation automatique
Mais un pointeur reste un pointeur : une simple
case de la taille d’une adresse telle qu’existant
sur le système où tourne le programme
59. Cours semaine 1 jour 4 Cours C++ 59
Vektor.h
struct Vektor {
int size;
int quantity;
int next;
unsigned char* storage;
void initialize( int size );
void cleanup();
int add( const void* element ); // protection
void* fetch( int index );
int count();
void inflate( int increase );
};
60. Cours semaine 1 jour 4 Cours C++ 60
Vektor.c
#include "Vektor.h"
const int increment = 100;
void Vektor::initialize( int sz )
{
size = sz;
quantity = 0;
storage = 0;
next = 0;
}
61. Cours semaine 1 jour 4 Cours C++ 61
Vektor.c (2)
int Vektor::add( const void* element )
{
if( next >= quantity )
inflate( increment );
int startBytes = next * size;
unsigned char* e = (unsigned char*) element;
for( int i = 0; i < size; i++ )
storage[ startBytes + i ] = e[ i ];
next++;
return( next - 1 ); // return( next++ ) ?
}
62. Cours semaine 1 jour 4 Cours C++ 62
Vektor.c (3)
void* Vektor::fetch( int index )
{
if( index >= next )
return 0;
return &( storage[ index * size ] );
}
int Vektor::count()
{
return next;
}
63. Cours semaine 1 jour 4 Cours C++ 63
Vektor.c (4)
void Vektor::inflate( int increase )
{
int newQuantity = quantity + increase;
int newBytes = newQuantity * size;
int oldBytes = quantity * size;
unsigned char* b = new unsigned char[ newBytes ];
for( int i = 0; i < oldBytes; i++ )
b[ i ] = storage[ i ];
delete []storage;
storage = b;
quantity = newQuantity;
}
64. Cours semaine 1 jour 4 Cours C++ 64
Vektor.c (5)
void Vektor::cleanup()
{
if( storage != 0 )
delete []storage;
}
65. Cours semaine 1 jour 4 Cours C++ 65
Vektor
Vektor.h est le fichier d’include :
il définit la structure
Il définit la liste des variables (data members)
Il définit la signature des opérations
Vektor.c :
Ne définit pas la structure ni les variables de la
structure (#include "Vektor.h")
Il donne le corps des méthodes (member functions)
associées à la structure et incorpore le fichier Vektor.h
Il s’agit de l’implémentation
66. Cours semaine 1 jour 4 Cours C++ 66
Vektor (2)
Il y a deux double-points dans la définition
des fonctions car Vektor est l’espace de
nommage auquel on se réfère
Cela peut aller plus loin !
67. Cours semaine 1 jour 4 Cours C++ 67
Vektor (3)
struct Vektor {
struct Punkt
{
int x;
int y;
void setPunkt( int x, int y );
}
int size;
…
};
68. Cours semaine 1 jour 4 Cours C++ 68
Vektor (4)
void Vektor::Punkt::setPunkt( int x, int y )
{
this.x = x;
this.y = y;
};
69. Cours semaine 1 jour 4 Cours C++ 69
Vektor (5)
#include "Vektor.h"
#include <iostream>
void main() {
Vektor vecteur;
vecteur.initialize( sizeof( int ) );
for( int i = 0; i < 100; i++ )
vecteur.add( &i );
for( int j = 0; j < vecteur.count(); j++ )
std::cout << " vecteur.fetch("
<< j << ") = "
<< *(int*) vecteur.fetch( j )
<< std::endl;
vecteur.cleanup();
}
70. Cours semaine 1 jour 4 Cours C++ 70
Apparition des classes
Mais où sont passées les classes ?
Nous venons de les voir…
Mais elles étaient bien cachées !
71. Cours semaine 1 jour 4 Cours C++ 71
Apparition des classes (2)
class Vektor {
public:
int size;
int quantity;
int next;
unsigned char* storage;
void initialize( int size );
void cleanup();
int add( const void* element );
void* fetch( int index );
int count();
void inflate( int increase );
};
72. Cours semaine 1 jour 4 Cours C++ 72
Apparition des classes (3)
Deux opérations spéciales existent sur les
classes
Elles sont forcément en rapport avec le nom de
la classe
Elles permettent de savoir quelle méthode
appeler pour créer et détruire une instance
Il s’agit des constructeurs et destructeurs de
classes
73. Cours semaine 1 jour 4 Cours C++ 73
Apparition des classes (4)
Si on définit une classe Vektor
Le constructeur
se définit par Vektor::Vektor()
Arguments possibles
s’appelle par Vektor vecteur ( ou new Vektor() )
À la création de la variable
Le destructeur
se définit par Vektor::~Vektor()
Arguments possibles
est appelé par le programme lorsque la variable n’est
plus utilisée
74. Cours semaine 1 jour 4 Cours C++ 74
Apparition des classes (5)
class Vektor {
public:
int size;
int quantity;
int next;
unsigned char* storage;
Vektor();
Vektor( int size );
~Vektor();
void initialize( int size );
void cleanup();
int add( const void* element );
void* fetch( int index );
int count();
void inflate( int increase );
};
75. Cours semaine 1 jour 4 Cours C++ 75
Apparition des classes (6)
#include "Vektor.h"
const int increment = 100;
Vektor::Vektor()
{
initialize( sizeof( long double ) );
}
Vektor::Vektor( int sz )
{
initialize( sz );
}
Vektor::~Vektor()
{
cleanup();
}
76. Cours semaine 1 jour 4 Cours C++ 76
Apparition des classes (7)
Faites tourner le programme de test
Que se passe-t-il ?
Enlever les appels à initialize et cleanup
Refaites tourner
77. Cours semaine 1 jour 4 Cours C++ 77
Apparition des classes (8)
Une classe est un ADT !
Toutes les variables et méthodes doivent-elles
être disponibles ?
NON !
78. Cours semaine 1 jour 4 Cours C++ 78
Apparition des classes (9)
class Vektor {
private:
int size;
int quantity;
int next;
unsigned char* storage;
void initialize( int size );
void inflate( int increase );
void cleanup();
public:
Vektor();
Vektor( int size );
~Vektor();
int add( const void* element );
void* fetch( int index );
int count();
};
79. Cours semaine 1 jour 4 Cours C++ 79
Espace de nommage : humour
int i;
void f();
struct S {
int i;
void f();
}
void S::f() {
::f(); // global ou récursif !
::i++; // global
i--;
}