• Aucun résultat trouvé

Tout comme c’est le cas pour les fonctions, il est possible de définir des modèles de classes. De tels modèles servent à créer des types personnalisés qui sont paramétrés par d’autres types.

Création d’un modèle de classe

Un modèle de classe est créé de la manière suivante :

template <class T1, …, class Tn> class NomClasse {

// Définition de la classe };

• template sert indiquer qu’il s’agit de la création de modèle.

• < .. .. .. > désigne la zone de déclaration du ou des paramètres de type qui seront utilisés par le modèle de la classe. Dans cette zone il est également possible de mentionner directement des types concrets qui seront également utilisée par la classe.

• class Ti est une déclaration d’un paramètre de type qui porte dans le présent cas le nom Ti. un modèle peut toujours utiliser plusieurs paramètres de type. Ces derniers sont déclarés chacun avec le mot réservé class et séparés par des virgules.

• NomClasse désigne le nom de la classe à créer. Exemple :

Cet exemple montre la création d’un modèle de classe servant à représenter des points.

template <class T> class Point {

T x; T y;

Point(T abs, T ord) ; void Afficher(); };

Définition des méthodes d’un modèle de classe

Les méthodes d’un modèle de classe sont des modèles de fonctions avec les mêmes paramètres de type que la classe. Ces méthodes peuvent être définies à l’intérieur ou à l’extérieur de la classe.

Définition à l’intérieur de la classe (en ligne)

La définition se fait dans ce cas d’une manière classique comme pour les méthodes usuelles. Définition à l’extérieur de la classe

La définition à l’extérieur de la classe utilise une syntaxe un peu différente que dans le cas classique. Cette syntaxe rappelle au compilateur qu’il s’agit d’un modèle et mentionne les paramètres de types qui sont utilisés. Cette syntaxe se présente comme suit :

Les modèles Programmation orientée objet (C++) _________________________________________________________________________________________________________________ template<class T> NomClasse<T>::NomMethode(Paramètres) { // Définition de la méthode }

L’exemple suivant donne une illustration de ces deux possibilités de définition. Exemple :

template <class T> class Point {

T x; T y;

// Exemple de définition à l’intérieur de la classe Point(T abs, T ord)

{ x = abs ; y = ord ; } void Afficher(); };

// Exemple de définition à l’extérieur de la classe template <class T> void Point<T>::Afficher()

{

cout<<"Abs : "<<x; cout<<"Ord : "<<y; }

Utilisation d’un modèle de classe

Lors de l’appel d’un modèle de fonctions, le compilateur se base sur la signature pour déterminer le type effectif des arguments utilisés. Cette identification automatique par le compilateur n’est pas possible lorsqu’il s’agit d’utiliser un modèle de classe pour instancier un objet. C’est pourquoi la spécification de la classe dans ce cas doit être accompagnée explicitement du (des) types effectif(s) utilisé(s). La syntaxe d’instanciation se présente de ce fait comme suit :

NomModèleClasse <TypeEffectif> NomObjet(args du constructeur);

Exemple : int main() { Point<int> P1(5,3); Point<double> P2(2.4, 3.7); P1.Afficher(); P2.Afficher(); return 0 ; }

Les modèles Programmation orientée objet (C++) _________________________________________________________________________________________________________________

Remarque :

Théoriquement, il est possible d’instancier la classe Point avec n’importe quel type. Toutefois, sur un plan pratique les types à utiliser doivent être compatibles avec la signification de cette classe (types numériques). Le bon usage du modèle reste alors et toujours l’affaire de l’utilisateur de ce dernier.

Classe générique avec des paramètres de type et des paramètres classiques

En plus des paramètres de type, il est tout à fait possible d’utiliser des paramètres classiques ayant des types concrets et ce lors de la création d’un modèle de classe. L’exemple suivant montre un exemple de ce type de situation.

Exemple :

La classe Tableau représente des tableaux d’éléments d’une manière générale indépendamment du type de ces éléments. Cette classe prend deux arguments, le premier représente le type des éléments à manipuler et le second représente la dimension du tableau. La définition de cette classe se présente comme suit :

template <class T, int N> class Tableau {

T Elements[N];

T& operator[](int Index) {

return Elements[Index]; }

};

Le code suivant montre l’utilisation du modèle Tableau :

int main() {

Tableau<int, 4> T1;

cout<<"Saisie des éléments du tableau\n"; for(int i=0;i<4;i++)

{

cout<<"Donner un élément : "; cin>>T1[i];

}

cout<<"Affichage des éléments du tableau\n"; for(int i=0;i<4;i++) cout<<T1[i]<<' '; system("PAUSE"); return 0; } Remarques :

• Cet exemple montre entre autres qu’il est tout à fait possible de créer un tableau non dynamique avec une dimension paramétrée. En effet au moment de la création de la classe concrète à partir du modèle, le préprocesseur va dans le cas présent remplacer

l’instruction : T Element[N]; par int Element[4]; qui est une instruction acceptée

Les modèles Programmation orientée objet (C++) _________________________________________________________________________________________________________________

• La dimension du tableau aurait pu être passée comme argument du constructeur ce qui éviterait ainsi l’utilisation du paramètre int dans le modèle de la classe. Mais une telle option ne permettrait pas de créer le tableau sur la pile d’exécution. Seul serait possible dans ce cas l’allocation dynamique.

Valeur par défaut des paramètres d’un patron de classe

Il est possible de spécifier des valeurs par défaut aux paramètres d’une classe générique. La règle qui régit cette spécification est semblable à celle utilisée avec les fonctions usuelles. Exemple :

template <class T=int, int N=10> class Tableau {

T Elements[N] ;

T& operator[](int Index) {

return Elements[Index] ; }

} ;

Les instructions suivantes montrent des exemples d’utilisation du modèle Tableau ainsi déclaré.

Tableau<float, 4> ; // Tableau de 4 réels simples

Tableau<Complexe> ; // Tableau de 10 objets de type Complexe. Tableau<> ; // Tableau de 10 entiers.

Remarque :

La notion de paramètre par défaut n’a pas de signification pour les modèles de fonctions.

Spécialisation d’un modèle de classe

La possibilité de spécialisation existe également avec les modèles des classes comme c’est le cas avec les fonctions. Elle peut être utile afin d’adapter le modèle à certaines situations particulières. La spécialisation peut concerner une méthode du modèle de classe comme elle peut concerner la classe en entier.

Spécialisation d’une méthode

La spécialisation d’une méthode d’un modèle de classe se fait selon la syntaxe suivante :

TypeRetour NomClasse<TypeEffectif>::NomMethode(Paramètres) {

// Définition de la spécialisation de la méthode }

L’exemple suivant montre une spécialisation de la méthode Afficher du modèle Point pour qu’elle affiche convenablement les coordonnées dans le cas où le type effectif utilisé est le

Les modèles Programmation orientée objet (C++) _________________________________________________________________________________________________________________

// Définition de la méthode Afficher pour le modèle de classe template <class T> class Point

{

T x; T y;

Point(T abs, T ord) {x= abs ; y ord ;} void Afficher(); };

template <class T> void Point<T>::Afficher() {

cout<<"Abs : "<<x<<endl; cout<<"Ord : "<<y<<endl; }

// Spécialisation de la méthode Afficher pour les caractères void Point<char> ::Afficher()

{

cout<<"Abs : "<<(int)x<<endl; cout<<"Ord : "<<(int)y<<endl; }

// Utilisation de la classe Point int main()

{

Point<int> P1(5,9); Point<char> P2('a','b');

P1.Afficher(); // Afficher générée par le compilateur P2.Afficher(); // Afficher spécialisée pour char return 0;

}

Spécialisation d’une classe

Il est tout à fait possible de spécialiser la classe dans sa totalité. Dans ce cas la nouvelle spécialisation doit suivre la définition du modèle tout en indiquant le ou les types concrets qu’elle utilise. La syntaxe à adopter est la suivante :

class Nomclasse<TypeConcret> {

// Nouvelle définition }

Exemple :

La spécialisation de la classe Point pour le type char doit être définie de la manière suivante :

class Point<char> {

// Nouvelle spécialisation }

Les modèles Programmation orientée objet (C++) _________________________________________________________________________________________________________________

Remarque :

Les modèles constituent un outil puissant permettant de réduire considérablement le code. Toutefois cet outil doit être utilisé avec précaution vu l’existence de situations pouvant mener vers des ambiguïtés d’interprétation au moment de la compilation. Par ailleurs, la génération du code faite par le compilateur est réalisée d’une manière automatique et ne donne aucune garantie sur l’adaptation des traitements aux données. C’est l’utilisateur du modèle qui doit toujours veiller sur cette adaptation et l’assurer éventuellement par des spécialisations.

La gestion des exceptions Programmation orientée objet (C++) _________________________________________________________________________________________________________________

La gestion des exceptions