Académique Documents
Professionnel Documents
Culture Documents
Introduction
Constatations :
Le monde réel est composé d’objets et d’entités qui évoluent d’une manière autonome et qui
interagissent entre eux :
Un animal, une voiture, une machine,…
Idée : Réaliser des programmes qui modélisent (simulent) le monde réel : Les composants d’un
programme seront des entités/ des objets qui représentent les objets du monde réel : Entité
objet
La notion d’objet n’est pas nouvelle. Elle date de 1967
1967 : SIMULA : un langage de programmation orienté vers les applications de simulation des
systèmes discrets fut le premier à avoir introduit la notion de classe
1976 : SMALTALK a implémenté les concepts d’encapsulation, d’agrégation et d’héritage
De nombreux langages OO ont vu le jour : EIFFEL, OBJECTIVE C, LOOPS
Difficultés : créer une représentation abstraite sous la forme d’objets / entités ayant une existence
matérielle ( chien, voiture, …) ou bien virtuelle (sécurité sociale, temps, ….)
Caractéristiques d’un objet
Une classe décrit la structure d’un ensemble d’objet de même nature. Plusieurs
chiens seront décrits par une même classe « chien ».
Instance : Un objet est une instanciation d’une classe.
Créer une classe est similaire à l’opération de définition d’un nouveau type de
données
Créer un objet est similaire à la déclaration d’une variable
Une classe sera composée de :
Attributs
Méthodes
Exemple: Pour décrire une classe voiture on sera amené à définir ses attributs qui
sont les composants de la voiture et des méthodes qui sont le comportement de la
voiture tels que « faire tourner le moteur »
Exemple de classe
Concept d’encapsulation des données
Masquage des données : L’utilisateur n’a pas à connaître la manière dont les données
sont stockées. Il ne peut pas les modifier ou bien les consulter directement. Il doit appeler
les méthodes de l’objet.
Exemple d’encapsulation
Niveau de visibilité
Une classe d’objet peut définir trois niveaux de visibilité pour ses
données ou bien pour ses méthodes :
EST-UN ?
Polymorphisme
Définition :
Poly : plusieurs
Morphisme : Forme
Modéliser le monde réel sous la forme d’objets abstraits n’est pas une
tâche facile. Il faut :
Analyser le monde réel
Identifier les entités
Déterminer leurs caractéristiques
Identifier leurs comportements
Identifier leurs interactions
Identifier leurs relations
Etc.
il faut adopter et suivre une démarche méthodique pour ne pas se
perdre
Les méthodes d’analyse et de modélisation (2)
Cette méthode doit être indépendante du langage de programmation.
Début des années 90 : Apparition de la programmation objet (il faut définir une
méthodologie adaptée), apparition de plus de 50 méthodes entre 1990 et 1995.
Les trois méthodes ont unifié leurs efforts et ont convergé vers une méthode
unique connue sous le nom de :
UML : Unified Modeling Language (Langage de Modélisation Unifié)
Les méthodes d’analyse et de modélisation (3)
Les mots réservés public et private délimitent les sections visibles par
l’application.
Définition d’une classe (2)
Exemple
class Vehicule
{ private : // membres privées
private: les membres privés ne sont accessibles que par les fonctions membres de
la classe. La partie privée est aussi appelée réalisation.
protected: les membres protégés sont comme les membres privés. Mais ils sont
aussi accessibles par les fonctions membres des classes dérivées (voir l’héritage).
public: les membres publics sont accessibles par tous. La partie publique est
appelée interface.
Les mots réservés private, protected et public peuvent figurer plusieurs fois dans la
déclaration de la classe. Le droit d’accès ne change pas tant qu’un nouveau droit n’est
pas spécifié.
Recommandations de style
En général, la déclaration d’une classe contient simplement les prototypes des fonctions
membres de la classe. Les fonctions membres sont définies dans un module séparé ou plus
loin dans le code source.
Déclaration à l’extérieur de la classe
class Vehicule
{ private :
char matriculation[8]; // données membres privées
float poids;
char* Type;
public :
void init(char [ ], char *, float); // prototype des fonctions membres
void affiche();
void set_poids(float x){ poids=x; }
};
Définition des fonctions membres (2)
void Vehicule::init(char m[ ], float p, char *t)
{ strcpy(matriculation, m);
Type = new char [strlen(t)+1];
strcpy(Type, t);
poids = p;
}
void Vehicule ::affiche()
{ cout << matriculation << " " << Type << " " <<poids; }
Syntaxe générale :
type_valeur_retournée Classe::nom_fonction ( paramètres_formels )
{… // corps de la fonction }
Définition des fonctions membres (3)
Déclaration à l’intérieur de la classe
La définition de la méthode peut avoir lieu à l’intérieur de la déclaration de la classe. Dans ce cas, ces fonctions
sont automatiquement traitées par le compilateur comme des fonctions inline.
Exemple
class Exemple
{ private : char indice, info;
public :
void init(char v1, char v2){ indice=v1; info=v2; }
void set_indice (char c) { indice = c; } // fonction inline
char get_indice () { return indice; } // fonction inline
void affiche();
};
inline void Exemple::affiche()
{ // fonction inline : La visibilité d’une fonction inline est restreinte au module dans lequel elle est définie.
cout << « Indice = " << indice << endl; }
Instanciation d’une classe
Exemple
Après avoir créé une instance (de façon statique ou dynamique) on peut
accéder aux attributs et méthodes de la classe. Cet accès se fait comme
pour les structures à l’aide de l’opérateur . (point) ou -> (flèche).
Exemple
v1.init("00779", 3, "BMW");
v2->init("00778", 4.7, "WV");
Groupe[0].init("007339", 6, "SEAT");
v1.affiche();
v2->affiche();
Groupe[0].affiche();
v1.set_poids(0);
Exercice
Nombre complexe
Un objet complexe doit contenir deux composantes réelles et doit répondre aux
fonctions suivantes :
initialiser un nombre complexe
additionner deux nombres complexes
soustraire deux nombres complexes
multiplier deux nombres complexes
afficher un nombre complexe
etc.
void afficher ( ); };
void complexe :: init(float a , float b) void complexe::afficher( )
{ if (y>=0)
{ x = a;
cout <<x<< « +i »<<y ;
y=b;}
else
void complexe::ajouter(complexe z)
cout <<x<< « -i »<<-y ;
{ x = x + z.x ;
}
y = y + z.y ; }
Exercice
Pile d’entiers
Pour cet exemple, nous allons supposer que les éléments à empiler sont de type
entier et nous allons utiliser un tableau linéaire pour l’implémentation.
Correction
//----------------- init ----------------------------- //----------------- push -----------------------------
class pile int pile::push (int x)
void pile::init ()
{ int tab [100]; { if (!full())
int k; { k=0 ; { tab[k++] = x;
// indice dans tab de la première position libre max = 100; return 1;
int max; } } else return 0;}
// nombre maximum de places dans la pile //----------------- pop -----------------------------
//----------------- full ----------------------------- int pile::pop ( )
bool pile::full() {
public:
{ return (k >= max ) ; } if ( !empty () )
void init (); { return tab[--k];
int push (int x); }
int pop (); //----------------- empty --------------------------- else
int full (); bool pile::empty() return 0;
int empty (); { return (k == 0 ) ; }
};
}
Fonctions constantes
Certaines méthodes d’une classe ne doivent (ou ne peuvent) pas modifier les valeurs des données
membres de la classe, ni retourner une référence non constante ou un pointeur non constant d’une
donnée membre. On dit que ce sont des fonctions membres constantes.
Ce type de déclaration renforce les contrôles effectués par le compilateur et permet donc une
programmation plus sûre sans coût d’exécution.
Exemple
class MaClasse
{ private :
int indice;
float info;
public :
void set_indice (int n) { indice = n; }
// méthodes constantes
int get_indice() const { return indice; }
void affiche() const;
};
inline void MaClasse::affiche() const
{ cout << "Indice = " << indice << endl; }
Fonctions constantes (2)
Une fonction membre const peut être appelée sur des objets constants ou pas, alors qu’une
fonction membre non constante ne peut être appelée que sur des objets non constants.
Exemple
const MaClasse mc1; // une constante
mc1.affiche(); // OK
mc1.set_indice(5); /* ERREUR: seule les fonctions const peuvent être appelées
pour un objet constant*/
MaClasse mc2;
mc2.affiche(); // OK
mc2.set_indice(5); // OK
Surcharge d’une méthode par une méthode
constante
Une méthode déclarée comme constante permet de surcharger une méthode non constante avec le
même nombre de paramètres du même type.
Exemple
class Chaîne
{ private :
char *mach;
public :
void init(char *ch = "");
// etc ...
char nieme (int n); // (1)
char nieme (int n) const; // (2)
// etc...
};
S’il n’y a pas le qualificatif const dans la deuxième méthode, le compilateur génère une erreur
(« Chaîne::nieme() cannot be redeclared in class").
Surcharge d’une méthode par une méthode
constante (2)
int main()
{
Chaîne ch1;
ch1.init("machaine");
const Chaîne ch2;
ch2.init("machaine2");
cout << ch1.nieme(1); // appel de la méthode (1)
cout << ch2.nieme(9); // appel de la méthode (2)
}
Constructeurs
Les données membres d’une classe ne peuvent pas être initialisées; il faut donc
prévoir une méthode d’initialisation de celles-ci (voir la méthode init de l’exemple
précédent). Si l’on oublie d’appeler cette fonction d’initialisation, le reste n’a plus de
sens et il se produira très certainement des surprises fâcheuses dans la suite de
l’exécution. De même, après avoir fini d’utiliser l’objet, il est bon de prévoir une
méthode permettant de détruire l’objet (libération de la mémoire dynamique ...).
Le constructeur est une fonction membre spécifique de la classe qui est appelée
implicitement à l’instanciation de l’objet, assurant ainsi une initialisation correcte de
l’objet. Ce constructeur est une fonction qui porte comme nom, le nom de la classe et
qui ne retourne pas de valeur (pas même un void).
Constructeurs (2)
Exemple
class MaClasse
{ public :
MaClasse ( ); // constructeur par défaut
// ...
private :
int indice;
};
MaClasse :: MaClasse ( )
{ indice = 0; }
Constructeur paramétré
class MaClasse
{
public :
MaClasse (int i=0); // constructeur à un paramètre
// ...
private :
int indice;
};
class MaClasse
{ public :
MaClasse ( ); // constructeur par défaut
MaClasse ( int a ); // constructeur à 1 paramètre
private :
int indice;
};
MaClasse tab2[3] = {MaClasse (1), MaClasse (2), MaClasse (3) }; //initialisation des 3 objets du tableau par les
//nombres 1, 2 et 3
Destructeur
De la même façon que pour les constructeurs, le destructeur est une fonction membre
spécifique de la classe qui est appelée implicitement à la destruction de l’objet. Ce
destructeur est une fonction qui :
class MaClasse
{ public :
// ...
~MaClasse ( );
private :
// ...
};
MaClasse :: ~MaClasse ( )
{ // ... }
public:
pile ( int taille = 100); // constructeur
~pile ( ) ; // destructeur
bool full ();
bool empty ();
bool push (int x);
int pop ( ); };
Constructeur de copie
Présentation du problème
Déclaration : int a ;
Par new : p = new int;
Initialisation : int b = a;
Paramètre d’une fonction : A chaque paramètre est créée sur la pile une
variable qui recevra une copie du paramètre. Cette variable locale sera
détruite automatiquement à la sortie de la fonction. Afficher(bidon objet)
Constructeur de copie (2)
Dans les deux premiers cas, le constructeur d’une classe est appelé
automatiquement. Par contre il n’est pas appelé dans le troisième et le
quatrième cas. Le destructeur quant à lui est appelé dans tous les cas.
Objet Objet
Date_initiale Date_copiée
jour jour
mois mois
année année
15 09 2021
Exercice (2)
Scénario 2
Objet
Date_initiale
jour
mois 15 09 2021
année
Objet
Date_copiée
jour
15 09 2021 mois
année
Exercice (3)
class MaDate
{ private:
int *jour, *mois, *annee;
public:
MaDate (int,int,int); //Constructeur par défaut
MaDate (const MaDate &); //Constructeur de copie
~MaDate ( ); //Destructeur
class Magasin
{ public:
// ....
private:
Vendeur ListeVend [10];
int main ( )
{
int n = 100 ; // c’est une initialisation
n = 200 ; // c’est une affectation
//…..
}
Initialiser une variable simple est facile par contre initialiser un objet qui est composé de
membres qui peuvent eux mêmes être des objets peut poser quelques petits problèmes.
Liste d’initialisation d’un constructeur
Lorsqu’on a des classes imbriquées, il peut y avoir un problème lors de l’appel du constructeur des différentes
classes.
class Composant
{ int att1 ;
float att2,
public :
Composant ( int a=0, float b=0) { att1 = a ; att2 = b;} …
};
class Composite
{ const int x;
int y;
Composant z;
public:
Composite(int a, int b, int c, float d); // Constructeur de Composite
~Composite ( ); // Destructeur de Composite
};
Liste d’initialisation d’un constructeur (2)
Composite :: Composite (int a, int b, int c, float d)
{ x=a ; // ERREUR: l’affectation à une constante est interdite
y=b // OK : affectation
// et comment initialiser l’objet membre z ???}
Comment initialiser la donnée membre constante x et appeler le constructeur de la classe Composant ?
Réponse : la liste d’initialisation
La phase d’initialisation de l’objet utilise une liste d’initialisation qui est spécifiée dans la définition du constructeur.
Syntaxe : nom_classe::nom_constructeur(args...) : liste_d’initialisation
{ // corps du constructeur }
x( a ) x = a
y( b ) y = b
z( c,d ) appel du constructeur de la classe Composant : Composant (c,d)
Pointeur “this”
Toute méthode d’une classe MaClasse a un paramètre caché : le pointeur this qui contient
l’adresse de l’objet qui l’a appelé. Il est implicitement déclaré et initialisé avec l’adresse de
l’objet sur lequel la méthode est appelée.
classe MaClasse
{ int attribut ;
public:
int fonction_membre1( )
{
return this i; //équivalent à : return i ;
}
};
Les membres statiques
Ces membres sont utiles lorsqu’on a besoin de gérer des données communes aux instances d’une
même classe. On peut avoir des données statiques et des fonctions statiques.
Une classe peut déclarer « amie » une autre classe ou des fonctions
externes.
C’est le mot clé friend qui permet de déclarer l’amitié entre classes.
C’est une infraction aux règles d’encapsulation pour des raisons
d’efficacité.
Fonctions amies
Exemple
class MaClasse
{
friend void visualiser (MaClasse ); // fonction amie
int a ;
public :
// ...
};
void visualiser(MaClasse n)
{
cout << n.a ;
}
Classes amies
Exemple
class Ecran
{ friend class Fenetre;
public:
//...
private :
//...
};
Les fonctions membres de la classe Fenetre peuvent accéder aux membres non-
publics de la classe Ecran.