Modèles C ++

Les modèles sont à la base de la programmation générique, qui implique l'écriture de code d'une manière indépendante de tout type particulier.

Un modèle est un plan ou une formule pour créer une classe générique ou une fonction. Les conteneurs de bibliothèque comme les itérateurs et les algorithmes sont des exemples de programmation générique et ont été développés en utilisant le concept de modèle.

Il existe une seule définition de chaque conteneur, telle que vector, mais nous pouvons définir de nombreux types de vecteurs différents, par exemple, vector <int> ou vector <string>.

Vous pouvez utiliser des modèles pour définir des fonctions ainsi que des classes, voyons comment ils fonctionnent -

Modèle de fonction

La forme générale d'une définition de fonction de modèle est affichée ici -

template <class type> ret-type func-name(parameter list) {
   // body of function
}

Ici, type est un nom d'espace réservé pour un type de données utilisé par la fonction. Ce nom peut être utilisé dans la définition de fonction.

Voici l'exemple d'un modèle de fonction qui renvoie le maximum de deux valeurs -

#include <iostream>
#include <string>

using namespace std;

template <typename T>
inline T const& Max (T const& a, T const& b) { 
   return a < b ? b:a; 
}

int main () {
   int i = 39;
   int j = 20;
   cout << "Max(i, j): " << Max(i, j) << endl; 

   double f1 = 13.5; 
   double f2 = 20.7; 
   cout << "Max(f1, f2): " << Max(f1, f2) << endl; 

   string s1 = "Hello"; 
   string s2 = "World"; 
   cout << "Max(s1, s2): " << Max(s1, s2) << endl; 

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World

Modèle de classe

Tout comme nous pouvons définir des modèles de fonctions, nous pouvons également définir des modèles de classes. La forme générale d'une déclaration de classe générique est présentée ici -

template <class type> class class-name {
   .
   .
   .
}

Ici, typeest le nom du type d'espace réservé, qui sera spécifié lorsqu'une classe est instanciée. Vous pouvez définir plusieurs types de données génériques à l'aide d'une liste séparée par des virgules.

Voici l'exemple pour définir la classe Stack <> et implémenter des méthodes génériques pour pousser et faire apparaître les éléments de la pile -

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>

using namespace std;

template <class T>
class Stack { 
   private: 
      vector<T> elems;    // elements 

   public: 
      void push(T const&);  // push element 
      void pop();               // pop element 
      T top() const;            // return top element 
      
      bool empty() const {      // return true if empty.
         return elems.empty(); 
      } 
}; 

template <class T>
void Stack<T>::push (T const& elem) { 
   // append copy of passed element 
   elems.push_back(elem);    
} 

template <class T>
void Stack<T>::pop () { 
   if (elems.empty()) { 
      throw out_of_range("Stack<>::pop(): empty stack"); 
   }
   
   // remove last element 
   elems.pop_back();         
} 

template <class T>
T Stack<T>::top () const { 
   if (elems.empty()) { 
      throw out_of_range("Stack<>::top(): empty stack"); 
   }
   
   // return copy of last element 
   return elems.back();      
} 

int main() { 
   try {
      Stack<int>         intStack;  // stack of ints 
      Stack<string> stringStack;    // stack of strings 

      // manipulate int stack 
      intStack.push(7); 
      cout << intStack.top() <<endl; 

      // manipulate string stack 
      stringStack.push("hello"); 
      cout << stringStack.top() << std::endl; 
      stringStack.pop(); 
      stringStack.pop(); 
   } catch (exception const& ex) { 
      cerr << "Exception: " << ex.what() <<endl; 
      return -1;
   } 
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

7
hello
Exception: Stack<>::pop(): empty stack