Ecrit le 18-07-2007 (5698 hits) ... section C++          Template C++ par l'exemple                        Un exemple classique de l'intérêt des classes Template    C++ (dont le principe a été repris dans la dernière    version de Java), serait la classe représentant une pile, dont on aurait    besoin pour réaliser des piles d'entiers et des piles de chaînes.                        On pourrait les implémenter comme ci-dessous. L'implémentation    n'est pas très générique, pas très robuste, mais    c'est pour l'exemple.                                                        class IntStack {
         public:
            IntStack() { top = -1; }
            void push(int i)
               { st[++top] = i; }
            int pop()
               { return st[top--]; }
         private:
            int top;
            int st[100];
         };    |                              class StringStack {
         public:
            StringStack() { top = -1; }
            void push(string i)
               { st[++top] = i; }
            string pop()
               { return st[top--]; }
         private:
            int top;
            string st[100];
         };    |                                            Le programme principal (main) utiliserait ces classes comme ci-dessous:          {mostip}    IntStack ii;  
       StringStack ss;  
       ii.push(25);  
       ss.push("Hello"); {/mostip}          Si on note que la seule différence entre ces classes (outre le nom    de la classe) est le type des données qui sont mises    dans la pile.                             C++ permet de définir une classe en fonction d'un type de générique,    c'est à dire paramétrable, ce qui permet de représenter    une pile de n'importe quel type possible (y compris défini par l'utilisateur    ). La déclaration ressemblerait à ceci :                                                                   #ifndef STACK_H
        #define STACK_H
        template <class T> class Stack {
        public:
           Stack() { top = -1; }
           void push(T i)
              { st[++top] = i; }
           T pop()
              { return st[top--]; }
        private:
           int top;
           T st[100];
        };
        
        #endif       |                                       Le T représente le type générique de la pile, à préciser à l'utilisation entre des symboles "".    
 On voit que le code de la class diffère peu, elle dépend maintenant d'un type T indéfini.   Le programme principal déclarerait et utiliserait les piles comme suit    :           {mostip}  
      Stack<int> ii; 
      Stack<string> ss; 
      ii.push(25); 
      ss.push("Hello"); 
      {/mostip}  Il n'y a jamais de fichier d'implémentation (*.cpp) pour    une classe de template (on dit aussi "patron de classe"). Toutes les    méthodes membres doivent être déclarées dans le fichier    d'en-tête (*.h).                       Conclusion           Les templates sont très pratiques, j'en parle car on les rencontre souvent,    par exemple quand on utilise Corba.                        Solutions alternatives:                         - pré-procésseur (un #define paramétré) - pas        très joli mais comparable.     
                      - Utilisation d'une référence générique ( void*,        Object ) + cast à tout va !     
                      - polymorphisme associé à de l'héritage multiple !!!     
                                   De mon point de vue, c'est une facilité qui peut malheureusement amener un  mauvais design d'application, dans le cas où il remplace un vrai  polymorphisme associé à de l'héritage multiple. On ne devrait les utiliser que dans le cas de classes utilitaires pour lesquelles la performance maximale est requise.                         			 |