Académique Documents
Professionnel Documents
Culture Documents
Mohamed
El Nabil
Abdellaoui SaïdSaidi 2020/ 2021
OLYMORPHISME
2
POLYMORPHISME (UNIVERSEL D’INCLUSION)
Mohamed
El Nabil
Abdellaoui SaïdSaidi 3
RÉSOLUTION DES LIENS (STATIQUE)
Bonjour !!
Mohamed
El Nabil
Abdellaoui SaïdSaidi 4
RÉSOLUTION DES LIENS (DYNAMIQUE)
Il pourrait dans certains cas sembler plus naturel de choisir la méthode correspondant à la nature réelle de
l’instance (type effectif ).
Dans ces cas, il faut permettre la résolution dynamique des liens pour que le choix de la méthode à exécuter
se fait à l’exécution et en fonction de la nature réelle des instances
méthodes virtuelles
et
références/pointeurs
Mohamed
El Nabil
Abdellaoui SaïdSaidi 5
DÉCLARATION DES MÉTHODES VIRTUELLES
En C++, on indique au compilateur qu’une méthode peut faire l’objet d’une résolution dynamique des liens
en la déclarant comme virtuelle (mot clé virtual)
Cette déclaration doit se faire dans la classe la plus générale qui admet cette méthode (c’est-à-dire lors du
prototypage d’origine)
Les redéfinitions éventuelles dans les sous-classes seront aussi considérées comme virtuelles par transitivité.
Syntaxe :
Exemple :
Mohamed
El Nabil
Abdellaoui SaïdSaidi 6
RETOUR SUR L’EXEMPLE (1)
... il manque encore un petit quelque chose pour que ça marche !!!!
Mohamed
El Nabil
Abdellaoui SaïdSaidi 7
RETOUR SUR L’EXEMPLE (2)
Attention ! Il faut passer un par référence pour que la fonction faire_rencontrer agisse sur l’instance
d’origine !
Mohamed
El Nabil
Abdellaoui SaïdSaidi 8
VIRTUELLE / NON VIRTUELLE : EXEMPLE
class Mammifere {
public: Mammifere() { cout << "Un nouveau mammifère est né !" << endl; }
virtual ~Mammifere() {cout << "Un mammifère est en train de mourir :(" << endl; }
void manger() const {cout << "Miam... croumf !" << endl; }
virtual void avancer() const {cout << "Un grand pas pour l'humanité." << endl;}};
int main() {
Mammifere* lui(new Dauphin());
lui->avancer();
lui->manger();
delete lui;
return 0; }
Mohamed
El Nabil
Abdellaoui SaïdSaidi 9
VIRTUELLE / NON VIRTUELLE : EXEMPLE
Mohamed
El Nabil
Abdellaoui SaïdSaidi 10
C++11 OVERRIDE ET FINAL
En C++11 , le programmeur peut (optionnel) indiquer ses intentions lors de la (re)déclaration d’une
méthode :
le qualificatif override pour dire qu’il pense substituer/redéfinir une méthode virtuelle
le qualificatif final pour empêcher la substitution/redéfinition future d’une méthode virtuelle.
Exemple :
class A {
// ...
virtual void f1();
virtual void f2() const;
void f3(); // non virtuelle (oubli ?)
virtual void f4() final; // pas de redéfinition
};
class B : public A {
// ...
virtual void f1() override; // OK
virtual void fl() override; // Erreur faute de frappe : 1 <-> l
virtual void f2() override; // Erreur: a oublié le const
void f3() override; // Erreur: non virtuelle
virtual void f4(); // Erreur : f4 était final
};
Mohamed
El Nabil
Abdellaoui SaïdSaidi 11
LASSE ABSTRAITE
12
MÉTHODES VIRTUELLES PURES : PROBLÈME
Class FigureFermee
+ double surface ()
Mohamed
El Nabil
Abdellaoui SaïdSaidi 13
BESOIN DE MÉTHODES VIRTUELLES PURES : EXEMPLE
Exemple : class FigureFermee {
// ...
// difficile à définir à ce niveau !..
virtual double surface() const { ??? }
} };
main (){
Cercle C1; Triangle T1;
// surfaces
C1.surface();T1.surface();
} }
Mohamed
El Nabil
Abdellaoui SaïdSaidi 14
MÉTHODES VIRTUELLES PURES : AUTRE EXEMPLE (5)
La solution :
class Personnage {
// ...
// On n'affiche rien : corps de la méthode vide
virtual void afficher() const = 0;
// ...
};
Mohamed
El Nabil
Abdellaoui SaïdSaidi 15
MÉTHODES VIRTUELLES PURES : DÉFINITION ET SYNTAXE
Exemple :
class Personnage {
// ...
virtual void afficher() const = 0;
// ...
};
Mohamed
El Nabil
Abdellaoui SaïdSaidi 16
CLASSES ABSTRAITES
}; }; }
Une classe abstraite est une classe contenant au moins une méthode virtuelle pure.
Elle ne peut être instanciée
Ses sous-classes restent abstraites tant qu’elles ne fournissent pas les définitions de toutes les méthodes
virtuelles pures dont elles héritent.
Mohamed
El Nabil
Abdellaoui SaïdSaidi 17
CLASSES ABSTRAITES : EXEMPLE
Jeu jeu;
jeu.ajouter_personnage (new Guerrier(...));
S’ils ont oublié de définir la méthode afficher, le code ci-dessus génère une erreur de
compilation car on ne peut pas créer d’instance de Guerrier :
Mohamed
El Nabil
Abdellaoui SaïdSaidi 18
CLASSES ABSTRAITES : AUTRE EXEMPLE
Cercle n’est pas une classe abstraite Polygone reste par contre une classe abstraite
Mohamed
El Nabil
Abdellaoui SaïdSaidi 19
MART OINTERS
20
Introduction
Les pointeurs à la C (build-in pointers) : les plus puissants (peuvent tout faire) mais
les plus dangereux.
C++11, les pointeurs intelligents (smart pointers) : gérés par le programmeur; mais
avec garde-fous. Il en existe 3 : unique_ptr, shared_ptr, weak_ptr (avec
#include<memory>)
Mohamed
El Nabil
Abdellaoui SaïdSaidi 21
Les références
Une référence est un autre nom pour un objet existant, un synonyme, un alias. Une référence
permet donc de désigner un objet indirectement. C’est exactement ce que l’on utilise lors d’un
passage par référence. La déclaration d’une référence se fait selon la syntaxe suivante :
Après une telle déclaration, nom_reference peut être utilisé partout où identificateur peut l’être
Exemple :
int val(1);
int& x(val);
Mohamed
El Nabil
Abdellaoui SaïdSaidi 22
Les références
Signification de l’opérateur = :
Sémantique de const :
int i(3);
const int& j(i); /* i et j sont les mêmes, on ne peut pas changer la valeur
Via j
* mais on peut le faire par ailleurs */
i=12; // NON
j=12;
// OUI, et j AUSSI vaut 12 !
Mohamed
El Nabil
Abdellaoui SaïdSaidi 23
Les Pointeurs
Un pointeur est une variable qui contient l’adresse d’un autre objet informatique.
Mohamed
El Nabil
Abdellaoui SaïdSaidi 24
Les Pointeurs
C++ possède deux opérateurs particuliers en relation avec les pointeurs : & et *.
& est l’opérateur qui : retourne l’adresse mémoire de la valeur d’une variable
Si x est de type type, &x est de type type* (pointeur sur type).
Exemple :
int x(3);
int* px(nullptr);
px = &x;
* est l’opérateur qui retourne la valeur pointée par une variable pointeur.
Si px est de type type*, (*px) est la valeur de type type pointée par px.
Exemple :
Mohamed
El Nabil
Abdellaoui SaïdSaidi 25
Les Pointeurs
Type& id est une référence sur une variable id &id est l’adresse de la variable id par exemple en
dans le passage par référence d’une fonction affectation d’un pointeur.
Type* id déclare une variable id comme un *id (ou id est un pointeur ) représente le contenu
pointeur sur un type de base type de l’endroit pointé par id
Mohamed
El Nabil
Abdellaoui SaïdSaidi 26
Unique_ptr
unique_ptr pointent sur une zone mémoire n’ayant qu’un seul pointeur (‘un seul propriétaire’).
==> évite les confusions
Ne peut pas être copié mais peut être ‘’déplacé’’, ‘’transmis’’ plus loin
Note : si on veut libérer un unique_ptr avant le garbage collector (c’est-à-dire faire le delete nous
même), on peut utiliser la fonction spécifique reset() :
Exemple :
#include <memory>
//…
unique_ptr<int> px(new int(20));
//…
cout << *px << endl;
Mohamed
El Nabil
Abdellaoui SaïdSaidi 27
OLLECTION HÉTÉROGÈNE
&
OINTOR OLLECTIOS
28
ECTOR ARRAY
29
Les tableaux en C++
En C++, on utilise :
NON OUI
Dans un premier temps, nous allons nous intéresser aux tableaux dynamiques (vector)
Viendront ensuite les tableaux de taille fixe (array)
Mohamed
El Nabil
Abdellaoui SaïdSaidi 30
Les tableaux en C++
Un tableau dynamique, est une collection de données homogènes, dont le nombre peut changer au
cours du déroulement du programme, par exemple lorsqu’on ajoute ou retire des éléments au/du tableau.
Les tableaux dynamiques sont définis en C++ par le biais du type : vector
Pour les utiliser, il faut tout d’abord importer les définitions associées à l’aide d’un include :
#include <vector>
où identificateur est le nom du tableau et type correspond au type des éléments du tableau.
Exemple :
#include <vector>
vector<int>tableau;
type des éléments peut être n’importe quel type C++ valide
Exemple (à ne pas suivre !) d’erreur classique :
Mohamed
El Nabil
Abdellaoui SaïdSaidi 31
Initialisation d’un tableau dynamique
En C++11, il y a 5 façons d’initialiser un tableau dynamique :
1. vide
vector <int> tab;
3. avec une taille initiale donnée et tous les éléments à une même valeur donnée
Mohamed
El Nabil
Abdellaoui SaïdSaidi 32
Itération sur un tableau (C++11)
Si on souhaite parcourir les éléments du tableau sans faire des modifications :
for (auto nom_de_variable : tableau)
Exemples :
Mohamed
El Nabil
Abdellaoui SaïdSaidi 33
Fonctions spécifiques
Quelques fonctions disponibles pour un tableau dynamique nommé tableau, de type vector<type> :
size() : renvoie la taille de tableau (type de retour : size_t)
front() : renvoie une référence au 1er élément
tableau.front() est donc équivalent à tableau[0]
back() : renvoie une référence au dernier élément.
tableau.back() est donc équivalent à tableau [tableau.size()-1]
empty() : détermine si tableau est vide ou non (bool).
clear() :supprime tous les éléments de tableau (et le transforme donc en
un tableau vide). Pas de (type de) retour.
pop_back() : supprime le dernier élément de tableau. Pas de retour.
push_back(Val) : ajoute un nouvel élément de valeur Val à la fin de tableau. Pas de retour.
Mohamed
El Nabil
Abdellaoui SaïdSaidi 34
push_back et pop_back
6,7
Mohamed
El Nabil
Abdellaoui SaïdSaidi 35
Les tableaux multidimensionnels
Exemple :
tab[i] est donc un « vector<int> », c’est-à-dire un tableau dynamique d’entiers (qui, au départ, en
contient 6)
Mohamed
El Nabil
Abdellaoui SaïdSaidi 36
Les tableaux multidimensionnels
Mais attention ! Un vector<vector<int>> n’est pas une matrice, mais un tableau dynamique de
tableaux dynamiques d’entiers (pas nécessairement tous de la même taille !).
tableau[][J]
0 1 2 3 42
4 5 6
tableau[i]
tableau[2][1]
7 8
9 0 1
tableau[2] : 7 8
Mohamed
El Nabil
Abdellaoui SaïdSaidi 37
Déclaration d’un tableau de taille fixe
En C++11 , le type « tableau de taille fixe » est défini dans la bibliothèque array.
Pour les utiliser, il faut ajouter en début de programme :
#include <array>
où identificateur est le nom du tableau, type correspond au type des éléments du tableau et taille est
le nombre d’éléments que contient le tableau. Ce nombre doit être connu au moment où on écrit le
programme ( sinon vector)
Exemple :
#include <array>
...
array<double,3>vecteur_3d;
Mohamed
El Nabil
Abdellaoui SaïdSaidi 38
Déclaration d’un tableau de taille fixe
Comme pour les tableaux dynamiques, un tableau de taille fixe peut être initialisé directement
lors de sa déclaration :
array<type, taille> identificateur({val1, ... , val});
ou
Exemple :
Mohamed
El Nabil
Abdellaoui SaïdSaidi 39
Pour résumer
tab[i][j]
Tab.size()
for (auto element : tab)
for (auto& element : tab)
Tab.push_back(x); -
Tab.pop_back(); -
vector<vector<int>> array<array<int,3>,4>
tableau( { {0,1,2,3,42}, matrice= { 0,1,2,
{4,5,6}, 3,4,5,
{7,8}, 6,7,8,
{9,0,1}} ); 9,0,1 };
Mohamed
El Nabil
Abdellaoui SaïdSaidi 40
Polymorphisme
Un exemple :
Mohamed
El Nabil
Abdellaoui SaïdSaidi 41
Collections
class Jeu {
public:
void afficher() const;
void ajouter_personnage(const Personnage&);
private:
vector<Personnage> personnages;
};
Les instances contenues dans l’attribut personnages font partie d’une même hiérarchie de classe, mais
sont de nature hétérogène (Guerrier, Magicien, ...).
On pourrait par exemple vouloir que, si personnages[i] est un guerrier, la méthode
personnages[i].afficher() soit bien celle de la sous-classe Guerrier.
Problème : Si l’on veut une collection avec comportement polymorphique des éléments, il faut une
collection de pointeurs ou de références
Mohamed
El Nabil
Abdellaoui SaïdSaidi 42
Collections
Personnages :
class Jeu {
private : vector<Personnage> personnages;
public :
void ajouter_personnage(const Personnage& per){
Personnages.push_back(per);
}
Mohamed
El Nabil
Abdellaoui SaïdSaidi 43
Collections
Personnages :
class Jeu {
private : vector<Personnage> personnages;
public :
void ajouter_personnage(const Personnage& per){
Personnages.push_back(per);
}
Mohamed
El Nabil
Abdellaoui SaïdSaidi 44
Collection de pointeurs
Notez que donc seuls les pointeurs, c’est-à-dire les adresses des instances, sont stockées dans la
collections, et non plus les instances elles-mêmes :
….
Mohamed
El Nabil
Abdellaoui SaïdSaidi 45
Exemple complet : classes
On aurait donc :
class Jeu {
public :
Void afficher() const;
Void ajouter_personnage(Personnage *);
private :
Vector<unique_ptr<Personnage>> personnages;
};
. Jeu jeu;
Jeu.ajouter_personnage(new Guerrier(…));
Mohamed
El Nabil
Abdellaoui SaïdSaidi 46
Collections
Personnages :
class Jeu {
private : vector<unique_ptr<Personnage>> personnages;
public :
void ajouter_personnage(const Personnage* per){
if(per!= nullptr)
Personnages.push_back(<unique_ptr<Personnage>> per);
}
Mohamed
El Nabil
Abdellaoui SaïdSaidi 47
Pointeur et intégrité des données
….
….
Guerrier Magicien Guerrier Guerrier
Attention !! La co-existence des pointeurs et des éléments pointés n’est cependant pas du tout
garantie ! Au programmeur de ne pas faire de bêtises.
Mohamed
El Nabil
Abdellaoui SaïdSaidi 48
Pointeurs et intégrité des données : mauvais exemple
La fonction creer_magicien ajoute un nouveau magicien au jeu mon_jeu, mais par le biais d’une
variable locale (bouh !)
Une fois l’exécution de creer_magicien terminée, la variable locale est détruite !!
Attention !! le pointeur stocké dans le vecteur personnages existe toujours….
Mohamed
El Nabil
Abdellaoui SaïdSaidi 49
Allocation / désallocation dynamique
La solution à ce problème est que l’utilisateur alloue dynamiquement une portion de mémoire qui
sera préservée après la fin du bloc où l’on crée l’instance.
Exemple
Grâce à l’utilisation de new, la mémoire allouée dynamiquement pour le magicien créé dans
creer_magicien est préservée à la fin de l’exécution de cette fonction.
Mohamed
El Nabil
Abdellaoui SaïdSaidi 50
Collection Pointeur
class Jeu {
private : vector<unique_ptr<Personnage>> personnages;
public : void ajouter_personnage(const Personnage* per){
if(per!= nullptr)
Personnages.push_back(<unique_ptr<Personnage>> per);
}
void afficher() const { for(auto const& element : personnages)
{element->Affiche(); }
}
class Jeu {
private : vector<Personnage*> personnages;
public :
void ajouter_personnage(const Personnage* per){
if(per!= nullptr)
Personnages.push_back(per);
}
void afficher() const { for(auto const& element : personnages)
{element->Affiche(); }
}
Mohamed
El Nabil
Abdellaoui SaïdSaidi 51