Chapitre X Modèles
Les modèles (polymorphisme de compilation) Comme l’héritage ou le polymorphisme, les templates (ou modèles) représentent une technique favorisant la réutilisation et la spécialisation des outils C++. Surcharge de fonctions Opérations similaires qui exigent une logique de programme différente sur des types de données différents. Rôle Permettent de définir des traitements identiques et applicables à plusieurs types de données. Utilisent un type paramétré (ou fictif) qui représente le type de donnée qui sera choisi (ou instancié) à l’utilisation du modèle. S’appliquent aux: fonctions classes fonctions membres des classes modèles. Rôle d’une fonction modèle Permet de définir une famille de fonctions qui partage le même traitement pour des types de données différents.
Les modèles Fournit la même facilité que les fonctions modèles en donnant la possibilité de paramétrer un type de donnée aussi bien pour ses données que pour ses fonctions membres. Rôle d’une classe modèle Le type paramétré peut être utilisé pour les données membres des classes, comme paramètre ou comme valeur renvoyée par les fonctions. Extrait de programme int Min(int a, int b) { if (a <= b) return a; else return b; } float Min(float a, float b) { if (a <= b) return a; else return b; } Chapitre X - Modèles
que le comportement ne change pas en fonction du type Les modèles Ces fonctions réalisent le même traitement pour des types de données différents (short, float, double, etc.) Une fonction modèle permettrait de définir une seule et unique fonction s’appliquant à tous les types de données primaires. Un modèle peut utiliser un ou plusieurs types paramétrés qui seront instanciés par un type réel à l’utilisation du modèle. Exemple Nous pourrions écrire un seul modèle de fonction pour une fonction de tri de tableau et laisser le C++ générer des fonctions de modèle distinctes qui trieraient, l’une un tableau d’int, un autre un tableau de float, … Les modèles sont utiles pour toutes les abstractions généralisant un type arbitraire c’est-à-dire, que le comportement ne change pas en fonction du type Chapitre X - Modèles
Les fonctions modèles Une fonction modèle est déclarée en utilisant un ou des types de données paramétrés. Ces types seront connus au moment de l’appel de la fonction. Nom d’un type paramétré utilisé par le modèle syntaxe template <class type_paramétré, …., class type_paramétré> type_de_retour Nom_de_la_fonction(arguments) { …………… } Il ne s’agit pas des arguments de la fonction. La fonction déclarée peut utiliser les types fictifs comme type de retour, comme paramètres (arguments) ou dans le corps de la fonction. La déclaration du modèle et la définition de la fonction peuvent être sur la même ligne. Un ensemble de types paramétriques différents génèrent un code de fonction différent : Min<int> vs Min<float>. En revanche, 2 emplois de la fonction Min<int> partageront la même fonction.
Les fonctions modèles Extrait de programme template <class type_primaire> type_primaire Min(type_primaire a, type_primaire b) { if (a <= b) return a; else return b; } Cette fonction modèle peut être employée avec tous les types de données à la condition que le traitement réalisé par la fonction soit supporté par ce type. Par exemple, le type de donnée doit supporter l’opérateur de comparaison <=. Autrement, l’opérateur doit être redéfini. À retrouver dans la spécification. Il n’existe pas de syntaxe particulière pour appeler une fonction modèle. int a, b, c; float d, e, f; ….. c = Min(a, b); f = Min(d, e); Le type associé à chaque paramètre du modèle est déduit des arguments lors de l’appel. On ne peut mélanger les types comme par exemple, f = Min(a, d); Mais on peut spécifier explicitement le type paramétrique: float g = Min<float>(2, 3.13); // l’entier est converti.
Les fonctions modèles class Auto { protected: char Reference[20+1]; Exemple I class Auto { protected: char Reference[20+1]; char Marque[20+1]; int Prix_vente; public: Auto(char * Ref = "", char * M = "", int Prix = 0); /* Permet de créer un objet Auto. Pré - Nil. Post - L'objet Auto est créé en tenant compte des valeurs par défaut pour les différents arguments. */ Chapitre X - Modèles
Les fonctions modèles void Init_Prix_vente(int P); /* Initialise le prix de vente. Pré - L'objet Auto est créé. Post - Le prix de vente est conservé. */ int Acces_Prix_vente(); /* Fournit le prix de vente. Post - Retourne le prix de vente de l'auto. */ friend bool operator <= (Auto A, Auto B); /* Compare le prix de vente des autos A et B. Pré - Les objets A et B sont créés. Post - Retourne true si le prix de vente de A est <= au prix de vente de B. */ }; Chapitre X - Modèles
Les fonctions modèles class Auto_usagee : public Auto {protected: char Nom_Ancien_Proprietaire[20+1]; char Prenom_Ancien_Proprietaire[20+1]; int Cout_achat; public: Auto_usagee(char * Ref = "", char * M = "", int Prix = 0, int Cout = 0, char * Nom = "", char * Prenom = ""); /* Permet de créer un objet Auto_usagee. Pré - Nil. Post - L'objet Auto_usagee est créé en tenant compte des valeurs par défaut pour les différents arguments.*/ Chapitre X - Modèles
Les fonctions modèles void Init_Cout_achat(int C); /* Initialise le coût d'achat. Pré - L'objet Auto_usagee est créé. Post - Le coût d'achat est conservé. */ int Acces_Cout_achat(); /* Fournit le coût d'achat. Post - Retourne le coût d'achat de l'auto usagée. */ }; Chapitre X - Modèles
Les fonctions modèles #include <iostream.h> #include "Auto.h" Le fichier Auto.cpp reste inchangé. Le fichier Application Auto.cpp devient : #include <iostream.h> #include "Auto.h" template <class type_primaire> type_primaire Min(type_primaire A, type_primaire B) { return (a <= b) ? a : b; } bool operator <= (Auto A, Auto B) return (A.Prix_vente <= B.Prix_vente) ? true : false; Chapitre X - Modèles
Les fonctions modèles int main() { Auto A("R025", "Honda Civic", 22500); Auto_usagee B("C25", "Toyota", 18500, 12550, "Duval", "Luc"); Auto_usagee C("D123", "Capri"); cout << A.Acces_Prix_vente() << endl; cout << B.Acces_Prix_vente() << endl; cout << B.Acces_Cout_achat() << endl; cout << C.Acces_Prix_vente() << endl; cout << C.Acces_Cout_achat() << endl; if (B <= A) cout << "B coute moins cher que A " << endl; if (B <= C) cout << "B coute moins cher que C " << endl; return 0; } Chapitre X - Modèles
Les fonctions modèles Exemple II #include <iostream.h> template <class T> void ImpressionTableau( const T * tableau, const int compte) { for ( int i = 0; i < compte; i++ ) cout << tableau[ i ] << " " ; cout << endl; } Chapitre X - Modèles
Les fonctions modèles Exemple II void main() { const int Nbentiers = 5; int a[Nbentiers] = { 1, 2, 3, 4, 5 }; ImpressionTableau(a, Nbentiers); const int Nbreels = 7; int b[Nbreels] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 }; ImpressionTableau(b, Nbreels); const int Nbcaracteres = 8; int c[Nbcaracteres] = { "BONJOUR" }; ImpressionTableau(c, Nbcaracteres); } 1 2 3 4 5 1.1 2.2 3.3 4.4 5.5 6.6 7.7 B O N J O U R Chapitre X - Modèles
Surcharger des fonctions modèles Une fonction modèle peut être surchargée de plusieurs façons : Créer d’autres modèles de fonctions qui portent le même nom de fonction mais qui utilisent des paramètres différents. La fonction modèle ImpressionTableau pourrait être surchargé par une autre fonction modèle ImpressionTableau qui accepte les paramètres supplémentaires indiceInf et indiceSup, destinés à indiquer la portion du tableau à imprimer. Ex. : Créer d’autres fonctions qui ne sont pas basées sur le modèle du même nom et qui utilisent des arguments de fonction différents. La fonction modèle ImpressionTableau pourrait être surchargé par une autre fonction ImpressionTableau qui ne respecte pas le modèle et qui imprime spécifiquement un tableau de chaînes de caractères sous une forme particulière. Ex. : Lorsque le compilateur doit choisir entre 2 fonctions ayant les mêmes arguments, la fonction non modèle est choisie.
Les classes modèles Nom d’un type paramétré utilisé par le modèle syntaxe template <class type_paramétré, …., class type_paramétré> class Nom_classe { …………… }; Les types fictifs spécifiés peuvent être utilisés pour définir des données ou par les fonctions membres de la classe. idem Syntaxe Définition du corps des fonctions membres Idem sans le mot class idem template <class type_paramétré, …., class type_paramétré> type_de_retour Nom_classe<type_paramétré, …., type paramétré>::Nom_fonction(arguments) { …………… }; Note : Le mot-clé class peut être remplacé par typename. Chapitre X - Modèles
Les classes modèles Une classe modèle peut également contenir des fonctions membres qui n’utilisent pas les types paramétrés. Le corps de la fonction doit respecter quand même la contrainte liée au nom complet de la fonction membre. Exemple tiré de Stéphane Dupin, Le langage C++, pp. 362-365, 1999. template <class T> class Tableau { private: T Valeurs[10]; int indice; public: Tableau(); void Ajouter(T v); T Renvoyer(int i); int NombreElement(); }; Chapitre X - Modèles
Les classes modèles template <class T> template <class T> void Tableau<T>::Ajouter(T v) { if (indice < 10) Valeurs[indice] = v; indice++; } else cout << "Tableau plein" << endl; template <class T> T Tableau<T>::Renvoyer(int i) { if (i < indice) return Valeurs[i]; else return 0; } La contrainte liée au nom complet des fonctions des classes modèles s’appliquent également aux méthodes qui n’utilisent pas le type paramétré. Chapitre X - Modèles
Les classes modèles template <class T> Tableau<T>::Tableau() { indice = 0; } int Tableau<T>::NombreElement() return indice; Autre exemple : Un modèle de classe Pile peut ainsi devenir la base de la création de nombreuses classes Pile (Pile de char, Pile d’employes, …).
Création d’objets statiques ou dynamiques Il faut explicitement indiquer la valeur des types paramétrés au moment de la création des objets de cette classe. Tableau<int> TabEntiers; ……. Tableau<char> * pTabCaracteres; pTabCaracteres = new Tableau<char>; delete pTabCaracteres; Mis à part leurs créations, les objets de type modèle s’utilisent de la même manière que n’importe quel objet. Création d’un alias de nom long à l’aide de typedef : typedef Tableau<int> tabint; tabint TabEntiers; Chapitre X - Modèles
Exemple #include <iostream.h> template <typename T> class Couple { private : T premier; T deuxieme; public : Couple(T a, T b); T Acces_premier() const; T Acces_deuxieme() const; }; Couple <T>::Couple(T a, T b) premier = a; deuxieme = b; } T Couple <T>::Acces_premier() const return premier; Chapitre X - Modèles
Exemple (suite) template <typename T> T Couple <T>::Acces_deuxieme() const { return deuxieme; } Couple<T> minmax(T * v, int L) T min = v[0]; T max = v[0]; for (int i = 0; i < L; i++) if (v[i] < min) min = v[i]; if (v[i] > max) max = v[i]; }; return Couple<int>(min, max); void main() int tab[10] = {3, 2, 5, 6, 9, 7, 1, 8, 10, 4}; Couple<int> C = minmax(tab, 10); cout << C.Acces_premier() << " " << C.Acces_deuxieme() << endl; Chapitre X - Modèles
Les classes et les fonctions modèles template <class type_numerique> class Vecteur { /* Spécification fonctionnelle de la classe " Vecteur " Composantes : Chaque composante est une valeur numérique. Les composantes sont de même type. Structure : Il existe une relation linéaire (structure) entre les composantes d'un vecteur. */ Chapitre X - Modèles
Les classes et les fonctions modèles protected: int n; /* Longueur du vecteur */ type_numerique * v; /* Pointeur vers le vecteur de */ /* composantes. */ public: Vecteur(int L = 3); /* Constructeur permettant de créer un vecteur de longueur L > 0 (3 par défaut) dont les composantes sont des valeurs numériques. Pré - L > 0. Post - Le vecteur de longueur L est le vecteur nul.*/ Chapitre X - Modèles
Les classes et les fonctions modèles type_numerique & operator[] (int i); /* Donne accès à la ième composante du vecteur. Pré - Le vecteur a déjà été créé et 1 <= i <= longueur du vecteur Post - Donne accès à la ième composante du vecteur. */ friend int dim(Vecteur P); /* Donne accès à la longueur du vecteur. Pré - Le vecteur a déjà été créé. Post - Retourne la longueur du vecteur. */ void Detruire_vecteur(); /* Permet de détruire le vecteur et de libérer l'espace correspondante. Post - Le vecteur n'existe plus. */ Chapitre X - Modèles
Les classes et les fonctions modèles type_numerique operator * (Vecteur P); /* Fournit le produit scalaire du vecteur courant avec le vecteur P où les composantes des 2 vecteurs sont de même type. Pré - Le vecteur courant et le vecteur P ont déjà été créés et sont de même longueur. Les éléments sont de même type. Post - Retourne le produit scalaire des 2 vecteurs. */ void operator * (type_numerique Lambda); /* Multiplie chaque composante du vecteur par le scalaire "Lambda" Pré - Le vecteur a déjà été créé. Le scalaire et les composantes du vecteur sont de même type. Post - Chaque composante du vecteur a été multipliée par "Lambda". */ Chapitre X - Modèles
Les classes et les fonctions modèles void operator += (Vecteur P); /* Permet d'additionner le vecteur P au vecteur courant. Les composantes des 2 vecteurs sont de même type. Pré - Le vecteur courant et le vecteur P ont déjà été créés et sont de même longueur. Post - Additionne P au vecteur courant. */ void operator -= (Vecteur P); /* Permet de soustraire le vecteur P du vecteur courant. Les Post - Soustrait P du vecteur courant. */ }; Chapitre X - Modèles
Les classes et les fonctions modèles Fichier « Calcul_vectoriel.cpp » #include <iostream.h> #include "Vecteur.h" template <class type_numerique> Vecteur<type_numerique>::Vecteur(int L):n(L) { int i; v = new type_numerique[n]; for (i = 0; i < n; i++) v[i] = 0; } Chapitre X - Modèles
Les classes et les fonctions modèles template <class type_numerique> type_numerique & Vecteur<type_numerique>::operator[](int i) { return v[i - 1]; } int dim(Vecteur<type_numerique> P) return P.n; Chapitre X - Modèles
Les classes et les fonctions modèles template <class type_numerique> void Vecteur<type_numerique>::Detruire_vecteur() { delete v; } type_numerique Vecteur<type_numerique>::operator * (Vecteur P) int i; type_numerique somme; somme = 0; for (i = 0; i < n; i++) somme = somme + P[i+1] * (*(v + i)); return somme; Chapitre X - Modèles
Les classes et les fonctions modèles template <class type_numerique> void Vecteur<type_numerique>::operator * (type_numerique Lambda) { for (int i = 0; i < n; i++) (*(v+i)) = (*(v+i)) * Lambda; } void Vecteur<type_numerique>::operator += (Vecteur P) (*(v+i)) = (*(v+i)) + P[i+1]; Chapitre X - Modèles
Les classes et les fonctions modèles template <class type_numerique> void Vecteur<type_numerique>::operator -= (Vecteur P) { for (int i = 0; i < n; i++) (*(v+i)) = (*(v+i)) - P[i+1]; } void main(void) int i; int L = 3; Vecteur<float> P; Vecteur<float> Q; Chapitre X - Modèles
Les classes et les fonctions modèles for (i=1; i <= L; i++) { P[i] = (float) i; Q[i] = 0.1f; } for (i=1; i <= L; i++) cout << P[i] << " ; » << Q[i] << " ; " << endl; cout << "Longueur du vecteur: " << dim(P); cout << "Produit scalaire : " << P * Q; Q * 0.2f; cout << "Produit scalaire : " << P * Q; P += Q; cout << "Produit scalaire : " << Q * P; P -= P; cout << "Produit scalaire : " << P * Q; Chapitre X - Modèles
Définition de paramètres en plus de types paramétrés En plus de spécifier les types paramétrés, vous pouvez utiliser la liste d’arguments d’un modèle pour définir des paramètres dont le type est figé. La valeur de ces arguments devra être passée à l’instance du modèle, exactement de la même manière que les valeurs des types paramétrés. Ainsi, la classe modèle dispose d’arguments qui peuvent être utilisés par les données et les fonctions membres de la classe. Comme les arguments des fonctions, ces variables peuvent avoir une valeur par défaut. Chapitre X - Modèles
Définition de paramètres en plus de types paramétrés template <class type_numerique, int n = 3> class Vecteur { /* Spécification fonctionnelle de la classe " Vecteur " Composantes : Chaque composante est une valeur numérique. Les composantes sont de même type. Structure : Il existe une relation linéaire (structure) entre les composantes d'un vecteur. */ Chapitre X - Modèles
Définition de paramètres en plus de types paramétrés protected: type_numerique v[n]; /* Un vecteur de composantes.*/ public: Vecteur(); /* Constructeur permettant de créer un vecteur de longueur n > 0 (3 par défaut) dont les composantes sont des valeurs numériques. Pré - n > 0. Post - Le vecteur de longueur n est le vecteur nul.*/ idem Chapitre X - Modèles
Définition de paramètres en plus de types paramétrés Fichier « Calcul_vectoriel.cpp » #include <iostream.h> #include "Vecteur.h" template <class type_numerique, int n> Vecteur<type_numerique, n>::Vecteur() { for (int i = 0; i < n; i++) v[i] = 0; } Chapitre X - Modèles
Définition de paramètres en plus de types paramétrés template <class type_numerique, int n> type_numerique & Vecteur<type_numerique, n>::operator[](int i) { return v[i - 1]; } int dim(Vecteur<type_numerique, n> P) return n; Chapitre X - Modèles
Définition de paramètres en plus de types paramétrés template <class type_numerique, int n> void Vecteur<type_numerique, n>::Detruire_vecteur() { delete v; } type_numerique Vecteur<type_numerique, n>::operator * (Vecteur P) int i; type_numerique somme; somme = 0; for (i = 0; i < n; i++) somme = somme + P[i+1] * (*(v + i)); return somme; etc. Chapitre X - Modèles
Définition de paramètres en plus de types paramétrés void main(void) { int i; const int L = 3; Vecteur<float> P; Vecteur<float, L> Q; } On peut spécifier la taille d’un vecteur au moment de la compilation. On pourrait aussi avoir les déclarations suivantes: Vecteur <double, 10> R; Vecteur <int> * pTabEntiers; pTabEntiers = new pTabEntiers<int, 12>; Chapitre X - Modèles
La classe Pile template <class element> class pile { /* Spécification fonctionnelle de la classe " pile ". Éléments : Chaque sommet de la pile renferme l'adresse d'un élément et non pas l'élément lui-même. Le type de chaque élément de la pile peut être quelconque. Structure : Les éléments sont reliés entre eux permettant de déterminer l'ordre d'arrivée des éléments dans la pile. */ Chapitre X - Modèles
La classe Pile protected: struct sommet_pile { element * pElement; struct sommet_pile *suivant; }; struct sommet_pile * pPile; public: void Creer_pile(); /* Permet de créer une pile vide. Pré - Nil. Post - La pile existe et est vide. */ Chapitre X - Modèles
La classe Pile void Inserer(element * pElement); /* Insérer l'adresse d'un élément dans la pile. Pré - La pile a déjà été créée et n'est pas pleine. Post - La pile renferme pElement et l'interprète comme étant l'adresse de l'élément le plus récent inséré dans la pile.*/ element * Enlever(); /* Enlever un élément de la pile. Pré - La pile a déjà été créée et n'est pas vide. Post - L'adresse de l'élément le plus récent inséré dans la pile est retourné; cet élément ne fait plus partie de la pile.*/ Chapitre X - Modèles
La classe Pile bool Pile_vide(); /* Vérifier si la pile est vide ou non. Pré - La pile a déjà été créée. Post - Si la pile ne possède aucun élément alors retourner true sinon retourner false. */ bool Pile_pleine(); /* Vérifier si la pile est pleine ou non. Post - Si la pile a atteint sa capacité maximale alors retourner vrai sinon retourner faux. */ Chapitre X - Modèles
La classe Pile void Vider_pile(); /* Vider la pile. Pré - La pile a déjà été créée. Post - La pile est vide. */ }; #include <iostream.h> #include "Pile.h" template<class element> void pile<element>::Creer_pile() { pPile = NULL; } Chapitre X - Modèles
La classe Pile template<class element> void pile<element>::Inserer(element * pElement) { struct sommet_pile *pe = new sommet_pile; (*pe).pElement = pElement; (*pe).suivant = pPile; pPile = pe; } Chapitre X - Modèles
La classe Pile template<class element> element * pile<element>::Enlever() { element * pElement; struct sommet_pile *pe = NULL; pElement = (*pPile).pElement; pe = pPile; pPile = (*pPile).suivant; delete(pe); return pElement; } Chapitre X - Modèles
La classe Pile template<class element> bool pile<element>::Pile_vide() { if (pPile == NULL ) return true; else return false; } bool pile<element>::Pile_pleine() /* Il n'y a aucune façon de tester si la liste chaînée est pleine i.e. s'il existe encore de l'espace disponible pour un autre sommet.*/ return false; Chapitre X - Modèles
La classe Pile template<class element> void pile<element>::Vider_pile() { element * pElement; while (Pile_vide() == false) pElement = Enlever(); } void main() int i=0, j=1, k=2; float a=0.0f, b=0.1f; char u = 'a'; pile<int> Pile_entiers; pile<float> Pile_reels; pile<char> Pile_caracteres; Chapitre X - Modèles
La classe Pile Pile_entiers.Creer_pile(); Pile_reels.Creer_pile(); Pile_caracteres.Creer_pile(); Pile_entiers.Inserer(&i); Pile_entiers.Inserer(&j); Pile_entiers.Inserer(&k); Pile_reels.Inserer(&a); Pile_reels.Inserer(&b); Pile_caracteres.Inserer(&u); cout << * Pile_entiers.Enlever(); cout << * Pile_entiers.Enlever(); cout << * Pile_entiers.Enlever(); cout << * Pile_reels.Enlever(); cout << * Pile_reels.Enlever(); cout << * Pile_caracteres.Enlever(); if ((Pile_entiers.Pile_vide() == true) &&(Pile_reels.Pile_vide() == true) && (Pile_caracteres.Pile_vide() == true)) cout << "Les 3 piles sont vides."; } pas de conversion Chapitre X - Modèles
Modèles et membres statiques Une classe modèle peut contenir des données et fonctions membres statiques. template <class T> class Salle_attente { public: static int Nb_chaises_disponibles; ………. }; int Salle_attente<T>::Nb_chaises_disponibles = 12; Ex.: Une donnée membre statique existe pour chaque instance du modèle. Tous les objets de type Salle_attente<Clients_Pharmacie> partagent la même variable statique et tous les objets de type Salle_attente<Clients_Dentiste> partagent la leur. Chapitre X - Modèles
Modèles et héritage Les modèles ne préservent pas l’héritage. Exemple : Même si Gestionnaire dérive de Employe, il n’y a aucune relation entre Vecteur<Gestionnaire> et Vecteur<Employe>. Les modèles et l’héritage se retrouvent de différentes façons : un modèle de classe (classe générique) dérivé d’une classe spécifique d’un modèle, un modèle de classe (classe générique) dérivé d’une classe non spécifique à un modèle, une classe spécifique d’un modèle dérivée d’un modèle de classe (classe générique), une classe non spécifique à un modèle dérivée d’un modèle de classe (classe générique). Chapitre X - Modèles
Modèles et amitié L’amitié peut être établie entre un modèle de classe et - une fonction globale, - une fonction membre d’une autre classe (laquelle peut être une classe spécifique à un modèle), - une classe toute entière (laquelle peut être une classe spécifique à un modèle). Chapitre X - Modèles
Modèles et amitié Exemple I Soit un modèle de classe pour la classe Essai, déclaré par : template <class T> class Essai une déclaration d’amitié de la forme friend void f(); fait de la fonction f une amie de toute classe spécifique au modèle de la classe Essai. Chapitre X - Modèles
Modèles et amitié Exemple II Soit un modèle de classe pour la classe Essai, déclaré par : template <class T> class Essai une déclaration d’amitié de la forme friend void g(Essai < T > & Obj); pour un type T particulier tel que float fait de la fonction g (Essai < float > & Obj) une amie de Essai< float > seulement. Chapitre X - Modèles
Modèles et amitié Exemple III Soit un modèle de classe pour la classe Essai, déclaré par : template <class T> class Essai une déclaration d’amitié de la forme friend void Autre::h(); fait de la fonction membre h de la classe Autre une amie de toute classe spécifique au modèle de la classe Essai. Chapitre X - Modèles
Modèles et amitié Exemple IV Soit un modèle de classe pour la classe Essai, déclaré par : template <class T> class Essai une déclaration d’amitié de la forme friend void Autre< T >::K(Essai< T > & Obj); pour un type T particulier tel que float, fait de la fonction membre Autre< float >::K(Essai< float > & Obj) une fonction amie de la seule classe spécifique de modèle Essai<float>. Chapitre X - Modèles
Modèles et amitié Exemple V Soit un modèle de classe pour la classe Essai, déclaré par : template <class T> class Essai une seconde classe Tentative peut être déclarée par friend class Tentative; rendant toute fonction membre de la classe Tentative amie de toute classe spécifique au modèle de classe Essai. Chapitre X - Modèles
Modèles et amitié Exemple VI Soit un modèle de classe pour la classe Essai, déclaré par : template <class T> class Essai une seconde classe Tentative peut être déclarée par friend class Tentative<T>; ensuite, lorsqu’une classe spécifique à la classe Essai est instanciée avec un type particulier de T tel que float, tous les membres de la classe Tentative<float> deviennent amis de la classe Essai<float>. Chapitre X - Modèles